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 ;
@@ -12,25 +11,40 @@ use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
1211use rustc_span:: symbol:: sym;
1312use rustc_target:: abi:: { LayoutOf , Size , Variants } ;
1413
14+ use super :: { truncate, FnVal , ImmTy , Immediate , InterpCx , Machine , OpTy , PlaceTy } ;
15+
1516impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
1617 pub fn cast (
1718 & mut self ,
1819 src : OpTy < ' tcx , M :: PointerTag > ,
19- kind : CastKind ,
20+ cast_kind : CastKind ,
21+ cast_ty : Ty < ' tcx > ,
2022 dest : PlaceTy < ' tcx , M :: PointerTag > ,
2123 ) -> InterpResult < ' tcx > {
2224 use rustc_middle:: mir:: CastKind :: * ;
23- match kind {
25+ // FIXME: In which cases should we trigger UB when the source is uninit?
26+ match cast_kind {
2427 Pointer ( PointerCast :: Unsize ) => {
28+ assert_eq ! (
29+ cast_ty, dest. layout. ty,
30+ "mismatch of cast type {} and place type {}" ,
31+ cast_ty, dest. layout. ty
32+ ) ;
2533 self . unsize_into ( src, dest) ?;
2634 }
2735
28- Misc | Pointer ( PointerCast :: MutToConstPointer | PointerCast :: ArrayToPointer ) => {
36+ Misc => {
2937 let src = self . read_immediate ( src) ?;
30- let res = self . cast_immediate ( src, dest . layout ) ?;
38+ let res = self . misc_cast ( src, cast_ty ) ?;
3139 self . write_immediate ( res, dest) ?;
3240 }
3341
42+ Pointer ( PointerCast :: MutToConstPointer | PointerCast :: ArrayToPointer ) => {
43+ // These are NOPs, but can be wide pointers.
44+ let v = self . read_immediate ( src) ?;
45+ self . write_immediate ( * v, dest) ?;
46+ }
47+
3448 Pointer ( PointerCast :: ReifyFnPointer ) => {
3549 // The src operand does not matter, just its type
3650 match src. layout . ty . kind {
@@ -61,12 +75,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6175
6276 Pointer ( PointerCast :: UnsafeFnPointer ) => {
6377 let src = self . read_immediate ( src) ?;
64- match dest . layout . ty . kind {
78+ match cast_ty . kind {
6579 ty:: FnPtr ( _) => {
6680 // No change to value
6781 self . write_immediate ( * src, dest) ?;
6882 }
69- _ => bug ! ( "fn to unsafe fn cast on {:?}" , dest . layout . ty ) ,
83+ _ => bug ! ( "fn to unsafe fn cast on {:?}" , cast_ty ) ,
7084 }
7185 }
7286
@@ -95,21 +109,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
95109 Ok ( ( ) )
96110 }
97111
98- fn cast_immediate (
112+ fn misc_cast (
99113 & self ,
100114 src : ImmTy < ' tcx , M :: PointerTag > ,
101- dest_layout : TyAndLayout < ' tcx > ,
115+ cast_ty : Ty < ' tcx > ,
102116 ) -> InterpResult < ' tcx , Immediate < M :: PointerTag > > {
103117 use rustc_middle:: ty:: TyKind :: * ;
104- trace ! ( "Casting {:?}: {:?} to {:?}" , * src, src. layout. ty, dest_layout . ty ) ;
118+ trace ! ( "Casting {:?}: {:?} to {:?}" , * src, src. layout. ty, cast_ty ) ;
105119
106120 match src. layout . ty . kind {
107121 // Floating point
108122 Float ( FloatTy :: F32 ) => {
109- return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f32 ( ) ?, dest_layout . ty ) . into ( ) ) ;
123+ return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f32 ( ) ?, cast_ty ) . into ( ) ) ;
110124 }
111125 Float ( FloatTy :: F64 ) => {
112- return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f64 ( ) ?, dest_layout . ty ) . into ( ) ) ;
126+ return Ok ( self . cast_from_float ( src. to_scalar ( ) ?. to_f64 ( ) ?, cast_ty ) . into ( ) ) ;
113127 }
114128 // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
115129 // are represented as integers.
@@ -124,69 +138,79 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
124138 ) ,
125139 }
126140
141+ // # First handle non-scalar source values.
142+
127143 // Handle cast from a univariant (ZST) enum.
128144 match src. layout . variants {
129145 Variants :: Single { index } => {
130146 if let Some ( discr) = src. layout . ty . discriminant_for_variant ( * self . tcx , index) {
131147 assert ! ( src. layout. is_zst( ) ) ;
132148 let discr_layout = self . layout_of ( discr. ty ) ?;
133- return Ok ( self
134- . cast_from_int_like ( discr. val , discr_layout, dest_layout)
135- . into ( ) ) ;
149+ return Ok ( self . cast_from_scalar ( discr. val , discr_layout, cast_ty) . into ( ) ) ;
136150 }
137151 }
138152 Variants :: Multiple { .. } => { }
139153 }
140154
141- // Handle casting the metadata away from a fat pointer.
142- if src. layout . ty . is_unsafe_ptr ( )
143- && dest_layout. ty . is_unsafe_ptr ( )
144- && dest_layout. size != src. layout . size
145- {
146- assert_eq ! ( src. layout. size, 2 * self . memory. pointer_size( ) ) ;
147- assert_eq ! ( dest_layout. size, self . memory. pointer_size( ) ) ;
148- assert ! ( dest_layout. ty. is_unsafe_ptr( ) ) ;
149- match * src {
150- Immediate :: ScalarPair ( data, _) => return Ok ( data. into ( ) ) ,
151- Immediate :: Scalar ( ..) => bug ! (
152- "{:?} input to a fat-to-thin cast ({:?} -> {:?})" ,
153- * src,
154- src. layout. ty,
155- dest_layout. ty
156- ) ,
157- } ;
158- }
159-
160155 // Handle casting any ptr to raw ptr (might be a fat ptr).
161- if src. layout . ty . is_any_ptr ( ) && dest_layout. ty . is_unsafe_ptr ( ) {
162- // The only possible size-unequal case was handled above.
163- assert_eq ! ( src. layout. size, dest_layout. size) ;
164- return Ok ( * src) ;
156+ if src. layout . ty . is_any_ptr ( ) && cast_ty. is_unsafe_ptr ( ) {
157+ let dest_layout = self . layout_of ( cast_ty) ?;
158+ if dest_layout. size == src. layout . size {
159+ // Thin or fat pointer that just hast the ptr kind of target type changed.
160+ return Ok ( * src) ;
161+ } else {
162+ // Casting the metadata away from a fat ptr.
163+ assert_eq ! ( src. layout. size, 2 * self . memory. pointer_size( ) ) ;
164+ assert_eq ! ( dest_layout. size, self . memory. pointer_size( ) ) ;
165+ assert ! ( src. layout. ty. is_unsafe_ptr( ) ) ;
166+ return match * src {
167+ Immediate :: ScalarPair ( data, _) => Ok ( data. into ( ) ) ,
168+ Immediate :: Scalar ( ..) => bug ! (
169+ "{:?} input to a fat-to-thin cast ({:?} -> {:?})" ,
170+ * src,
171+ src. layout. ty,
172+ cast_ty
173+ ) ,
174+ } ;
175+ }
165176 }
166177
178+ // # The remaining source values are scalar.
179+
167180 // For all remaining casts, we either
168181 // (a) cast a raw ptr to usize, or
169182 // (b) cast from an integer-like (including bool, char, enums).
170183 // In both cases we want the bits.
171184 let bits = self . force_bits ( src. to_scalar ( ) ?, src. layout . size ) ?;
172- Ok ( self . cast_from_int_like ( bits, src. layout , dest_layout ) . into ( ) )
185+ Ok ( self . cast_from_scalar ( bits, src. layout , cast_ty ) . into ( ) )
173186 }
174187
175- pub ( super ) fn cast_from_int_like (
188+ pub ( super ) fn cast_from_scalar (
176189 & self ,
177- v : u128 , // raw bits
190+ v : u128 , // raw bits (there is no ScalarTy so we separate data+layout)
178191 src_layout : TyAndLayout < ' tcx > ,
179- dest_layout : TyAndLayout < ' tcx > ,
192+ cast_ty : Ty < ' tcx > ,
180193 ) -> Scalar < M :: PointerTag > {
181194 // Let's make sure v is sign-extended *if* it has a signed type.
182- let signed = src_layout. abi . is_signed ( ) ;
195+ let signed = src_layout. abi . is_signed ( ) ; // also checks that abi is `Scalar`.
183196 let v = if signed { self . sign_extend ( v, src_layout) } else { v } ;
184- trace ! ( "cast_from_int : {}, {}, {}" , v, src_layout. ty, dest_layout . ty ) ;
197+ trace ! ( "cast_from_scalar : {}, {} -> {}" , v, src_layout. ty, cast_ty ) ;
185198 use rustc_middle:: ty:: TyKind :: * ;
186- match dest_layout . ty . kind {
199+ match cast_ty . kind {
187200 Int ( _) | Uint ( _) | RawPtr ( _) => {
188- let v = self . truncate ( v, dest_layout) ;
189- Scalar :: from_uint ( v, dest_layout. size )
201+ let size = match cast_ty. kind {
202+ // FIXME: Isn't there a helper for this? The same pattern occurs below.
203+ Int ( t) => {
204+ t. bit_width ( ) . map ( Size :: from_bits) . unwrap_or_else ( || self . pointer_size ( ) )
205+ }
206+ Uint ( t) => {
207+ t. bit_width ( ) . map ( Size :: from_bits) . unwrap_or_else ( || self . pointer_size ( ) )
208+ }
209+ RawPtr ( _) => self . pointer_size ( ) ,
210+ _ => bug ! ( ) ,
211+ } ;
212+ let v = truncate ( v, size) ;
213+ Scalar :: from_uint ( v, size)
190214 }
191215
192216 Float ( FloatTy :: F32 ) if signed => Scalar :: from_f32 ( Single :: from_i128 ( v as i128 ) . value ) ,
@@ -200,7 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
200224 }
201225
202226 // Casts to bool are not permitted by rustc, no need to handle them here.
203- _ => bug ! ( "invalid int to {:?} cast" , dest_layout . ty ) ,
227+ _ => bug ! ( "invalid int to {:?} cast" , cast_ty ) ,
204228 }
205229 }
206230
@@ -283,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
283307 src : OpTy < ' tcx , M :: PointerTag > ,
284308 dest : PlaceTy < ' tcx , M :: PointerTag > ,
285309 ) -> InterpResult < ' tcx > {
286- trace ! ( "Unsizing {:?} into {:?}" , src, dest) ;
310+ trace ! ( "Unsizing {:?} of type {} into {:?}" , * src, src . layout . ty , dest. layout . ty ) ;
287311 match ( & src. layout . ty . kind , & dest. layout . ty . kind ) {
288312 ( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, d, _) | & ty:: RawPtr ( TypeAndMut { ty : d, .. } ) )
289313 | ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : d, .. } ) ) => {
0 commit comments