4
4
5
5
use std:: assert_matches:: assert_matches;
6
6
7
- use rustc_abi:: { FieldIdx , Size } ;
7
+ use rustc_abi:: { FieldIdx , HasDataLayout , Size } ;
8
8
use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
9
+ use rustc_middle:: mir:: interpret:: { read_target_uint, write_target_uint} ;
9
10
use rustc_middle:: mir:: { self , BinOp , ConstValue , NonDivergingIntrinsic } ;
10
11
use rustc_middle:: ty:: layout:: TyAndLayout ;
11
12
use rustc_middle:: ty:: { Ty , TyCtxt } ;
@@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
30
31
}
31
32
impl < ' tcx , M : Machine < ' tcx > > InterpCx < ' tcx , M > {
32
33
/// Generates a value of `TypeId` for `ty` in-place.
33
- pub ( crate ) fn write_type_id (
34
+ fn write_type_id (
34
35
& mut self ,
35
36
ty : Ty < ' tcx > ,
36
37
dest : & PlaceTy < ' tcx , M :: Provenance > ,
@@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
48
49
// Here we rely on `TypeId` being a newtype around an array of pointers, so we
49
50
// first project to its only field and then the array elements.
50
51
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 ) ?;
52
+ let arr = self . project_field ( dest, FieldIdx :: ZERO ) ?;
53
+ let mut elem_iter = self . project_array_fields ( & arr ) ?;
53
54
while let Some ( ( _, elem) ) = elem_iter. next ( self ) ? {
54
55
// Decorate this part of the hash with provenance; leave the integer part unchanged.
55
56
let hash_fragment = self . read_scalar ( & elem) ?. to_target_usize ( & tcx) ?;
@@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
61
62
interp_ok ( ( ) )
62
63
}
63
64
65
+ /// Read a value of type `TypeId`, returning the type it represents.
66
+ pub ( crate ) fn read_type_id (
67
+ & self ,
68
+ op : & OpTy < ' tcx , M :: Provenance > ,
69
+ ) -> InterpResult < ' tcx , Ty < ' tcx > > {
70
+ // `TypeId` is a newtype around an array of pointers. All pointers must have the same
71
+ // provenance, and that provenance represents the type.
72
+ let ptr_size = self . pointer_size ( ) . bytes_usize ( ) ;
73
+ let arr = self . project_field ( op, FieldIdx :: ZERO ) ?;
74
+
75
+ let mut ty_and_hash = None ;
76
+ let mut elem_iter = self . project_array_fields ( & arr) ?;
77
+ while let Some ( ( idx, elem) ) = elem_iter. next ( self ) ? {
78
+ let elem = self . read_pointer ( & elem) ?;
79
+ let ( elem_ty, elem_hash) = self . get_ptr_type_id ( elem) ?;
80
+ // If this is the first element, remember the type and its hash.
81
+ // If this is not the first element, ensure it is consistent with the previous ones.
82
+ let full_hash = match ty_and_hash {
83
+ None => {
84
+ let hash = self . tcx . type_id_hash ( elem_ty) . as_u128 ( ) ;
85
+ let mut hash_bytes = [ 0u8 ; 16 ] ;
86
+ write_target_uint ( self . data_layout ( ) . endian , & mut hash_bytes, hash) . unwrap ( ) ;
87
+ ty_and_hash = Some ( ( elem_ty, hash_bytes) ) ;
88
+ hash_bytes
89
+ }
90
+ Some ( ( ty, hash_bytes) ) => {
91
+ if ty != elem_ty {
92
+ throw_ub_format ! (
93
+ "invalid `TypeId` value: not all bytes carry the same type id metadata"
94
+ ) ;
95
+ }
96
+ hash_bytes
97
+ }
98
+ } ;
99
+ // Ensure the elem_hash matches the corresponding part of the full hash.
100
+ let hash_frag = & full_hash[ ( idx as usize ) * ptr_size..] [ ..ptr_size] ;
101
+ if read_target_uint ( self . data_layout ( ) . endian , hash_frag) . unwrap ( ) != elem_hash. into ( ) {
102
+ throw_ub_format ! (
103
+ "invalid `TypeId` value: the hash does not match the type id metadata"
104
+ ) ;
105
+ }
106
+ }
107
+
108
+ interp_ok ( ty_and_hash. unwrap ( ) . 0 )
109
+ }
110
+
64
111
/// Returns `true` if emulation happened.
65
112
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
66
113
/// intrinsic handling.
@@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
97
144
self . write_type_id ( tp_ty, dest) ?;
98
145
}
99
146
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) ?;
147
+ let a_ty = self . read_type_id ( & args[ 0 ] ) ?;
148
+ let b_ty = self . read_type_id ( & args[ 1 ] ) ?;
149
+ self . write_scalar ( Scalar :: from_bool ( a_ty == b_ty) , dest) ?;
141
150
}
142
151
sym:: variant_count => {
143
152
let tp_ty = instance. args . type_at ( 0 ) ;
0 commit comments