1
Fork 0

Rollup merge of #108208 - cjgillot:flood-enum, r=oli-obk

Correctly handle aggregates in DataflowConstProp

The previous implementation from https://github.com/rust-lang/rust/pull/107411 flooded target of an aggregate assignment with `Bottom`, corresponding to the `deinit` that the interpreter does.

As a consequence, when assigning `target = Enum::Variant#i(...)` all the `(target as Variant#j)` were at `Bottom` while they should have been `Top`.

This PR replaces that flooding with `Top`.

Aside, it corrects a second bug where the wrong place would be used to assign to enum variant fields, resulting to nothing happening.

Fixes https://github.com/rust-lang/rust/issues/108166
This commit is contained in:
Matthias Krüger 2023-02-23 06:18:06 +01:00 committed by GitHub
commit a423fa7b46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 9 deletions

View file

@ -122,7 +122,10 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
) {
match rvalue {
Rvalue::Aggregate(kind, operands) => {
state.flood_with(target.as_ref(), self.map(), FlatSet::Bottom);
// If we assign `target = Enum::Variant#0(operand)`,
// we must make sure that all `target as Variant#i` are `Top`.
state.flood(target.as_ref(), self.map());
if let Some(target_idx) = self.map().find(target.as_ref()) {
let (variant_target, variant_index) = match **kind {
AggregateKind::Tuple | AggregateKind::Closure(..) => {
@ -131,18 +134,21 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
AggregateKind::Adt(def_id, variant_index, ..) => {
match self.tcx.def_kind(def_id) {
DefKind::Struct => (Some(target_idx), None),
DefKind::Enum => (Some(target_idx), Some(variant_index)),
DefKind::Enum => (
self.map.apply(target_idx, TrackElem::Variant(variant_index)),
Some(variant_index),
),
_ => (None, None),
}
}
_ => (None, None),
};
if let Some(target) = variant_target {
if let Some(variant_target_idx) = variant_target {
for (field_index, operand) in operands.iter().enumerate() {
if let Some(field) = self
.map()
.apply(target, TrackElem::Field(Field::from_usize(field_index)))
{
if let Some(field) = self.map().apply(
variant_target_idx,
TrackElem::Field(Field::from_usize(field_index)),
) {
let result = self.handle_operand(operand, state);
state.insert_idx(field, result, self.map());
}
@ -151,6 +157,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
if let Some(variant_index) = variant_index
&& let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant)
{
// We are assigning the discriminant as part of an aggregate.
// This discriminant can only alias a variant field's value if the operand
// had an invalid value for that type.
// Using invalid values is UB, so we are allowed to perform the assignment
// without extra flooding.
let enum_ty = target.ty(self.local_decls, self.tcx).ty;
if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) {
state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map);