4
4
5
5
use std:: assert_matches:: assert_matches;
6
6
7
- use rustc_abi:: Size ;
7
+ use rustc_abi:: { FieldIdx , Size } ;
8
8
use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
9
+ use rustc_ast:: Mutability ;
10
+ use rustc_middle:: mir:: interpret:: { AllocId , AllocInit , alloc_range} ;
9
11
use rustc_middle:: mir:: { self , BinOp , ConstValue , NonDivergingIntrinsic } ;
10
12
use rustc_middle:: ty:: layout:: TyAndLayout ;
11
13
use rustc_middle:: ty:: { Ty , TyCtxt } ;
@@ -29,6 +31,37 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
29
31
tcx. mk_const_alloc ( alloc)
30
32
}
31
33
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
+
32
65
impl < ' tcx , M : Machine < ' tcx > > InterpCx < ' tcx , M > {
33
66
/// Returns `true` if emulation happened.
34
67
/// 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> {
63
96
sym:: type_id => {
64
97
let tp_ty = instance. args . type_at ( 0 ) ;
65
98
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 } ;
67
101
let val = self . const_val_to_op ( val, dest. layout . ty , Some ( dest. layout ) ) ?;
68
102
self . copy_op ( & val, dest) ?;
69
103
}
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
+ }
70
145
sym:: variant_count => {
71
146
let tp_ty = instance. args . type_at ( 0 ) ;
72
147
let ty = match tp_ty. kind ( ) {
0 commit comments