@@ -84,14 +84,18 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
8484 }
8585
8686 #[ inline]
87- pub fn to_scalar_pair ( self ) -> InterpResult < ' tcx , ( Scalar < Tag > , Scalar < Tag > ) > {
87+ pub fn to_scalar_or_uninit_pair ( self ) -> ( ScalarMaybeUninit < Tag > , ScalarMaybeUninit < Tag > ) {
8888 match self {
89- Immediate :: ScalarPair ( val1, val2) => Ok ( ( val1. check_init ( ) ?, val2. check_init ( ) ?) ) ,
90- Immediate :: Scalar ( ..) => {
91- bug ! ( "Got a scalar where a scalar pair was expected" )
92- }
89+ Immediate :: ScalarPair ( val1, val2) => ( val1, val2) ,
90+ Immediate :: Scalar ( ..) => bug ! ( "Got a scalar where a scalar pair was expected" ) ,
9391 }
9492 }
93+
94+ #[ inline]
95+ pub fn to_scalar_pair ( self ) -> InterpResult < ' tcx , ( Scalar < Tag > , Scalar < Tag > ) > {
96+ let ( val1, val2) = self . to_scalar_or_uninit_pair ( ) ;
97+ Ok ( ( val1. check_init ( ) ?, val2. check_init ( ) ?) )
98+ }
9599}
96100
97101// ScalarPair needs a type to interpret, so we often have an immediate and a type together
@@ -251,6 +255,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
251255 fn try_read_immediate_from_mplace (
252256 & self ,
253257 mplace : & MPlaceTy < ' tcx , M :: PointerTag > ,
258+ force : bool ,
254259 ) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , M :: PointerTag > > > {
255260 if mplace. layout . is_unsized ( ) {
256261 // Don't touch unsized
@@ -271,27 +276,40 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
271276 // case where some of the bytes are initialized and others are not. So, we need an extra
272277 // check that walks over the type of `mplace` to make sure it is truly correct to treat this
273278 // like a `Scalar` (or `ScalarPair`).
274- match mplace. layout . abi {
275- Abi :: Scalar ( abi:: Scalar :: Initialized { .. } ) => {
276- let scalar = alloc. read_scalar ( alloc_range ( Size :: ZERO , mplace. layout . size ) ) ?;
277- Ok ( Some ( ImmTy { imm : scalar. into ( ) , layout : mplace. layout } ) )
278- }
279+ let scalar_layout = match mplace. layout . abi {
280+ // `if` does not work nested inside patterns, making this a bit awkward to express.
281+ Abi :: Scalar ( abi:: Scalar :: Initialized { value : s, .. } ) => Some ( s) ,
282+ Abi :: Scalar ( s) if force => Some ( s. primitive ( ) ) ,
283+ _ => None ,
284+ } ;
285+ if let Some ( _) = scalar_layout {
286+ let scalar = alloc. read_scalar ( alloc_range ( Size :: ZERO , mplace. layout . size ) ) ?;
287+ return Ok ( Some ( ImmTy { imm : scalar. into ( ) , layout : mplace. layout } ) ) ;
288+ }
289+ let scalar_pair_layout = match mplace. layout . abi {
279290 Abi :: ScalarPair (
280291 abi:: Scalar :: Initialized { value : a, .. } ,
281292 abi:: Scalar :: Initialized { value : b, .. } ,
282- ) => {
283- // We checked `ptr_align` above, so all fields will have the alignment they need.
284- // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
285- // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
286- let ( a_size, b_size) = ( a. size ( self ) , b. size ( self ) ) ;
287- let b_offset = a_size. align_to ( b. align ( self ) . abi ) ;
288- assert ! ( b_offset. bytes( ) > 0 ) ; // we later use the offset to tell apart the fields
289- let a_val = alloc. read_scalar ( alloc_range ( Size :: ZERO , a_size) ) ?;
290- let b_val = alloc. read_scalar ( alloc_range ( b_offset, b_size) ) ?;
291- Ok ( Some ( ImmTy { imm : Immediate :: ScalarPair ( a_val, b_val) , layout : mplace. layout } ) )
292- }
293- _ => Ok ( None ) ,
293+ ) => Some ( ( a, b) ) ,
294+ Abi :: ScalarPair ( a, b) if force => Some ( ( a. primitive ( ) , b. primitive ( ) ) ) ,
295+ _ => None ,
296+ } ;
297+ if let Some ( ( a, b) ) = scalar_pair_layout {
298+ // We checked `ptr_align` above, so all fields will have the alignment they need.
299+ // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
300+ // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
301+ let ( a_size, b_size) = ( a. size ( self ) , b. size ( self ) ) ;
302+ let b_offset = a_size. align_to ( b. align ( self ) . abi ) ;
303+ assert ! ( b_offset. bytes( ) > 0 ) ; // we later use the offset to tell apart the fields
304+ let a_val = alloc. read_scalar ( alloc_range ( Size :: ZERO , a_size) ) ?;
305+ let b_val = alloc. read_scalar ( alloc_range ( b_offset, b_size) ) ?;
306+ return Ok ( Some ( ImmTy {
307+ imm : Immediate :: ScalarPair ( a_val, b_val) ,
308+ layout : mplace. layout ,
309+ } ) ) ;
294310 }
311+ // Neither a scalar nor scalar pair.
312+ return Ok ( None ) ;
295313 }
296314
297315 /// Try returning an immediate for the operand.
@@ -300,13 +318,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
300318 /// Note that for a given layout, this operation will either always fail or always
301319 /// succeed! Whether it succeeds depends on whether the layout can be represented
302320 /// in an `Immediate`, not on which data is stored there currently.
321+ ///
322+ /// If `force` is `true`, then even scalars with fields that can be ununit will be
323+ /// read. This means the load is lossy and should not be written back!
324+ /// This flag exists only for validity checking.
303325 pub fn try_read_immediate (
304326 & self ,
305327 src : & OpTy < ' tcx , M :: PointerTag > ,
328+ force : bool ,
306329 ) -> InterpResult < ' tcx , Result < ImmTy < ' tcx , M :: PointerTag > , MPlaceTy < ' tcx , M :: PointerTag > > > {
307330 Ok ( match src. try_as_mplace ( ) {
308331 Ok ( ref mplace) => {
309- if let Some ( val) = self . try_read_immediate_from_mplace ( mplace) ? {
332+ if let Some ( val) = self . try_read_immediate_from_mplace ( mplace, force ) ? {
310333 Ok ( val)
311334 } else {
312335 Err ( * mplace)
@@ -322,7 +345,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322345 & self ,
323346 op : & OpTy < ' tcx , M :: PointerTag > ,
324347 ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
325- if let Ok ( imm) = self . try_read_immediate ( op) ? {
348+ if let Ok ( imm) = self . try_read_immediate ( op, /*force*/ false ) ? {
326349 Ok ( imm)
327350 } else {
328351 span_bug ! ( self . cur_span( ) , "primitive read failed for type: {:?}" , op. layout. ty) ;
0 commit comments