@@ -24,41 +24,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
24
24
cast_ty : Ty < ' tcx > ,
25
25
dest : & PlaceTy < ' tcx , M :: Provenance > ,
26
26
) -> InterpResult < ' tcx > {
27
+ // `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still
28
+ // possible.
29
+ let cast_layout =
30
+ if cast_ty == dest. layout . ty { dest. layout } else { self . layout_of ( cast_ty) ? } ;
27
31
// FIXME: In which cases should we trigger UB when the source is uninit?
28
32
match cast_kind {
29
33
CastKind :: PointerCoercion ( PointerCoercion :: Unsize ) => {
30
- let cast_ty = self . layout_of ( cast_ty) ?;
31
- self . unsize_into ( src, cast_ty, dest) ?;
34
+ self . unsize_into ( src, cast_layout, dest) ?;
32
35
}
33
36
34
37
CastKind :: PointerExposeAddress => {
35
38
let src = self . read_immediate ( src) ?;
36
- let res = self . pointer_expose_address_cast ( & src, cast_ty ) ?;
37
- self . write_immediate ( res, dest) ?;
39
+ let res = self . pointer_expose_address_cast ( & src, cast_layout ) ?;
40
+ self . write_immediate ( * res, dest) ?;
38
41
}
39
42
40
43
CastKind :: PointerFromExposedAddress => {
41
44
let src = self . read_immediate ( src) ?;
42
- let res = self . pointer_from_exposed_address_cast ( & src, cast_ty ) ?;
43
- self . write_immediate ( res, dest) ?;
45
+ let res = self . pointer_from_exposed_address_cast ( & src, cast_layout ) ?;
46
+ self . write_immediate ( * res, dest) ?;
44
47
}
45
48
46
49
CastKind :: IntToInt | CastKind :: IntToFloat => {
47
50
let src = self . read_immediate ( src) ?;
48
- let res = self . int_to_int_or_float ( & src, cast_ty ) ?;
49
- self . write_immediate ( res, dest) ?;
51
+ let res = self . int_to_int_or_float ( & src, cast_layout ) ?;
52
+ self . write_immediate ( * res, dest) ?;
50
53
}
51
54
52
55
CastKind :: FloatToFloat | CastKind :: FloatToInt => {
53
56
let src = self . read_immediate ( src) ?;
54
- let res = self . float_to_float_or_int ( & src, cast_ty ) ?;
55
- self . write_immediate ( res, dest) ?;
57
+ let res = self . float_to_float_or_int ( & src, cast_layout ) ?;
58
+ self . write_immediate ( * res, dest) ?;
56
59
}
57
60
58
61
CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
59
62
let src = self . read_immediate ( src) ?;
60
- let res = self . ptr_to_ptr ( & src, cast_ty ) ?;
61
- self . write_immediate ( res, dest) ?;
63
+ let res = self . ptr_to_ptr ( & src, cast_layout ) ?;
64
+ self . write_immediate ( * res, dest) ?;
62
65
}
63
66
64
67
CastKind :: PointerCoercion (
@@ -87,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
87
90
let fn_ptr = self . fn_ptr ( FnVal :: Instance ( instance) ) ;
88
91
self . write_pointer ( fn_ptr, dest) ?;
89
92
}
90
- _ => span_bug ! ( self . cur_span( ) , "reify fn pointer on {:? }" , src. layout. ty) ,
93
+ _ => span_bug ! ( self . cur_span( ) , "reify fn pointer on {}" , src. layout. ty) ,
91
94
}
92
95
}
93
96
@@ -98,7 +101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
98
101
// No change to value
99
102
self . write_immediate ( * src, dest) ?;
100
103
}
101
- _ => span_bug ! ( self . cur_span( ) , "fn to unsafe fn cast on {:? }" , cast_ty) ,
104
+ _ => span_bug ! ( self . cur_span( ) , "fn to unsafe fn cast on {}" , cast_ty) ,
102
105
}
103
106
}
104
107
@@ -119,7 +122,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
119
122
let fn_ptr = self . fn_ptr ( FnVal :: Instance ( instance) ) ;
120
123
self . write_pointer ( fn_ptr, dest) ?;
121
124
}
122
- _ => span_bug ! ( self . cur_span( ) , "closure fn pointer on {:? }" , src. layout. ty) ,
125
+ _ => span_bug ! ( self . cur_span( ) , "closure fn pointer on {}" , src. layout. ty) ,
123
126
}
124
127
}
125
128
@@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
140
143
CastKind :: Transmute => {
141
144
assert ! ( src. layout. is_sized( ) ) ;
142
145
assert ! ( dest. layout. is_sized( ) ) ;
146
+ assert_eq ! ( cast_ty, dest. layout. ty) ; // we otherwise ignore `cast_ty` enirely...
143
147
if src. layout . size != dest. layout . size {
144
148
let src_bytes = src. layout . size . bytes ( ) ;
145
149
let dest_bytes = dest. layout . size . bytes ( ) ;
@@ -164,62 +168,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
164
168
pub fn int_to_int_or_float (
165
169
& self ,
166
170
src : & ImmTy < ' tcx , M :: Provenance > ,
167
- cast_ty : Ty < ' tcx > ,
168
- ) -> InterpResult < ' tcx , Immediate < M :: Provenance > > {
171
+ cast_to : TyAndLayout < ' tcx > ,
172
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
169
173
assert ! ( src. layout. ty. is_integral( ) || src. layout. ty. is_char( ) || src. layout. ty. is_bool( ) ) ;
170
- assert ! ( cast_ty . is_floating_point( ) || cast_ty . is_integral( ) || cast_ty . is_char( ) ) ;
174
+ assert ! ( cast_to . ty . is_floating_point( ) || cast_to . ty . is_integral( ) || cast_to . ty . is_char( ) ) ;
171
175
172
- Ok ( self . cast_from_int_like ( src. to_scalar ( ) , src. layout , cast_ty) ?. into ( ) )
176
+ Ok ( ImmTy :: from_scalar (
177
+ self . cast_from_int_like ( src. to_scalar ( ) , src. layout , cast_to. ty ) ?,
178
+ cast_to,
179
+ ) )
173
180
}
174
181
175
182
/// Handles 'FloatToFloat' and 'FloatToInt' casts.
176
183
pub fn float_to_float_or_int (
177
184
& self ,
178
185
src : & ImmTy < ' tcx , M :: Provenance > ,
179
- cast_ty : Ty < ' tcx > ,
180
- ) -> InterpResult < ' tcx , Immediate < M :: Provenance > > {
186
+ cast_to : TyAndLayout < ' tcx > ,
187
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
181
188
use rustc_type_ir:: sty:: TyKind :: * ;
182
189
183
- match src. layout . ty . kind ( ) {
190
+ let val = match src. layout . ty . kind ( ) {
184
191
// Floating point
185
- Float ( FloatTy :: F32 ) => {
186
- return Ok ( self . cast_from_float ( src. to_scalar ( ) . to_f32 ( ) ?, cast_ty) . into ( ) ) ;
187
- }
188
- Float ( FloatTy :: F64 ) => {
189
- return Ok ( self . cast_from_float ( src. to_scalar ( ) . to_f64 ( ) ?, cast_ty) . into ( ) ) ;
190
- }
192
+ Float ( FloatTy :: F32 ) => self . cast_from_float ( src. to_scalar ( ) . to_f32 ( ) ?, cast_to. ty ) ,
193
+ Float ( FloatTy :: F64 ) => self . cast_from_float ( src. to_scalar ( ) . to_f64 ( ) ?, cast_to. ty ) ,
191
194
_ => {
192
- bug ! ( "Can't cast 'Float' type into {:? }" , cast_ty ) ;
195
+ bug ! ( "Can't cast 'Float' type into {}" , cast_to . ty ) ;
193
196
}
194
- }
197
+ } ;
198
+ Ok ( ImmTy :: from_scalar ( val, cast_to) )
195
199
}
196
200
197
201
/// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
198
202
pub fn ptr_to_ptr (
199
203
& self ,
200
204
src : & ImmTy < ' tcx , M :: Provenance > ,
201
- cast_ty : Ty < ' tcx > ,
202
- ) -> InterpResult < ' tcx , Immediate < M :: Provenance > > {
205
+ cast_to : TyAndLayout < ' tcx > ,
206
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
203
207
assert ! ( src. layout. ty. is_any_ptr( ) ) ;
204
- assert ! ( cast_ty . is_unsafe_ptr( ) ) ;
208
+ assert ! ( cast_to . ty . is_unsafe_ptr( ) ) ;
205
209
// Handle casting any ptr to raw ptr (might be a fat ptr).
206
- let dest_layout = self . layout_of ( cast_ty) ?;
207
- if dest_layout. size == src. layout . size {
210
+ if cast_to. size == src. layout . size {
208
211
// Thin or fat pointer that just hast the ptr kind of target type changed.
209
- return Ok ( * * src) ;
212
+ return Ok ( ImmTy :: from_immediate ( * * src, cast_to ) ) ;
210
213
} else {
211
214
// Casting the metadata away from a fat ptr.
212
215
assert_eq ! ( src. layout. size, 2 * self . pointer_size( ) ) ;
213
- assert_eq ! ( dest_layout . size, self . pointer_size( ) ) ;
216
+ assert_eq ! ( cast_to . size, self . pointer_size( ) ) ;
214
217
assert ! ( src. layout. ty. is_unsafe_ptr( ) ) ;
215
218
return match * * src {
216
- Immediate :: ScalarPair ( data, _) => Ok ( data . into ( ) ) ,
219
+ Immediate :: ScalarPair ( data, _) => Ok ( ImmTy :: from_scalar ( data , cast_to ) ) ,
217
220
Immediate :: Scalar ( ..) => span_bug ! (
218
221
self . cur_span( ) ,
219
- "{:?} input to a fat-to-thin cast ({:? } -> {:? })" ,
222
+ "{:?} input to a fat-to-thin cast ({} -> {})" ,
220
223
* src,
221
224
src. layout. ty,
222
- cast_ty
225
+ cast_to . ty
223
226
) ,
224
227
Immediate :: Uninit => throw_ub ! ( InvalidUninitBytes ( None ) ) ,
225
228
} ;
@@ -229,27 +232,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
229
232
pub fn pointer_expose_address_cast (
230
233
& mut self ,
231
234
src : & ImmTy < ' tcx , M :: Provenance > ,
232
- cast_ty : Ty < ' tcx > ,
233
- ) -> InterpResult < ' tcx , Immediate < M :: Provenance > > {
235
+ cast_to : TyAndLayout < ' tcx > ,
236
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
234
237
assert_matches ! ( src. layout. ty. kind( ) , ty:: RawPtr ( _) | ty:: FnPtr ( _) ) ;
235
- assert ! ( cast_ty . is_integral( ) ) ;
238
+ assert ! ( cast_to . ty . is_integral( ) ) ;
236
239
237
240
let scalar = src. to_scalar ( ) ;
238
241
let ptr = scalar. to_pointer ( self ) ?;
239
242
match ptr. into_pointer_or_addr ( ) {
240
243
Ok ( ptr) => M :: expose_ptr ( self , ptr) ?,
241
244
Err ( _) => { } // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
242
245
} ;
243
- Ok ( self . cast_from_int_like ( scalar, src. layout , cast_ty ) ? . into ( ) )
246
+ Ok ( ImmTy :: from_scalar ( self . cast_from_int_like ( scalar, src. layout , cast_to . ty ) ? , cast_to ) )
244
247
}
245
248
246
249
pub fn pointer_from_exposed_address_cast (
247
250
& self ,
248
251
src : & ImmTy < ' tcx , M :: Provenance > ,
249
- cast_ty : Ty < ' tcx > ,
250
- ) -> InterpResult < ' tcx , Immediate < M :: Provenance > > {
252
+ cast_to : TyAndLayout < ' tcx > ,
253
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
251
254
assert ! ( src. layout. ty. is_integral( ) ) ;
252
- assert_matches ! ( cast_ty . kind( ) , ty:: RawPtr ( _) ) ;
255
+ assert_matches ! ( cast_to . ty . kind( ) , ty:: RawPtr ( _) ) ;
253
256
254
257
// First cast to usize.
255
258
let scalar = src. to_scalar ( ) ;
@@ -258,12 +261,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
258
261
259
262
// Then turn address into pointer.
260
263
let ptr = M :: ptr_from_addr_cast ( & self , addr) ?;
261
- Ok ( Scalar :: from_maybe_pointer ( ptr, self ) . into ( ) )
264
+ Ok ( ImmTy :: from_scalar ( Scalar :: from_maybe_pointer ( ptr, self ) , cast_to ) )
262
265
}
263
266
264
267
/// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
265
268
/// type (basically everything with a scalar layout) to int/float/char types.
266
- pub fn cast_from_int_like (
269
+ fn cast_from_int_like (
267
270
& self ,
268
271
scalar : Scalar < M :: Provenance > , // input value (there is no ScalarTy so we separate data+layout)
269
272
src_layout : TyAndLayout < ' tcx > ,
@@ -298,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
298
301
}
299
302
300
303
// Casts to bool are not permitted by rustc, no need to handle them here.
301
- _ => span_bug ! ( self . cur_span( ) , "invalid int to {:? } cast" , cast_ty) ,
304
+ _ => span_bug ! ( self . cur_span( ) , "invalid int to {} cast" , cast_ty) ,
302
305
} )
303
306
}
304
307
@@ -331,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
331
334
// float -> f64
332
335
Float ( FloatTy :: F64 ) => Scalar :: from_f64 ( f. convert ( & mut false ) . value ) ,
333
336
// That's it.
334
- _ => span_bug ! ( self . cur_span( ) , "invalid float to {:? } cast" , dest_ty) ,
337
+ _ => span_bug ! ( self . cur_span( ) , "invalid float to {} cast" , dest_ty) ,
335
338
}
336
339
}
337
340
@@ -390,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
390
393
391
394
span_bug ! (
392
395
self . cur_span( ) ,
393
- "invalid pointer unsizing {:? } -> {:? }" ,
396
+ "invalid pointer unsizing {} -> {}" ,
394
397
src. layout. ty,
395
398
cast_ty
396
399
)
@@ -404,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
404
407
cast_ty : TyAndLayout < ' tcx > ,
405
408
dest : & PlaceTy < ' tcx , M :: Provenance > ,
406
409
) -> InterpResult < ' tcx > {
407
- trace ! ( "Unsizing {:?} of type {} into {:? }" , * src, src. layout. ty, cast_ty. ty) ;
410
+ trace ! ( "Unsizing {:?} of type {} into {}" , * src, src. layout. ty, cast_ty. ty) ;
408
411
match ( & src. layout . ty . kind ( ) , & cast_ty. ty . kind ( ) ) {
409
412
( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, c, _) | & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) )
410
413
| ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) ) => {
0 commit comments