44
55use std:: assert_matches:: assert_matches;
66
7- use rustc_abi:: Size ;
7+ use rustc_abi:: { FieldIdx , Size } ;
88use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
9+ use rustc_ast:: Mutability ;
10+ use rustc_middle:: mir:: interpret:: { AllocId , AllocInit , alloc_range} ;
911use rustc_middle:: mir:: { self , BinOp , ConstValue , NonDivergingIntrinsic } ;
1012use rustc_middle:: ty:: layout:: TyAndLayout ;
1113use rustc_middle:: ty:: { Ty , TyCtxt } ;
@@ -29,6 +31,37 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
2931 tcx. mk_const_alloc ( alloc)
3032}
3133
34+ pub ( crate ) fn alloc_type_id < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> AllocId {
35+ let size = Size :: from_bytes ( 16 ) ;
36+ let align = tcx. data_layout . pointer_align ( ) ;
37+ let mut alloc = Allocation :: new ( size, * align, AllocInit :: Uninit , ( ) ) ;
38+ let ptr_size = tcx. data_layout . pointer_size ( ) ;
39+ let type_id_hash = tcx. type_id_hash ( ty) . as_u128 ( ) ;
40+ alloc
41+ . write_scalar (
42+ & tcx,
43+ alloc_range ( Size :: ZERO , Size :: from_bytes ( 16 ) ) ,
44+ Scalar :: from_u128 ( type_id_hash) ,
45+ )
46+ . unwrap ( ) ;
47+
48+ // Give the first pointer-size bytes provenance that knows about the type id
49+
50+ let alloc_id = tcx. reserve_and_set_type_id_alloc ( ty) ;
51+ let offset = alloc
52+ . read_scalar ( & tcx, alloc_range ( Size :: ZERO , ptr_size) , false )
53+ . unwrap ( )
54+ . to_target_usize ( & tcx)
55+ . unwrap ( ) ;
56+ let ptr = Pointer :: new ( alloc_id. into ( ) , Size :: from_bytes ( offset) ) ;
57+ let val = Scalar :: from_pointer ( ptr, & tcx) ;
58+ alloc. write_scalar ( & tcx, alloc_range ( Size :: ZERO , ptr_size) , val) . unwrap ( ) ;
59+
60+ alloc. mutability = Mutability :: Not ;
61+
62+ tcx. reserve_and_set_memory_alloc ( tcx. mk_const_alloc ( alloc) )
63+ }
64+
3265impl < ' tcx , M : Machine < ' tcx > > InterpCx < ' tcx , M > {
3366 /// Returns `true` if emulation happened.
3467 /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
@@ -63,10 +96,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6396 sym:: type_id => {
6497 let tp_ty = instance. args . type_at ( 0 ) ;
6598 ensure_monomorphic_enough ( tcx, tp_ty) ?;
66- let val = ConstValue :: from_u128 ( tcx. type_id_hash ( tp_ty) . as_u128 ( ) ) ;
99+ let alloc_id = alloc_type_id ( tcx, tp_ty) ;
100+ let val = ConstValue :: Indirect { alloc_id, offset : Size :: ZERO } ;
67101 let val = self . const_val_to_op ( val, dest. layout . ty , Some ( dest. layout ) ) ?;
68102 self . copy_op ( & val, dest) ?;
69103 }
104+ sym:: type_id_eq => {
105+ // Both operands are `TypeId`, which is a newtype around an array of pointers.
106+ // Project until we have the array elements.
107+ let a_fields = self . project_field ( & args[ 0 ] , FieldIdx :: ZERO ) ?;
108+ let b_fields = self . project_field ( & args[ 1 ] , FieldIdx :: ZERO ) ?;
109+
110+ let mut a_fields = self . project_array_fields ( & a_fields) ?;
111+ let mut b_fields = self . project_array_fields ( & b_fields) ?;
112+
113+ let ( _idx, a) = a_fields
114+ . next ( self ) ?
115+ . expect ( "we know the layout of TypeId has at least 2 array elements" ) ;
116+ let a = self . deref_pointer ( & a) ?;
117+ let ( a, offset_a) = self . get_ptr_type_id ( a. ptr ( ) ) ?;
118+
119+ let ( _idx, b) = b_fields
120+ . next ( self ) ?
121+ . expect ( "we know the layout of TypeId has at least 2 array elements" ) ;
122+ let b = self . deref_pointer ( & b) ?;
123+ let ( b, offset_b) = self . get_ptr_type_id ( b. ptr ( ) ) ?;
124+
125+ let provenance_matches = a == b;
126+
127+ let mut eq_id = offset_a == offset_b;
128+
129+ while let Some ( ( _, a) ) = a_fields. next ( self ) ? {
130+ let ( _, b) = b_fields. next ( self ) ?. unwrap ( ) ;
131+
132+ let a = self . read_target_usize ( & a) ?;
133+ let b = self . read_target_usize ( & b) ?;
134+ eq_id &= a == b;
135+ }
136+
137+ if !eq_id && provenance_matches {
138+ throw_ub_format ! (
139+ "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents"
140+ )
141+ }
142+
143+ self . write_scalar ( Scalar :: from_bool ( provenance_matches) , dest) ?;
144+ }
70145 sym:: variant_count => {
71146 let tp_ty = instance. args . type_at ( 0 ) ;
72147 let ty = match tp_ty. kind ( ) {
0 commit comments