1 use super::ScalarInt; 2 use crate::mir::interpret::{AllocId, Scalar}; 3 use crate::ty::{self, Ty, TyCtxt}; 4 use rustc_macros::{HashStable, TyDecodable, TyEncodable}; 5 6 #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] 7 #[derive(HashStable)] 8 /// This datastructure is used to represent the value of constants used in the type system. 9 /// 10 /// We explicitly choose a different datastructure from the way values are processed within 11 /// CTFE, as in the type system equal values (according to their `PartialEq`) must also have 12 /// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. 13 /// Since CTFE uses `AllocId` to represent pointers, it often happens that two different 14 /// `AllocId`s point to equal values. So we may end up with different representations for 15 /// two constants whose value is `&42`. Furthermore any kind of struct that has padding will 16 /// have arbitrary values within that padding, even if the values of the struct are the same. 17 /// 18 /// `ValTree` does not have this problem with representation, as it only contains integers or 19 /// lists of (nested) `ValTree`. 20 pub enum ValTree<'tcx> { 21 /// integers, `bool`, `char` are represented as scalars. 22 /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values 23 /// of these types have the same representation. 24 Leaf(ScalarInt), 25 26 //SliceOrStr(ValSlice<'tcx>), 27 // dont use SliceOrStr for now 28 /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by 29 /// listing their fields' values in order. 30 /// 31 /// Enums are represented by storing their discriminant as a field, followed by all 32 /// the fields of the variant. 33 /// 34 /// ZST types are represented as an empty slice. 35 Branch(&'tcx [ValTree<'tcx>]), 36 } 37 38 impl<'tcx> ValTree<'tcx> { zst() -> Self39 pub fn zst() -> Self { 40 Self::Branch(&[]) 41 } 42 43 #[inline] unwrap_leaf(self) -> ScalarInt44 pub fn unwrap_leaf(self) -> ScalarInt { 45 match self { 46 Self::Leaf(s) => s, 47 _ => bug!("expected leaf, got {:?}", self), 48 } 49 } 50 51 #[inline] unwrap_branch(self) -> &'tcx [Self]52 pub fn unwrap_branch(self) -> &'tcx [Self] { 53 match self { 54 Self::Branch(branch) => branch, 55 _ => bug!("expected branch, got {:?}", self), 56 } 57 } 58 from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self59 pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self { 60 let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b))); 61 let interned = tcx.arena.alloc_from_iter(branches); 62 63 Self::Branch(interned) 64 } 65 from_scalar_int(i: ScalarInt) -> Self66 pub fn from_scalar_int(i: ScalarInt) -> Self { 67 Self::Leaf(i) 68 } 69 try_to_scalar(self) -> Option<Scalar<AllocId>>70 pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { 71 self.try_to_scalar_int().map(Scalar::Int) 72 } 73 try_to_scalar_int(self) -> Option<ScalarInt>74 pub fn try_to_scalar_int(self) -> Option<ScalarInt> { 75 match self { 76 Self::Leaf(s) => Some(s), 77 Self::Branch(_) => None, 78 } 79 } 80 try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64>81 pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { 82 self.try_to_scalar_int().and_then(|s| s.try_to_target_usize(tcx).ok()) 83 } 84 85 /// Get the values inside the ValTree as a slice of bytes. This only works for 86 /// constants with types &str, &[u8], or [u8; _]. try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]>87 pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { 88 match ty.kind() { 89 ty::Ref(_, inner_ty, _) => match inner_ty.kind() { 90 // `&str` can be interpreted as raw bytes 91 ty::Str => {} 92 // `&[u8]` can be interpreted as raw bytes 93 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {} 94 // other `&_` can't be interpreted as raw bytes 95 _ => return None, 96 }, 97 // `[u8; N]` can be interpreted as raw bytes 98 ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {} 99 // Otherwise, type cannot be interpreted as raw bytes 100 _ => return None, 101 } 102 103 Some(tcx.arena.alloc_from_iter( 104 self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()), 105 )) 106 } 107 } 108