Do not const pop unions

as they can made to produce values whose types don't
match their underlying layout types which can lead to
ICEs on eval
This commit is contained in:
Gurinder Singh 2024-02-26 15:22:22 +05:30
parent 0250ef2571
commit 633c92cd6d
2 changed files with 47 additions and 14 deletions

View File

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