1
1
use std:: convert:: TryFrom ;
2
2
3
- use super :: { FnVal , ImmTy , Immediate , InterpCx , Machine , OpTy , PlaceTy } ;
4
3
use rustc_apfloat:: ieee:: { Double , Single } ;
5
4
use rustc_apfloat:: { Float , FloatConvert } ;
6
5
use rustc_ast:: ast:: FloatTy ;
6
+ use rustc_attr as attr;
7
7
use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar } ;
8
8
use rustc_middle:: mir:: CastKind ;
9
9
use rustc_middle:: ty:: adjustment:: PointerCast ;
10
- use rustc_middle:: ty:: layout:: TyAndLayout ;
10
+ use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
11
11
use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeFoldable } ;
12
12
use rustc_span:: symbol:: sym;
13
- use rustc_target:: abi:: { LayoutOf , Size , Variants } ;
13
+ use rustc_target:: abi:: { Integer , LayoutOf , Variants } ;
14
+
15
+ use super :: { truncate, FnVal , ImmTy , Immediate , InterpCx , Machine , OpTy , PlaceTy } ;
14
16
15
17
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
16
18
pub fn cast (
17
19
& mut self ,
18
20
src : OpTy < ' tcx , M :: PointerTag > ,
19
- kind : CastKind ,
21
+ cast_kind : CastKind ,
22
+ cast_ty : Ty < ' tcx > ,
20
23
dest : PlaceTy < ' tcx , M :: PointerTag > ,
21
24
) -> InterpResult < ' tcx > {
22
25
use rustc_middle:: mir:: CastKind :: * ;
23
- match kind {
26
+ // FIXME: In which cases should we trigger UB when the source is uninit?
27
+ match cast_kind {
24
28
Pointer ( PointerCast :: Unsize ) => {
25
- self . unsize_into ( src, dest) ?;
29
+ let cast_ty = self . layout_of ( cast_ty) ?;
30
+ self . unsize_into ( src, cast_ty, dest) ?;
26
31
}
27
32
28
- Misc | Pointer ( PointerCast :: MutToConstPointer | PointerCast :: ArrayToPointer ) => {
33
+ Misc => {
29
34
let src = self . read_immediate ( src) ?;
30
- let res = self . cast_immediate ( src, dest . layout ) ?;
35
+ let res = self . misc_cast ( src, cast_ty ) ?;
31
36
self . write_immediate ( res, dest) ?;
32
37
}
33
38
39
+ Pointer ( PointerCast :: MutToConstPointer | PointerCast :: ArrayToPointer ) => {
40
+ // These are NOPs, but can be wide pointers.
41
+ let v = self . read_immediate ( src) ?;
42
+ self . write_immediate ( * v, dest) ?;
43
+ }
44
+
34
45
Pointer ( PointerCast :: ReifyFnPointer ) => {
35
46
// The src operand does not matter, just its type
36
47
match src. layout . ty . kind {
@@ -61,12 +72,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
61
72
62
73
Pointer ( PointerCast :: UnsafeFnPointer ) => {
63
74
let src = self . read_immediate ( src) ?;
64
- match dest . layout . ty . kind {
75
+ match cast_ty . kind {
65
76
ty:: FnPtr ( _) => {
66
77
// No change to value
67
78
self . write_immediate ( * src, dest) ?;
68
79
}
69
- _ => bug ! ( "fn to unsafe fn cast on {:?}" , dest . layout . ty ) ,
80
+ _ => bug ! ( "fn to unsafe fn cast on {:?}" , cast_ty ) ,
70
81
}
71
82
}
72
83
@@ -95,25 +106,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
95
106
Ok ( ( ) )
96
107
}
97
108
98
- fn cast_immediate (
109
+ fn misc_cast (
99
110
& self ,
100
111
src : ImmTy < ' tcx , M :: PointerTag > ,
101
- dest_layout : TyAndLayout < ' tcx > ,
112
+ cast_ty : Ty < ' tcx > ,
102
113
) -> InterpResult < ' tcx , Immediate < M :: PointerTag > > {
103
114
use rustc_middle:: ty:: TyKind :: * ;
104
- trace ! ( "Casting {:?}: {:?} to {:?}" , * src, src. layout. ty, dest_layout . ty ) ;
115
+ trace ! ( "Casting {:?}: {:?} to {:?}" , * src, src. layout. ty, cast_ty ) ;
105
116
106
117
match src. layout . ty . kind {
107
118
// Floating point
108
119
Float ( FloatTy :: F32 ) => {
109
- return Ok ( self
110
- . cast_from_float ( src. to_scalar ( ) ?. to_f32 ( ) ?, dest_layout. ty ) ?
111
- . into ( ) ) ;
120
+ return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f32 ( ) ?, cast_ty) . into ( ) ) ;
112
121
}
113
122
Float ( FloatTy :: F64 ) => {
114
- return Ok ( self
115
- . cast_from_float ( src. to_scalar ( ) ?. to_f64 ( ) ?, dest_layout. ty ) ?
116
- . into ( ) ) ;
123
+ return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f64 ( ) ?, cast_ty) . into ( ) ) ;
117
124
}
118
125
// The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
119
126
// are represented as integers.
@@ -128,121 +135,118 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
128
135
) ,
129
136
}
130
137
138
+ // # First handle non-scalar source values.
139
+
131
140
// Handle cast from a univariant (ZST) enum.
132
141
match src. layout . variants {
133
142
Variants :: Single { index } => {
134
143
if let Some ( discr) = src. layout . ty . discriminant_for_variant ( * self . tcx , index) {
135
144
assert ! ( src. layout. is_zst( ) ) ;
136
145
let discr_layout = self . layout_of ( discr. ty ) ?;
137
- return Ok ( self
138
- . cast_from_int_like ( discr. val , discr_layout, dest_layout) ?
139
- . into ( ) ) ;
146
+ return Ok ( self . cast_from_scalar ( discr. val , discr_layout, cast_ty) . into ( ) ) ;
140
147
}
141
148
}
142
149
Variants :: Multiple { .. } => { }
143
150
}
144
151
145
- // Handle casting the metadata away from a fat pointer.
146
- if src. layout . ty . is_unsafe_ptr ( )
147
- && dest_layout. ty . is_unsafe_ptr ( )
148
- && dest_layout. size != src. layout . size
149
- {
150
- assert_eq ! ( src. layout. size, 2 * self . memory. pointer_size( ) ) ;
151
- assert_eq ! ( dest_layout. size, self . memory. pointer_size( ) ) ;
152
- assert ! ( dest_layout. ty. is_unsafe_ptr( ) ) ;
153
- match * src {
154
- Immediate :: ScalarPair ( data, _) => return Ok ( data. into ( ) ) ,
155
- Immediate :: Scalar ( ..) => bug ! (
156
- "{:?} input to a fat-to-thin cast ({:?} -> {:?})" ,
157
- * src,
158
- src. layout. ty,
159
- dest_layout. ty
160
- ) ,
161
- } ;
162
- }
163
-
164
152
// Handle casting any ptr to raw ptr (might be a fat ptr).
165
- if src. layout . ty . is_any_ptr ( ) && dest_layout. ty . is_unsafe_ptr ( ) {
166
- // The only possible size-unequal case was handled above.
167
- assert_eq ! ( src. layout. size, dest_layout. size) ;
168
- return Ok ( * src) ;
153
+ if src. layout . ty . is_any_ptr ( ) && cast_ty. is_unsafe_ptr ( ) {
154
+ let dest_layout = self . layout_of ( cast_ty) ?;
155
+ if dest_layout. size == src. layout . size {
156
+ // Thin or fat pointer that just hast the ptr kind of target type changed.
157
+ return Ok ( * src) ;
158
+ } else {
159
+ // Casting the metadata away from a fat ptr.
160
+ assert_eq ! ( src. layout. size, 2 * self . memory. pointer_size( ) ) ;
161
+ assert_eq ! ( dest_layout. size, self . memory. pointer_size( ) ) ;
162
+ assert ! ( src. layout. ty. is_unsafe_ptr( ) ) ;
163
+ return match * src {
164
+ Immediate :: ScalarPair ( data, _) => Ok ( data. into ( ) ) ,
165
+ Immediate :: Scalar ( ..) => bug ! (
166
+ "{:?} input to a fat-to-thin cast ({:?} -> {:?})" ,
167
+ * src,
168
+ src. layout. ty,
169
+ cast_ty
170
+ ) ,
171
+ } ;
172
+ }
169
173
}
170
174
175
+ // # The remaining source values are scalar.
176
+
171
177
// For all remaining casts, we either
172
178
// (a) cast a raw ptr to usize, or
173
179
// (b) cast from an integer-like (including bool, char, enums).
174
180
// In both cases we want the bits.
175
181
let bits = self . force_bits ( src. to_scalar ( ) ?, src. layout . size ) ?;
176
- Ok ( self . cast_from_int_like ( bits, src. layout , dest_layout ) ? . into ( ) )
182
+ Ok ( self . cast_from_scalar ( bits, src. layout , cast_ty ) . into ( ) )
177
183
}
178
184
179
- fn cast_from_int_like (
185
+ pub ( super ) fn cast_from_scalar (
180
186
& self ,
181
- v : u128 , // raw bits
187
+ v : u128 , // raw bits (there is no ScalarTy so we separate data+layout)
182
188
src_layout : TyAndLayout < ' tcx > ,
183
- dest_layout : TyAndLayout < ' tcx > ,
184
- ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > > {
189
+ cast_ty : Ty < ' tcx > ,
190
+ ) -> Scalar < M :: PointerTag > {
185
191
// Let's make sure v is sign-extended *if* it has a signed type.
186
- let signed = src_layout. abi . is_signed ( ) ;
192
+ let signed = src_layout. abi . is_signed ( ) ; // Also asserts that abi is `Scalar`.
187
193
let v = if signed { self . sign_extend ( v, src_layout) } else { v } ;
188
- trace ! ( "cast_from_int : {}, {}, {}" , v, src_layout. ty, dest_layout . ty ) ;
194
+ trace ! ( "cast_from_scalar : {}, {} -> {}" , v, src_layout. ty, cast_ty ) ;
189
195
use rustc_middle:: ty:: TyKind :: * ;
190
- match dest_layout . ty . kind {
196
+ match cast_ty . kind {
191
197
Int ( _) | Uint ( _) | RawPtr ( _) => {
192
- let v = self . truncate ( v, dest_layout) ;
193
- Ok ( Scalar :: from_uint ( v, dest_layout. size ) )
198
+ let size = match cast_ty. kind {
199
+ Int ( t) => Integer :: from_attr ( self , attr:: IntType :: SignedInt ( t) ) . size ( ) ,
200
+ Uint ( t) => Integer :: from_attr ( self , attr:: IntType :: UnsignedInt ( t) ) . size ( ) ,
201
+ RawPtr ( _) => self . pointer_size ( ) ,
202
+ _ => bug ! ( ) ,
203
+ } ;
204
+ let v = truncate ( v, size) ;
205
+ Scalar :: from_uint ( v, size)
194
206
}
195
207
196
- Float ( FloatTy :: F32 ) if signed => {
197
- Ok ( Scalar :: from_f32 ( Single :: from_i128 ( v as i128 ) . value ) )
198
- }
199
- Float ( FloatTy :: F64 ) if signed => {
200
- Ok ( Scalar :: from_f64 ( Double :: from_i128 ( v as i128 ) . value ) )
201
- }
202
- Float ( FloatTy :: F32 ) => Ok ( Scalar :: from_f32 ( Single :: from_u128 ( v) . value ) ) ,
203
- Float ( FloatTy :: F64 ) => Ok ( Scalar :: from_f64 ( Double :: from_u128 ( v) . value ) ) ,
208
+ Float ( FloatTy :: F32 ) if signed => Scalar :: from_f32 ( Single :: from_i128 ( v as i128 ) . value ) ,
209
+ Float ( FloatTy :: F64 ) if signed => Scalar :: from_f64 ( Double :: from_i128 ( v as i128 ) . value ) ,
210
+ Float ( FloatTy :: F32 ) => Scalar :: from_f32 ( Single :: from_u128 ( v) . value ) ,
211
+ Float ( FloatTy :: F64 ) => Scalar :: from_f64 ( Double :: from_u128 ( v) . value ) ,
204
212
205
213
Char => {
206
214
// `u8` to `char` cast
207
- Ok ( Scalar :: from_u32 ( u8:: try_from ( v) . unwrap ( ) . into ( ) ) )
215
+ Scalar :: from_u32 ( u8:: try_from ( v) . unwrap ( ) . into ( ) )
208
216
}
209
217
210
218
// Casts to bool are not permitted by rustc, no need to handle them here.
211
- _ => bug ! ( "invalid int to {:?} cast" , dest_layout . ty ) ,
219
+ _ => bug ! ( "invalid int to {:?} cast" , cast_ty ) ,
212
220
}
213
221
}
214
222
215
- fn cast_from_float < F > (
216
- & self ,
217
- f : F ,
218
- dest_ty : Ty < ' tcx > ,
219
- ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > >
223
+ fn cast_from_float < F > ( & self , f : F , dest_ty : Ty < ' tcx > ) -> Scalar < M :: PointerTag >
220
224
where
221
225
F : Float + Into < Scalar < M :: PointerTag > > + FloatConvert < Single > + FloatConvert < Double > ,
222
226
{
223
227
use rustc_middle:: ty:: TyKind :: * ;
224
228
match dest_ty. kind {
225
229
// float -> uint
226
230
Uint ( t) => {
227
- let width = t . bit_width ( ) . unwrap_or_else ( || self . pointer_size ( ) . bits ( ) ) ;
231
+ let size = Integer :: from_attr ( self , attr :: IntType :: UnsignedInt ( t ) ) . size ( ) ;
228
232
// `to_u128` is a saturating cast, which is what we need
229
233
// (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
230
- let v = f. to_u128 ( usize :: try_from ( width ) . unwrap ( ) ) . value ;
234
+ let v = f. to_u128 ( size . bits_usize ( ) ) . value ;
231
235
// This should already fit the bit width
232
- Ok ( Scalar :: from_uint ( v, Size :: from_bits ( width ) ) )
236
+ Scalar :: from_uint ( v, size )
233
237
}
234
238
// float -> int
235
239
Int ( t) => {
236
- let width = t . bit_width ( ) . unwrap_or_else ( || self . pointer_size ( ) . bits ( ) ) ;
240
+ let size = Integer :: from_attr ( self , attr :: IntType :: SignedInt ( t ) ) . size ( ) ;
237
241
// `to_i128` is a saturating cast, which is what we need
238
242
// (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
239
- let v = f. to_i128 ( usize :: try_from ( width ) . unwrap ( ) ) . value ;
240
- Ok ( Scalar :: from_int ( v, Size :: from_bits ( width ) ) )
243
+ let v = f. to_i128 ( size . bits_usize ( ) ) . value ;
244
+ Scalar :: from_int ( v, size )
241
245
}
242
246
// float -> f32
243
- Float ( FloatTy :: F32 ) => Ok ( Scalar :: from_f32 ( f. convert ( & mut false ) . value ) ) ,
247
+ Float ( FloatTy :: F32 ) => Scalar :: from_f32 ( f. convert ( & mut false ) . value ) ,
244
248
// float -> f64
245
- Float ( FloatTy :: F64 ) => Ok ( Scalar :: from_f64 ( f. convert ( & mut false ) . value ) ) ,
249
+ Float ( FloatTy :: F64 ) => Scalar :: from_f64 ( f. convert ( & mut false ) . value ) ,
246
250
// That's it.
247
251
_ => bug ! ( "invalid float to {:?} cast" , dest_ty) ,
248
252
}
@@ -254,11 +258,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
254
258
dest : PlaceTy < ' tcx , M :: PointerTag > ,
255
259
// The pointee types
256
260
source_ty : Ty < ' tcx > ,
257
- dest_ty : Ty < ' tcx > ,
261
+ cast_ty : Ty < ' tcx > ,
258
262
) -> InterpResult < ' tcx > {
259
263
// A<Struct> -> A<Trait> conversion
260
264
let ( src_pointee_ty, dest_pointee_ty) =
261
- self . tcx . struct_lockstep_tails_erasing_lifetimes ( source_ty, dest_ty , self . param_env ) ;
265
+ self . tcx . struct_lockstep_tails_erasing_lifetimes ( source_ty, cast_ty , self . param_env ) ;
262
266
263
267
match ( & src_pointee_ty. kind , & dest_pointee_ty. kind ) {
264
268
( & ty:: Array ( _, length) , & ty:: Slice ( _) ) => {
@@ -286,48 +290,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
286
290
self . write_immediate ( val, dest)
287
291
}
288
292
289
- _ => bug ! ( "invalid unsizing {:?} -> {:?}" , src. layout. ty, dest . layout . ty ) ,
293
+ _ => bug ! ( "invalid unsizing {:?} -> {:?}" , src. layout. ty, cast_ty ) ,
290
294
}
291
295
}
292
296
293
297
fn unsize_into (
294
298
& mut self ,
295
299
src : OpTy < ' tcx , M :: PointerTag > ,
300
+ cast_ty : TyAndLayout < ' tcx > ,
296
301
dest : PlaceTy < ' tcx , M :: PointerTag > ,
297
302
) -> InterpResult < ' tcx > {
298
- trace ! ( "Unsizing {:?} into {:?}" , src, dest ) ;
299
- match ( & src. layout . ty . kind , & dest . layout . ty . kind ) {
300
- ( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, d , _) | & ty:: RawPtr ( TypeAndMut { ty : d , .. } ) )
301
- | ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : d , .. } ) ) => {
302
- self . unsize_into_ptr ( src, dest, s, d )
303
+ trace ! ( "Unsizing {:?} of type {} into {:?}" , * src, src . layout . ty , cast_ty . ty ) ;
304
+ match ( & src. layout . ty . kind , & cast_ty . ty . kind ) {
305
+ ( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, c , _) | & ty:: RawPtr ( TypeAndMut { ty : c , .. } ) )
306
+ | ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : c , .. } ) ) => {
307
+ self . unsize_into_ptr ( src, dest, s, c )
303
308
}
304
309
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
305
310
assert_eq ! ( def_a, def_b) ;
306
311
if def_a. is_box ( ) || def_b. is_box ( ) {
307
312
if !def_a. is_box ( ) || !def_b. is_box ( ) {
308
- bug ! ( "invalid unsizing between {:?} -> {:?}" , src. layout, dest . layout ) ;
313
+ bug ! ( "invalid unsizing between {:?} -> {:?}" , src. layout. ty , cast_ty . ty ) ;
309
314
}
310
315
return self . unsize_into_ptr (
311
316
src,
312
317
dest,
313
318
src. layout . ty . boxed_ty ( ) ,
314
- dest . layout . ty . boxed_ty ( ) ,
319
+ cast_ty . ty . boxed_ty ( ) ,
315
320
) ;
316
321
}
317
322
318
323
// unsizing of generic struct with pointer fields
319
324
// Example: `Arc<T>` -> `Arc<Trait>`
320
325
// here we need to increase the size of every &T thin ptr field to a fat ptr
321
326
for i in 0 ..src. layout . fields . count ( ) {
322
- let dst_field = self . place_field ( dest , i) ?;
323
- if dst_field . layout . is_zst ( ) {
327
+ let cast_ty_field = cast_ty . field ( self , i) ?;
328
+ if cast_ty_field . is_zst ( ) {
324
329
continue ;
325
330
}
326
331
let src_field = self . operand_field ( src, i) ?;
327
- if src_field. layout . ty == dst_field. layout . ty {
332
+ let dst_field = self . place_field ( dest, i) ?;
333
+ if src_field. layout . ty == cast_ty_field. ty {
328
334
self . copy_op ( src_field, dst_field) ?;
329
335
} else {
330
- self . unsize_into ( src_field, dst_field) ?;
336
+ self . unsize_into ( src_field, cast_ty_field , dst_field) ?;
331
337
}
332
338
}
333
339
Ok ( ( ) )
0 commit comments