@@ -24,40 +24,43 @@ 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 ) ?;
39
+ let res = self . pointer_expose_address_cast ( & src, cast_layout ) ?;
37
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 ) ?;
45
+ let res = self . pointer_from_exposed_address_cast ( & src, cast_layout ) ?;
43
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 ) ?;
51
+ let res = self . int_to_int_or_float ( & src, cast_layout ) ?;
49
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 ) ?;
57
+ let res = self . float_to_float_or_int ( & src, cast_layout ) ?;
55
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 ) ?;
63
+ let res = self . ptr_to_ptr ( & src, cast_layout ) ?;
61
64
self . write_immediate ( * res, dest) ?;
62
65
}
63
66
@@ -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,64 +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 > ,
171
+ cast_to : TyAndLayout < ' tcx > ,
168
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
- let layout = self . layout_of ( cast_ty) ?;
173
176
Ok ( ImmTy :: from_scalar (
174
- self . cast_from_int_like ( src. to_scalar ( ) , src. layout , cast_ty ) ?,
175
- layout ,
177
+ self . cast_from_int_like ( src. to_scalar ( ) , src. layout , cast_to . ty ) ?,
178
+ cast_to ,
176
179
) )
177
180
}
178
181
179
182
/// Handles 'FloatToFloat' and 'FloatToInt' casts.
180
183
pub fn float_to_float_or_int (
181
184
& self ,
182
185
src : & ImmTy < ' tcx , M :: Provenance > ,
183
- cast_ty : Ty < ' tcx > ,
186
+ cast_to : TyAndLayout < ' tcx > ,
184
187
) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
185
188
use rustc_type_ir:: sty:: TyKind :: * ;
186
189
187
- let layout = self . layout_of ( cast_ty) ?;
188
190
let val = match src. layout . ty . kind ( ) {
189
191
// Floating point
190
- Float ( FloatTy :: F32 ) => self . cast_from_float ( src. to_scalar ( ) . to_f32 ( ) ?, cast_ty ) ,
191
- Float ( FloatTy :: F64 ) => self . cast_from_float ( src. to_scalar ( ) . to_f64 ( ) ?, cast_ty ) ,
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 ) ,
192
194
_ => {
193
- bug ! ( "Can't cast 'Float' type into {}" , cast_ty ) ;
195
+ bug ! ( "Can't cast 'Float' type into {}" , cast_to . ty ) ;
194
196
}
195
197
} ;
196
- Ok ( ImmTy :: from_scalar ( val, layout ) )
198
+ Ok ( ImmTy :: from_scalar ( val, cast_to ) )
197
199
}
198
200
199
201
/// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
200
202
pub fn ptr_to_ptr (
201
203
& self ,
202
204
src : & ImmTy < ' tcx , M :: Provenance > ,
203
- cast_ty : Ty < ' tcx > ,
205
+ cast_to : TyAndLayout < ' tcx > ,
204
206
) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
205
207
assert ! ( src. layout. ty. is_any_ptr( ) ) ;
206
- assert ! ( cast_ty . is_unsafe_ptr( ) ) ;
208
+ assert ! ( cast_to . ty . is_unsafe_ptr( ) ) ;
207
209
// Handle casting any ptr to raw ptr (might be a fat ptr).
208
- let dest_layout = self . layout_of ( cast_ty) ?;
209
- if dest_layout. size == src. layout . size {
210
+ if cast_to. size == src. layout . size {
210
211
// Thin or fat pointer that just hast the ptr kind of target type changed.
211
- return Ok ( ImmTy :: from_immediate ( * * src, dest_layout ) ) ;
212
+ return Ok ( ImmTy :: from_immediate ( * * src, cast_to ) ) ;
212
213
} else {
213
214
// Casting the metadata away from a fat ptr.
214
215
assert_eq ! ( src. layout. size, 2 * self . pointer_size( ) ) ;
215
- assert_eq ! ( dest_layout . size, self . pointer_size( ) ) ;
216
+ assert_eq ! ( cast_to . size, self . pointer_size( ) ) ;
216
217
assert ! ( src. layout. ty. is_unsafe_ptr( ) ) ;
217
218
return match * * src {
218
- Immediate :: ScalarPair ( data, _) => Ok ( ImmTy :: from_scalar ( data, dest_layout ) ) ,
219
+ Immediate :: ScalarPair ( data, _) => Ok ( ImmTy :: from_scalar ( data, cast_to ) ) ,
219
220
Immediate :: Scalar ( ..) => span_bug ! (
220
221
self . cur_span( ) ,
221
222
"{:?} input to a fat-to-thin cast ({} -> {})" ,
222
223
* src,
223
224
src. layout. ty,
224
- cast_ty
225
+ cast_to . ty
225
226
) ,
226
227
Immediate :: Uninit => throw_ub ! ( InvalidUninitBytes ( None ) ) ,
227
228
} ;
@@ -231,28 +232,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
231
232
pub fn pointer_expose_address_cast (
232
233
& mut self ,
233
234
src : & ImmTy < ' tcx , M :: Provenance > ,
234
- cast_ty : Ty < ' tcx > ,
235
+ cast_to : TyAndLayout < ' tcx > ,
235
236
) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
236
237
assert_matches ! ( src. layout. ty. kind( ) , ty:: RawPtr ( _) | ty:: FnPtr ( _) ) ;
237
- assert ! ( cast_ty . is_integral( ) ) ;
238
+ assert ! ( cast_to . ty . is_integral( ) ) ;
238
239
239
240
let scalar = src. to_scalar ( ) ;
240
241
let ptr = scalar. to_pointer ( self ) ?;
241
242
match ptr. into_pointer_or_addr ( ) {
242
243
Ok ( ptr) => M :: expose_ptr ( self , ptr) ?,
243
244
Err ( _) => { } // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
244
245
} ;
245
- let layout = self . layout_of ( cast_ty) ?;
246
- Ok ( ImmTy :: from_scalar ( self . cast_from_int_like ( scalar, src. layout , cast_ty) ?, layout) )
246
+ Ok ( ImmTy :: from_scalar ( self . cast_from_int_like ( scalar, src. layout , cast_to. ty ) ?, cast_to) )
247
247
}
248
248
249
249
pub fn pointer_from_exposed_address_cast (
250
250
& self ,
251
251
src : & ImmTy < ' tcx , M :: Provenance > ,
252
- cast_ty : Ty < ' tcx > ,
252
+ cast_to : TyAndLayout < ' tcx > ,
253
253
) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: Provenance > > {
254
254
assert ! ( src. layout. ty. is_integral( ) ) ;
255
- assert_matches ! ( cast_ty . kind( ) , ty:: RawPtr ( _) ) ;
255
+ assert_matches ! ( cast_to . ty . kind( ) , ty:: RawPtr ( _) ) ;
256
256
257
257
// First cast to usize.
258
258
let scalar = src. to_scalar ( ) ;
@@ -261,8 +261,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
261
261
262
262
// Then turn address into pointer.
263
263
let ptr = M :: ptr_from_addr_cast ( & self , addr) ?;
264
- let layout = self . layout_of ( cast_ty) ?;
265
- Ok ( ImmTy :: from_scalar ( Scalar :: from_maybe_pointer ( ptr, self ) , layout) )
264
+ Ok ( ImmTy :: from_scalar ( Scalar :: from_maybe_pointer ( ptr, self ) , cast_to) )
266
265
}
267
266
268
267
/// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
0 commit comments