@@ -84,14 +84,18 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
84
84
}
85
85
86
86
#[ 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 > ) {
88
88
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" ) ,
93
91
}
94
92
}
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
+ }
95
99
}
96
100
97
101
// 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> {
251
255
fn try_read_immediate_from_mplace (
252
256
& self ,
253
257
mplace : & MPlaceTy < ' tcx , M :: PointerTag > ,
258
+ force : bool ,
254
259
) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , M :: PointerTag > > > {
255
260
if mplace. layout . is_unsized ( ) {
256
261
// Don't touch unsized
@@ -271,27 +276,40 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
271
276
// case where some of the bytes are initialized and others are not. So, we need an extra
272
277
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
273
278
// 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 {
279
290
Abi :: ScalarPair (
280
291
abi:: Scalar :: Initialized { value : a, .. } ,
281
292
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
+ } ) ) ;
294
310
}
311
+ // Neither a scalar nor scalar pair.
312
+ return Ok ( None ) ;
295
313
}
296
314
297
315
/// Try returning an immediate for the operand.
@@ -300,13 +318,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
300
318
/// Note that for a given layout, this operation will either always fail or always
301
319
/// succeed! Whether it succeeds depends on whether the layout can be represented
302
320
/// 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.
303
325
pub fn try_read_immediate (
304
326
& self ,
305
327
src : & OpTy < ' tcx , M :: PointerTag > ,
328
+ force : bool ,
306
329
) -> InterpResult < ' tcx , Result < ImmTy < ' tcx , M :: PointerTag > , MPlaceTy < ' tcx , M :: PointerTag > > > {
307
330
Ok ( match src. try_as_mplace ( ) {
308
331
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 ) ? {
310
333
Ok ( val)
311
334
} else {
312
335
Err ( * mplace)
@@ -322,7 +345,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322
345
& self ,
323
346
op : & OpTy < ' tcx , M :: PointerTag > ,
324
347
) -> 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 ) ? {
326
349
Ok ( imm)
327
350
} else {
328
351
span_bug ! ( self . cur_span( ) , "primitive read failed for type: {:?}" , op. layout. ty) ;
0 commit comments