Skip to content

Commit 7d44887

Browse files
committed
Invalid dereferences for all non-local mutations
1 parent 4e05d85 commit 7d44887

8 files changed

+75
-36
lines changed

compiler/rustc_mir_transform/src/gvn.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -1728,12 +1728,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17281728
self.tcx
17291729
}
17301730

1731-
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
1731+
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
17321732
self.simplify_place_projection(place, location);
1733+
if context.is_mutating_use() && !place.projection.is_empty() {
1734+
// Non-local mutation maybe invalidate deref.
1735+
self.invalidate_derefs();
1736+
}
1737+
self.super_place(place, context, location);
17331738
}
17341739

17351740
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
17361741
self.simplify_operand(operand, location);
1742+
self.super_operand(operand, location);
17371743
}
17381744

17391745
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
@@ -1751,22 +1757,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17511757
self.assign(local, value);
17521758
Some(value)
17531759
} else {
1754-
// Non-local assignments maybe invalidate deref.
1755-
self.invalidate_derefs();
17561760
value
17571761
};
1758-
let Some(value) = value else { return };
1759-
1760-
if let Some(const_) = self.try_as_constant(value) {
1761-
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
1762-
} else if let Some(local) = self.try_as_local(value, location)
1763-
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
1764-
{
1765-
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
1766-
self.reused_locals.insert(local);
1762+
if let Some(value) = value {
1763+
if let Some(const_) = self.try_as_constant(value) {
1764+
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
1765+
} else if let Some(local) = self.try_as_local(value, location)
1766+
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
1767+
{
1768+
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
1769+
self.reused_locals.insert(local);
1770+
}
17671771
}
1768-
1769-
return;
17701772
}
17711773
self.super_statement(stmt, location);
17721774
}

tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
StorageLive(_1);
1111
StorageLive(_2);
1212
- _2 = ();
13+
- _1 = Union32 { value: move _2 };
1314
+ _2 = const ();
14-
_1 = Union32 { value: move _2 };
15+
+ _1 = Union32 { value: const () };
1516
StorageDead(_2);
1617
_0 = move _1 as u32 (Transmute);
1718
StorageDead(_1);

tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
StorageLive(_1);
1111
StorageLive(_2);
1212
- _2 = ();
13+
- _1 = Union32 { value: move _2 };
1314
+ _2 = const ();
14-
_1 = Union32 { value: move _2 };
15+
+ _1 = Union32 { value: const () };
1516
StorageDead(_2);
1617
_0 = move _1 as u32 (Transmute);
1718
StorageDead(_1);

tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff

+3-7
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,21 @@
55
let mut _0: ();
66
let _1: main::Un;
77
let mut _2: u32;
8-
let mut _3: u32;
98
scope 1 {
109
debug un => _1;
1110
scope 3 (inlined std::mem::drop::<u32>) {
12-
debug _x => _3;
11+
debug _x => _2;
1312
}
1413
}
1514
scope 2 (inlined val) {
1615
}
1716

1817
bb0: {
1918
StorageLive(_1);
20-
StorageLive(_2);
21-
nop;
2219
_1 = Un { us: const 1_u32 };
20+
StorageLive(_2);
21+
_2 = copy (_1.0: u32);
2322
StorageDead(_2);
24-
StorageLive(_3);
25-
_3 = copy (_1.0: u32);
26-
StorageDead(_3);
2723
StorageDead(_1);
2824
return;
2925
}

tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff

+3-7
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,21 @@
55
let mut _0: ();
66
let _1: main::Un;
77
let mut _2: u32;
8-
let mut _3: u32;
98
scope 1 {
109
debug un => _1;
1110
scope 3 (inlined std::mem::drop::<u32>) {
12-
debug _x => _3;
11+
debug _x => _2;
1312
}
1413
}
1514
scope 2 (inlined val) {
1615
}
1716

1817
bb0: {
1918
StorageLive(_1);
20-
StorageLive(_2);
21-
nop;
2219
_1 = Un { us: const 1_u32 };
20+
StorageLive(_2);
21+
_2 = copy (_1.0: u32);
2322
StorageDead(_2);
24-
StorageLive(_3);
25-
_3 = copy (_1.0: u32);
26-
StorageDead(_3);
2723
StorageDead(_1);
2824
return;
2925
}

tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
StorageLive(_2);
2121
StorageLive(_3);
2222
_3 = &(*_1);
23-
_2 = get(move _3) -> [return: bb1, unwind unreachable];
23+
_2 = get::<Option<i32>>(move _3) -> [return: bb1, unwind unreachable];
2424
}
2525

2626
bb1: {

tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
#![crate_type = "lib"]
1010
//@ test-mir-pass: GVN
1111
#![allow(internal_features)]
12-
#![feature(rustc_attrs, core_intrinsics)]
12+
#![feature(core_intrinsics, custom_mir, rustc_attrs)]
13+
14+
use std::intrinsics::mir::*;
1315

1416
// EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
15-
#[no_mangle]
1617
fn foo(v: &mut Option<i32>) -> Option<i32> {
1718
// CHECK-LABEL: fn foo(
1819
// CHECK-SAME: [[v:_.*]]: &mut Option<i32>
1920
// CHECK: [[v_alias_1:_.*]] = &(*_1)
20-
// CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]])
21+
// CHECK-NEXT: [[v_alias_2:_.*]] = get::<Option<i32>>(move [[v_alias_1]])
2122
// CHECK: (*[[v]]) = const Option::<i32>::None;
2223
// CHECK-NOT: _0 = copy (*[[v_alias_2]])
2324
// CHECK: _0 = Option::<i32>::Some
@@ -30,9 +31,31 @@ fn foo(v: &mut Option<i32>) -> Option<i32> {
3031
}
3132
}
3233

33-
#[no_mangle]
34+
pub enum Value {
35+
V0(i32),
36+
V1(i32),
37+
}
38+
39+
// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
40+
#[custom_mir(dialect = "runtime", phase = "initial")]
41+
fn set_discriminant(v: &mut Value) -> Value {
42+
// CHECK-LABEL: fn set_discriminant(
43+
mir! {
44+
let v_: &Value;
45+
{
46+
Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable())
47+
}
48+
ret = {
49+
let col: i32 = Field(Variant(*v_, 0), 0);
50+
SetDiscriminant(*v, 1);
51+
RET = Value::V0(col);
52+
Return()
53+
}
54+
}
55+
}
56+
3457
#[inline(never)]
3558
#[rustc_nounwind]
36-
fn get(v: &Option<i32>) -> &Option<i32> {
59+
fn get<T>(v: &T) -> &T {
3760
v
3861
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
- // MIR for `set_discriminant` before GVN
2+
+ // MIR for `set_discriminant` after GVN
3+
4+
fn set_discriminant(_1: &mut Value) -> Value {
5+
let mut _0: Value;
6+
let mut _2: &Value;
7+
let mut _3: i32;
8+
9+
bb0: {
10+
_2 = get::<Value>(copy _1) -> [return: bb1, unwind unreachable];
11+
}
12+
13+
bb1: {
14+
_3 = copy (((*_2) as variant#0).0: i32);
15+
discriminant((*_1)) = 1;
16+
_0 = Value::V0(copy _3);
17+
return;
18+
}
19+
}
20+

0 commit comments

Comments
 (0)