@@ -24,41 +24,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2424 cast_ty : Ty < ' tcx > ,
2525 dest : & PlaceTy < ' tcx , M :: Provenance > ,
2626 ) -> 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) ? } ;
2731 // FIXME: In which cases should we trigger UB when the source is uninit?
2832 match cast_kind {
2933 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) ?;
3235 }
3336
3437 CastKind :: PointerExposeAddress => {
3538 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) ?;
3841 }
3942
4043 CastKind :: PointerFromExposedAddress => {
4144 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) ?;
4447 }
4548
4649 CastKind :: IntToInt | CastKind :: IntToFloat => {
4750 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) ?;
5053 }
5154
5255 CastKind :: FloatToFloat | CastKind :: FloatToInt => {
5356 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) ?;
5659 }
5760
5861 CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
5962 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) ?;
6265 }
6366
6467 CastKind :: PointerCoercion (
@@ -87,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8790 let fn_ptr = self . fn_ptr ( FnVal :: Instance ( instance) ) ;
8891 self . write_pointer ( fn_ptr, dest) ?;
8992 }
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) ,
9194 }
9295 }
9396
@@ -98,7 +101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
98101 // No change to value
99102 self . write_immediate ( * src, dest) ?;
100103 }
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) ,
102105 }
103106 }
104107
@@ -119,7 +122,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
119122 let fn_ptr = self . fn_ptr ( FnVal :: Instance ( instance) ) ;
120123 self . write_pointer ( fn_ptr, dest) ?;
121124 }
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) ,
123126 }
124127 }
125128
@@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
140143 CastKind :: Transmute => {
141144 assert ! ( src. layout. is_sized( ) ) ;
142145 assert ! ( dest. layout. is_sized( ) ) ;
146+ assert_eq ! ( cast_ty, dest. layout. ty) ; // we otherwise ignore `cast_ty` enirely...
143147 if src. layout . size != dest. layout . size {
144148 let src_bytes = src. layout . size . bytes ( ) ;
145149 let dest_bytes = dest. layout . size . bytes ( ) ;
@@ -164,62 +168,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
164168 pub fn int_to_int_or_float (
165169 & self ,
166170 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 > > {
169173 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( ) ) ;
171175
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+ ) )
173180 }
174181
175182 /// Handles 'FloatToFloat' and 'FloatToInt' casts.
176183 pub fn float_to_float_or_int (
177184 & self ,
178185 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 > > {
181188 use rustc_type_ir:: sty:: TyKind :: * ;
182189
183- match src. layout . ty . kind ( ) {
190+ let val = match src. layout . ty . kind ( ) {
184191 // 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 ) ,
191194 _ => {
192- bug ! ( "Can't cast 'Float' type into {:? }" , cast_ty ) ;
195+ bug ! ( "Can't cast 'Float' type into {}" , cast_to . ty ) ;
193196 }
194- }
197+ } ;
198+ Ok ( ImmTy :: from_scalar ( val, cast_to) )
195199 }
196200
197201 /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
198202 pub fn ptr_to_ptr (
199203 & self ,
200204 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 > > {
203207 assert ! ( src. layout. ty. is_any_ptr( ) ) ;
204- assert ! ( cast_ty . is_unsafe_ptr( ) ) ;
208+ assert ! ( cast_to . ty . is_unsafe_ptr( ) ) ;
205209 // 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 {
208211 // 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 ) ) ;
210213 } else {
211214 // Casting the metadata away from a fat ptr.
212215 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( ) ) ;
214217 assert ! ( src. layout. ty. is_unsafe_ptr( ) ) ;
215218 return match * * src {
216- Immediate :: ScalarPair ( data, _) => Ok ( data . into ( ) ) ,
219+ Immediate :: ScalarPair ( data, _) => Ok ( ImmTy :: from_scalar ( data , cast_to ) ) ,
217220 Immediate :: Scalar ( ..) => span_bug ! (
218221 self . cur_span( ) ,
219- "{:?} input to a fat-to-thin cast ({:? } -> {:? })" ,
222+ "{:?} input to a fat-to-thin cast ({} -> {})" ,
220223 * src,
221224 src. layout. ty,
222- cast_ty
225+ cast_to . ty
223226 ) ,
224227 Immediate :: Uninit => throw_ub ! ( InvalidUninitBytes ( None ) ) ,
225228 } ;
@@ -229,27 +232,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
229232 pub fn pointer_expose_address_cast (
230233 & mut self ,
231234 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 > > {
234237 assert_matches ! ( src. layout. ty. kind( ) , ty:: RawPtr ( _) | ty:: FnPtr ( _) ) ;
235- assert ! ( cast_ty . is_integral( ) ) ;
238+ assert ! ( cast_to . ty . is_integral( ) ) ;
236239
237240 let scalar = src. to_scalar ( ) ;
238241 let ptr = scalar. to_pointer ( self ) ?;
239242 match ptr. into_pointer_or_addr ( ) {
240243 Ok ( ptr) => M :: expose_ptr ( self , ptr) ?,
241244 Err ( _) => { } // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
242245 } ;
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 ) )
244247 }
245248
246249 pub fn pointer_from_exposed_address_cast (
247250 & self ,
248251 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 > > {
251254 assert ! ( src. layout. ty. is_integral( ) ) ;
252- assert_matches ! ( cast_ty . kind( ) , ty:: RawPtr ( _) ) ;
255+ assert_matches ! ( cast_to . ty . kind( ) , ty:: RawPtr ( _) ) ;
253256
254257 // First cast to usize.
255258 let scalar = src. to_scalar ( ) ;
@@ -258,12 +261,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
258261
259262 // Then turn address into pointer.
260263 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 ) )
262265 }
263266
264267 /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
265268 /// 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 (
267270 & self ,
268271 scalar : Scalar < M :: Provenance > , // input value (there is no ScalarTy so we separate data+layout)
269272 src_layout : TyAndLayout < ' tcx > ,
@@ -298,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
298301 }
299302
300303 // 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) ,
302305 } )
303306 }
304307
@@ -331,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
331334 // float -> f64
332335 Float ( FloatTy :: F64 ) => Scalar :: from_f64 ( f. convert ( & mut false ) . value ) ,
333336 // 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) ,
335338 }
336339 }
337340
@@ -390,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
390393
391394 span_bug ! (
392395 self . cur_span( ) ,
393- "invalid pointer unsizing {:? } -> {:? }" ,
396+ "invalid pointer unsizing {} -> {}" ,
394397 src. layout. ty,
395398 cast_ty
396399 )
@@ -404,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
404407 cast_ty : TyAndLayout < ' tcx > ,
405408 dest : & PlaceTy < ' tcx , M :: Provenance > ,
406409 ) -> 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) ;
408411 match ( & src. layout . ty . kind ( ) , & cast_ty. ty . kind ( ) ) {
409412 ( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, c, _) | & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) )
410413 | ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) ) => {
0 commit comments