@@ -30,7 +30,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
3030}
3131impl < ' tcx , M : Machine < ' tcx > > InterpCx < ' tcx , M > {
3232 /// Generates a value of `TypeId` for `ty` in-place.
33- pub ( crate ) fn write_type_id (
33+ fn write_type_id (
3434 & mut self ,
3535 ty : Ty < ' tcx > ,
3636 dest : & PlaceTy < ' tcx , M :: Provenance > ,
@@ -48,8 +48,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
4848 // Here we rely on `TypeId` being a newtype around an array of pointers, so we
4949 // first project to its only field and then the array elements.
5050 let alloc_id = tcx. reserve_and_set_type_id_alloc ( ty) ;
51- let first = self . project_field ( dest, FieldIdx :: ZERO ) ?;
52- let mut elem_iter = self . project_array_fields ( & first ) ?;
51+ let arr = self . project_field ( dest, FieldIdx :: ZERO ) ?;
52+ let mut elem_iter = self . project_array_fields ( & arr ) ?;
5353 while let Some ( ( _, elem) ) = elem_iter. next ( self ) ? {
5454 // Decorate this part of the hash with provenance; leave the integer part unchanged.
5555 let hash_fragment = self . read_scalar ( & elem) ?. to_target_usize ( & tcx) ?;
@@ -61,6 +61,51 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6161 interp_ok ( ( ) )
6262 }
6363
64+ /// Read a value of type `TypeId`, returning the type it represents.
65+ pub ( crate ) fn read_type_id (
66+ & self ,
67+ op : & OpTy < ' tcx , M :: Provenance > ,
68+ ) -> InterpResult < ' tcx , Ty < ' tcx > > {
69+ // `TypeId` is a newtype around an array of pointers. All pointers must have the same
70+ // provenance, and that provenance represents the type.
71+ let ptr_size = self . pointer_size ( ) . bytes_usize ( ) ;
72+ let arr = self . project_field ( op, FieldIdx :: ZERO ) ?;
73+
74+ let mut ty_and_hash = None ;
75+ let mut elem_iter = self . project_array_fields ( & arr) ?;
76+ while let Some ( ( idx, elem) ) = elem_iter. next ( self ) ? {
77+ let elem = self . read_pointer ( & elem) ?;
78+ let ( elem_ty, elem_hash) = self . get_ptr_type_id ( elem) ?;
79+ // If this is the first element, remember the type and its hash.
80+ // If this is not the first element, ensure it is consistent with the previous ones.
81+ let full_hash = match ty_and_hash {
82+ None => {
83+ let hash = self . tcx . type_id_hash ( elem_ty) . as_u128 ( ) ;
84+ ty_and_hash = Some ( ( elem_ty, hash) ) ;
85+ hash
86+ }
87+ Some ( ( ty, hash) ) => {
88+ if ty != elem_ty {
89+ throw_ub_format ! (
90+ "invalid `TypeId` value: not all bytes carry the same type id metadata"
91+ ) ;
92+ }
93+ hash
94+ }
95+ } ;
96+ // Ensure the elem_hash matches the corresponding part of the full hash.
97+ if full_hash. to_ne_bytes ( ) [ ( idx as usize ) * ptr_size..] [ ..ptr_size]
98+ != elem_hash. to_ne_bytes ( )
99+ {
100+ throw_ub_format ! (
101+ "invalid `TypeId` value: the hash does not match the type id metadata"
102+ ) ;
103+ }
104+ }
105+
106+ interp_ok ( ty_and_hash. unwrap ( ) . 0 )
107+ }
108+
64109 /// Returns `true` if emulation happened.
65110 /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
66111 /// intrinsic handling.
@@ -97,47 +142,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
97142 self . write_type_id ( tp_ty, dest) ?;
98143 }
99144 sym:: type_id_eq => {
100- // Both operands are `TypeId`, which is a newtype around an array of pointers.
101- // Project until we have the array elements.
102- let a_fields = self . project_field ( & args[ 0 ] , FieldIdx :: ZERO ) ?;
103- let b_fields = self . project_field ( & args[ 1 ] , FieldIdx :: ZERO ) ?;
104-
105- let mut a_fields = self . project_array_fields ( & a_fields) ?;
106- let mut b_fields = self . project_array_fields ( & b_fields) ?;
107-
108- let mut provenance_a = None ;
109- let mut provenance_b = None ;
110- let mut provenance_matches = true ;
111-
112- while let Some ( ( i, a) ) = a_fields. next ( self ) ? {
113- let ( _, b) = b_fields. next ( self ) ?. unwrap ( ) ;
114-
115- let a = self . deref_pointer ( & a) ?;
116- let ( a, offset_a) = self . get_ptr_type_id ( a. ptr ( ) ) ?;
117-
118- let b = self . deref_pointer ( & b) ?;
119- let ( b, offset_b) = self . get_ptr_type_id ( b. ptr ( ) ) ?;
120-
121- if * provenance_a. get_or_insert ( a) != a {
122- throw_ub_format ! (
123- "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
124- )
125- }
126- if * provenance_b. get_or_insert ( b) != b {
127- throw_ub_format ! (
128- "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
129- )
130- }
131- provenance_matches &= a == b;
132-
133- if offset_a != offset_b && provenance_matches {
134- throw_ub_format ! (
135- "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents"
136- )
137- }
138- }
139-
140- self . write_scalar ( Scalar :: from_bool ( provenance_matches) , dest) ?;
145+ let a_ty = self . read_type_id ( & args[ 0 ] ) ?;
146+ let b_ty = self . read_type_id ( & args[ 1 ] ) ?;
147+ self . write_scalar ( Scalar :: from_bool ( a_ty == b_ty) , dest) ?;
141148 }
142149 sym:: variant_count => {
143150 let tp_ty = instance. args . type_at ( 0 ) ;
0 commit comments