@@ -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
@@ -248,9 +252,12 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> {
248252impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
249253 /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
250254 /// Returns `None` if the layout does not permit loading this as a value.
251- fn try_read_immediate_from_mplace (
255+ ///
256+ /// This is an internal function; call `read_immediate` instead.
257+ fn read_immediate_from_mplace_raw (
252258 & self ,
253259 mplace : & MPlaceTy < ' tcx , M :: PointerTag > ,
260+ force : bool ,
254261 ) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , M :: PointerTag > > > {
255262 if mplace. layout . is_unsized ( ) {
256263 // Don't touch unsized
@@ -271,42 +278,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
271278 // case where some of the bytes are initialized and others are not. So, we need an extra
272279 // check that walks over the type of `mplace` to make sure it is truly correct to treat this
273280 // 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- }
281+ let scalar_layout = match mplace. layout . abi {
282+ // `if` does not work nested inside patterns, making this a bit awkward to express.
283+ Abi :: Scalar ( abi:: Scalar :: Initialized { value : s, .. } ) => Some ( s) ,
284+ Abi :: Scalar ( s) if force => Some ( s. primitive ( ) ) ,
285+ _ => None ,
286+ } ;
287+ if let Some ( _) = scalar_layout {
288+ let scalar = alloc. read_scalar ( alloc_range ( Size :: ZERO , mplace. layout . size ) ) ?;
289+ return Ok ( Some ( ImmTy { imm : scalar. into ( ) , layout : mplace. layout } ) ) ;
290+ }
291+ let scalar_pair_layout = match mplace. layout . abi {
279292 Abi :: ScalarPair (
280293 abi:: Scalar :: Initialized { value : a, .. } ,
281294 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 ) ,
295+ ) => Some ( ( a, b) ) ,
296+ Abi :: ScalarPair ( a, b) if force => Some ( ( a. primitive ( ) , b. primitive ( ) ) ) ,
297+ _ => None ,
298+ } ;
299+ if let Some ( ( a, b) ) = scalar_pair_layout {
300+ // We checked `ptr_align` above, so all fields will have the alignment they need.
301+ // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
302+ // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
303+ let ( a_size, b_size) = ( a. size ( self ) , b. size ( self ) ) ;
304+ let b_offset = a_size. align_to ( b. align ( self ) . abi ) ;
305+ assert ! ( b_offset. bytes( ) > 0 ) ; // we later use the offset to tell apart the fields
306+ let a_val = alloc. read_scalar ( alloc_range ( Size :: ZERO , a_size) ) ?;
307+ let b_val = alloc. read_scalar ( alloc_range ( b_offset, b_size) ) ?;
308+ return Ok ( Some ( ImmTy {
309+ imm : Immediate :: ScalarPair ( a_val, b_val) ,
310+ layout : mplace. layout ,
311+ } ) ) ;
294312 }
313+ // Neither a scalar nor scalar pair.
314+ return Ok ( None ) ;
295315 }
296316
297- /// Try returning an immediate for the operand.
298- /// If the layout does not permit loading this as an immediate, return where in memory
299- /// we can find the data.
317+ /// Try returning an immediate for the operand. If the layout does not permit loading this as an
318+ /// immediate, return where in memory we can find the data.
300319 /// Note that for a given layout, this operation will either always fail or always
301320 /// succeed! Whether it succeeds depends on whether the layout can be represented
302321 /// in an `Immediate`, not on which data is stored there currently.
303- pub fn try_read_immediate (
322+ ///
323+ /// If `force` is `true`, then even scalars with fields that can be ununit will be
324+ /// read. This means the load is lossy and should not be written back!
325+ /// This flag exists only for validity checking.
326+ ///
327+ /// This is an internal function that should not usually be used; call `read_immediate` instead.
328+ pub fn read_immediate_raw (
304329 & self ,
305330 src : & OpTy < ' tcx , M :: PointerTag > ,
331+ force : bool ,
306332 ) -> InterpResult < ' tcx , Result < ImmTy < ' tcx , M :: PointerTag > , MPlaceTy < ' tcx , M :: PointerTag > > > {
307333 Ok ( match src. try_as_mplace ( ) {
308334 Ok ( ref mplace) => {
309- if let Some ( val) = self . try_read_immediate_from_mplace ( mplace) ? {
335+ if let Some ( val) = self . read_immediate_from_mplace_raw ( mplace, force ) ? {
310336 Ok ( val)
311337 } else {
312338 Err ( * mplace)
@@ -322,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322348 & self ,
323349 op : & OpTy < ' tcx , M :: PointerTag > ,
324350 ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
325- if let Ok ( imm) = self . try_read_immediate ( op) ? {
351+ if let Ok ( imm) = self . read_immediate_raw ( op, /*force*/ false ) ? {
326352 Ok ( imm)
327353 } else {
328354 span_bug ! ( self . cur_span( ) , "primitive read failed for type: {:?}" , op. layout. ty) ;
0 commit comments