Rollup merge of #121628 - gurry:121534-ice-asymm-binop, r=oli-obk

Do not const prop unions

Unions can produce values whose types don't match their underlying layout types which can lead to ICEs on eval.

Fixes #121534
This commit is contained in:
Matthias Krüger 2024-02-26 16:06:04 +01:00 committed by GitHub
commit 218be2771d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 14 deletions

View File

@ -585,20 +585,32 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
val.into()
}
Aggregate(ref kind, ref fields) => Value::Aggregate {
fields: fields
.iter()
.map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate))
.collect(),
variant: match **kind {
AggregateKind::Adt(_, variant, _, _, _) => variant,
AggregateKind::Array(_)
| AggregateKind::Tuple
| AggregateKind::Closure(_, _)
| AggregateKind::Coroutine(_, _)
| AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0),
},
},
Aggregate(ref kind, ref fields) => {
// Do not const pop union fields as they can be
// made to produce values that don't match their
// underlying layout's type (see ICE #121534).
// If the last element of the `Adt` tuple
// is `Some` it indicates the ADT is a union
if let AggregateKind::Adt(_, _, _, _, Some(_)) = **kind {
return None;
};
Value::Aggregate {
fields: fields
.iter()
.map(|field| {
self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)
})
.collect(),
variant: match **kind {
AggregateKind::Adt(_, variant, _, _, _) => variant,
AggregateKind::Array(_)
| AggregateKind::Tuple
| AggregateKind::Closure(_, _)
| AggregateKind::Coroutine(_, _)
| AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0),
},
}
}
Repeat(ref op, n) => {
trace!(?op, ?n);

View File

@ -0,0 +1,21 @@
// Regression test for #121534
// Tests that no ICE occurs in KnownPanicsLint when it
// evaluates an operation whose operands have different
// layout types even though they have the same type.
// This situation can be contrived through the use of
// unions as in this test
//@ build-pass
union Union {
u32_field: u32,
i32_field: i32,
}
pub fn main() {
let u32_variant = Union { u32_field: 2 };
let i32_variant = Union { i32_field: 3 };
let a = unsafe { u32_variant.u32_field };
let b = unsafe { i32_variant.u32_field };
let _diff = a - b;
}