Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,12 @@ impl<'tcx> Map<'tcx> {
};
let elems = place.projection.iter().map(|&elem| elem.try_into()).chain(tail_elem.map(Ok));
for elem in elems {
// All fields of a union alias each other.
if self.places[index].ty.is_union() {
self.for_each_value_inside(index, f);
return;
}

// A field aliases the parent place.
if let Some(vi) = self.places[index].value_index {
f(vi);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp

fn main() -> () {
let mut _0: ();
let mut _1: U;
scope 1 {
debug u => _1;
let _2: u8;
scope 2 {
debug a => _2;
}
}

bb0: {
StorageLive(_1);
_1 = U { a: const 0_u8 };
(_1.0: u8) = const 1_u8;
(_1.1: u8) = const 5_u8;
StorageLive(_2);
_2 = copy (_1.0: u8);
_0 = const ();
StorageDead(_2);
StorageDead(_1);
return;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp

fn main() -> () {
let mut _0: ();
let mut _1: U;
scope 1 {
debug u => _1;
let _2: u8;
scope 2 {
debug a => _2;
}
}

bb0: {
StorageLive(_1);
_1 = U { a: const 0_u8 };
(_1.0: u8) = const 1_u8;
(_1.1: u8) = const 5_u8;
StorageLive(_2);
_2 = copy (_1.0: u8);
_0 = const ();
StorageDead(_2);
StorageDead(_1);
return;
}
}

24 changes: 24 additions & 0 deletions tests/mir-opt/dataflow-const-prop/union_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// Writing to one union field must also invalidate what is known about the other fields,
// since they share the same storage.

//@ test-mir-pass: DataflowConstProp

// EMIT_MIR union_field.main.DataflowConstProp.diff

union U {
a: u8,
b: u8,
}

// CHECK-LABEL: fn main(
fn main() {
// CHECK: debug a => [[a:_.*]];

let mut u = U { a: 0 };
u.a = 1;
u.b = 5;

// CHECK: [[a]] = copy ({{_.*}}.0: u8);
let a = unsafe { u.a }; // should not be propagated
}
30 changes: 30 additions & 0 deletions tests/mir-opt/jump_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,34 @@ fn chained_conditions() -> u8 {
}
}

union U {
a: u8,
b: u8,
}

fn union_field(x: u8) -> u8 {
// CHECK-LABEL: fn union_field(
// CHECK: ({{_.*}}.1: u8) = const 5_u8;
// CHECK-NOT: ({{_.*}}.1: u8) = const 5_u8;

// Test for #161898, where the write to `u.b` did not invalidate what was known about `u.a`.
let mut u = U { a: x };
let r = unsafe {
match u.a {
0 => 100,
_ => 200,
}
};
u.b = 5;
let r2 = unsafe {
match u.a {
0 => 1,
_ => 2,
}
};
r + r2
}

fn main() {
// CHECK-LABEL: fn main(
too_complex(Ok(0));
Expand All @@ -673,6 +701,7 @@ fn main() {
floats();
bitwise_not();
logical_not();
union_field(0);
}

// EMIT_MIR jump_threading.too_complex.JumpThreading.diff
Expand All @@ -693,3 +722,4 @@ fn main() {
// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff
// EMIT_MIR jump_threading.logical_not.JumpThreading.diff
// EMIT_MIR jump_threading.chained_conditions.JumpThreading.diff
// EMIT_MIR jump_threading.union_field.JumpThreading.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
- // MIR for `union_field` before JumpThreading
+ // MIR for `union_field` after JumpThreading

fn union_field(_1: u8) -> u8 {
debug x => _1;
let mut _0: u8;
let mut _2: U;
let mut _3: u8;
let mut _6: u8;
let mut _7: u8;
scope 1 {
debug u => _2;
let _4: u8;
scope 2 {
debug r => _4;
let _5: u8;
scope 3 {
debug r2 => _5;
}
}
}

bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = copy _1;
_2 = U { a: move _3 };
StorageDead(_3);
StorageLive(_4);
switchInt(copy (_2.0: u8)) -> [0: bb2, otherwise: bb1];
}

bb1: {
_4 = const 200_u8;
goto -> bb3;
}

bb2: {
_4 = const 100_u8;
goto -> bb3;
}

bb3: {
(_2.1: u8) = const 5_u8;
StorageLive(_5);
switchInt(copy (_2.0: u8)) -> [0: bb5, otherwise: bb4];
}

bb4: {
_5 = const 2_u8;
goto -> bb6;
}

bb5: {
_5 = const 1_u8;
goto -> bb6;
}

bb6: {
StorageLive(_6);
_6 = copy _4;
StorageLive(_7);
_7 = copy _5;
_0 = Add(move _6, move _7);
StorageDead(_7);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
StorageDead(_2);
return;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
- // MIR for `union_field` before JumpThreading
+ // MIR for `union_field` after JumpThreading

fn union_field(_1: u8) -> u8 {
debug x => _1;
let mut _0: u8;
let mut _2: U;
let mut _3: u8;
let mut _6: u8;
let mut _7: u8;
scope 1 {
debug u => _2;
let _4: u8;
scope 2 {
debug r => _4;
let _5: u8;
scope 3 {
debug r2 => _5;
}
}
}

bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = copy _1;
_2 = U { a: move _3 };
StorageDead(_3);
StorageLive(_4);
switchInt(copy (_2.0: u8)) -> [0: bb2, otherwise: bb1];
}

bb1: {
_4 = const 200_u8;
goto -> bb3;
}

bb2: {
_4 = const 100_u8;
goto -> bb3;
}

bb3: {
(_2.1: u8) = const 5_u8;
StorageLive(_5);
switchInt(copy (_2.0: u8)) -> [0: bb5, otherwise: bb4];
}

bb4: {
_5 = const 2_u8;
goto -> bb6;
}

bb5: {
_5 = const 1_u8;
goto -> bb6;
}

bb6: {
StorageLive(_6);
_6 = copy _4;
StorageLive(_7);
_7 = copy _5;
_0 = Add(move _6, move _7);
StorageDead(_7);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
StorageDead(_2);
return;
}
}

Loading