11use std:: convert:: TryFrom ;
22
3- use super :: { FnVal , ImmTy , Immediate , InterpCx , Machine , OpTy , PlaceTy } ;
43use rustc_apfloat:: ieee:: { Double , Single } ;
54use rustc_apfloat:: { Float , FloatConvert } ;
65use rustc_ast:: ast:: FloatTy ;
6+ use rustc_attr as attr;
77use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar } ;
88use rustc_middle:: mir:: CastKind ;
99use rustc_middle:: ty:: adjustment:: PointerCast ;
10- use rustc_middle:: ty:: layout:: TyAndLayout ;
10+ use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
1111use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeFoldable } ;
1212use 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 } ;
1416
1517impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
1618 pub fn cast (
1719 & mut self ,
1820 src : OpTy < ' tcx , M :: PointerTag > ,
19- kind : CastKind ,
21+ cast_kind : CastKind ,
22+ cast_ty : Ty < ' tcx > ,
2023 dest : PlaceTy < ' tcx , M :: PointerTag > ,
2124 ) -> InterpResult < ' tcx > {
2225 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 {
2428 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) ?;
2631 }
2732
28- Misc | Pointer ( PointerCast :: MutToConstPointer | PointerCast :: ArrayToPointer ) => {
33+ Misc => {
2934 let src = self . read_immediate ( src) ?;
30- let res = self . cast_immediate ( src, dest . layout ) ?;
35+ let res = self . misc_cast ( src, cast_ty ) ?;
3136 self . write_immediate ( res, dest) ?;
3237 }
3338
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+
3445 Pointer ( PointerCast :: ReifyFnPointer ) => {
3546 // The src operand does not matter, just its type
3647 match src. layout . ty . kind {
@@ -61,12 +72,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6172
6273 Pointer ( PointerCast :: UnsafeFnPointer ) => {
6374 let src = self . read_immediate ( src) ?;
64- match dest . layout . ty . kind {
75+ match cast_ty . kind {
6576 ty:: FnPtr ( _) => {
6677 // No change to value
6778 self . write_immediate ( * src, dest) ?;
6879 }
69- _ => bug ! ( "fn to unsafe fn cast on {:?}" , dest . layout . ty ) ,
80+ _ => bug ! ( "fn to unsafe fn cast on {:?}" , cast_ty ) ,
7081 }
7182 }
7283
@@ -95,25 +106,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
95106 Ok ( ( ) )
96107 }
97108
98- fn cast_immediate (
109+ fn misc_cast (
99110 & self ,
100111 src : ImmTy < ' tcx , M :: PointerTag > ,
101- dest_layout : TyAndLayout < ' tcx > ,
112+ cast_ty : Ty < ' tcx > ,
102113 ) -> InterpResult < ' tcx , Immediate < M :: PointerTag > > {
103114 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 ) ;
105116
106117 match src. layout . ty . kind {
107118 // Floating point
108119 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 ( ) ) ;
112121 }
113122 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 ( ) ) ;
117124 }
118125 // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
119126 // are represented as integers.
@@ -128,121 +135,118 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
128135 ) ,
129136 }
130137
138+ // # First handle non-scalar source values.
139+
131140 // Handle cast from a univariant (ZST) enum.
132141 match src. layout . variants {
133142 Variants :: Single { index } => {
134143 if let Some ( discr) = src. layout . ty . discriminant_for_variant ( * self . tcx , index) {
135144 assert ! ( src. layout. is_zst( ) ) ;
136145 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 ( ) ) ;
140147 }
141148 }
142149 Variants :: Multiple { .. } => { }
143150 }
144151
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-
164152 // 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+ }
169173 }
170174
175+ // # The remaining source values are scalar.
176+
171177 // For all remaining casts, we either
172178 // (a) cast a raw ptr to usize, or
173179 // (b) cast from an integer-like (including bool, char, enums).
174180 // In both cases we want the bits.
175181 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 ( ) )
177183 }
178184
179- fn cast_from_int_like (
185+ pub ( super ) fn cast_from_scalar (
180186 & self ,
181- v : u128 , // raw bits
187+ v : u128 , // raw bits (there is no ScalarTy so we separate data+layout)
182188 src_layout : TyAndLayout < ' tcx > ,
183- dest_layout : TyAndLayout < ' tcx > ,
184- ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > > {
189+ cast_ty : Ty < ' tcx > ,
190+ ) -> Scalar < M :: PointerTag > {
185191 // 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`.
187193 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 ) ;
189195 use rustc_middle:: ty:: TyKind :: * ;
190- match dest_layout . ty . kind {
196+ match cast_ty . kind {
191197 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)
194206 }
195207
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 ) ,
204212
205213 Char => {
206214 // `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 ( ) )
208216 }
209217
210218 // 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 ) ,
212220 }
213221 }
214222
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 >
220224 where
221225 F : Float + Into < Scalar < M :: PointerTag > > + FloatConvert < Single > + FloatConvert < Double > ,
222226 {
223227 use rustc_middle:: ty:: TyKind :: * ;
224228 match dest_ty. kind {
225229 // float -> uint
226230 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 ( ) ;
228232 // `to_u128` is a saturating cast, which is what we need
229233 // (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 ;
231235 // This should already fit the bit width
232- Ok ( Scalar :: from_uint ( v, Size :: from_bits ( width ) ) )
236+ Scalar :: from_uint ( v, size )
233237 }
234238 // float -> int
235239 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 ( ) ;
237241 // `to_i128` is a saturating cast, which is what we need
238242 // (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 )
241245 }
242246 // 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 ) ,
244248 // 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 ) ,
246250 // That's it.
247251 _ => bug ! ( "invalid float to {:?} cast" , dest_ty) ,
248252 }
@@ -254,11 +258,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
254258 dest : PlaceTy < ' tcx , M :: PointerTag > ,
255259 // The pointee types
256260 source_ty : Ty < ' tcx > ,
257- dest_ty : Ty < ' tcx > ,
261+ cast_ty : Ty < ' tcx > ,
258262 ) -> InterpResult < ' tcx > {
259263 // A<Struct> -> A<Trait> conversion
260264 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 ) ;
262266
263267 match ( & src_pointee_ty. kind , & dest_pointee_ty. kind ) {
264268 ( & ty:: Array ( _, length) , & ty:: Slice ( _) ) => {
@@ -286,48 +290,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
286290 self . write_immediate ( val, dest)
287291 }
288292
289- _ => bug ! ( "invalid unsizing {:?} -> {:?}" , src. layout. ty, dest . layout . ty ) ,
293+ _ => bug ! ( "invalid unsizing {:?} -> {:?}" , src. layout. ty, cast_ty ) ,
290294 }
291295 }
292296
293297 fn unsize_into (
294298 & mut self ,
295299 src : OpTy < ' tcx , M :: PointerTag > ,
300+ cast_ty : TyAndLayout < ' tcx > ,
296301 dest : PlaceTy < ' tcx , M :: PointerTag > ,
297302 ) -> 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 )
303308 }
304309 ( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
305310 assert_eq ! ( def_a, def_b) ;
306311 if def_a. is_box ( ) || def_b. is_box ( ) {
307312 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 ) ;
309314 }
310315 return self . unsize_into_ptr (
311316 src,
312317 dest,
313318 src. layout . ty . boxed_ty ( ) ,
314- dest . layout . ty . boxed_ty ( ) ,
319+ cast_ty . ty . boxed_ty ( ) ,
315320 ) ;
316321 }
317322
318323 // unsizing of generic struct with pointer fields
319324 // Example: `Arc<T>` -> `Arc<Trait>`
320325 // here we need to increase the size of every &T thin ptr field to a fat ptr
321326 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 ( ) {
324329 continue ;
325330 }
326331 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 {
328334 self . copy_op ( src_field, dst_field) ?;
329335 } else {
330- self . unsize_into ( src_field, dst_field) ?;
336+ self . unsize_into ( src_field, cast_ty_field , dst_field) ?;
331337 }
332338 }
333339 Ok ( ( ) )
0 commit comments