@@ -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