Auto merge of #143509 - cjgillot:copy-prop-noborrow, r=tmiasko

Do not unify borrowed locals in CopyProp.

Instead of trying yet another scheme to unify borrowed locals in CopyProp, let's just stop trying. We had already enough miscompilations because of this.

I'm convinced it's possible to have both unification of some borrowed locals and soundness, but I don't have a simple and convincing formulation yet.

Fixes https://github.com/rust-lang/rust/issues/143491
This commit is contained in:
bors
2025-07-06 19:58:07 +00:00
15 changed files with 832 additions and 283 deletions
+2 -2
View File
@@ -322,8 +322,8 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
// visited before `local`, and we just have to copy the representing local.
let head = copies[rhs];
// Do not unify two borrowed locals.
if borrowed_classes.contains(local) && borrowed_classes.contains(head) {
// Do not unify borrowed locals.
if borrowed_classes.contains(local) || borrowed_classes.contains(head) {
continue;
}
@@ -0,0 +1,101 @@
- // MIR for `borrow_in_loop` before CopyProp
+ // MIR for `borrow_in_loop` after CopyProp
fn borrow_in_loop() -> () {
let mut _0: ();
let mut _1: bool;
let _3: bool;
let mut _4: !;
let mut _5: ();
let mut _7: bool;
let mut _9: bool;
let mut _10: bool;
let mut _11: &bool;
let _12: &bool;
let mut _13: bool;
let mut _14: bool;
let mut _15: bool;
let mut _16: !;
scope 1 {
debug c => _1;
let mut _2: &bool;
let mut _17: &bool;
scope 2 {
debug p => _2;
let _6: bool;
scope 3 {
debug a => _6;
let _8: bool;
scope 4 {
debug b => _8;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_17 = const borrow_in_loop::promoted[0];
_2 = &(*_17);
- StorageLive(_4);
goto -> bb1;
}
bb1: {
- StorageLive(_6);
StorageLive(_7);
_7 = copy (*_2);
_6 = Not(move _7);
StorageDead(_7);
- StorageLive(_8);
StorageLive(_9);
_9 = copy (*_2);
_8 = Not(move _9);
StorageDead(_9);
- StorageLive(_10);
- _10 = copy _6;
- _1 = move _10;
- StorageDead(_10);
+ _1 = copy _6;
StorageLive(_11);
StorageLive(_12);
_12 = &_1;
_11 = &(*_12);
_2 = move _11;
StorageDead(_11);
StorageDead(_12);
StorageLive(_13);
- StorageLive(_14);
- _14 = copy _6;
- StorageLive(_15);
- _15 = copy _8;
- _13 = Ne(move _14, move _15);
+ _13 = Ne(copy _6, copy _8);
switchInt(move _13) -> [0: bb3, otherwise: bb2];
}
bb2: {
- StorageDead(_15);
- StorageDead(_14);
_0 = const ();
StorageDead(_13);
- StorageDead(_8);
- StorageDead(_6);
- StorageDead(_4);
StorageDead(_2);
StorageDead(_1);
return;
}
bb3: {
- StorageDead(_15);
- StorageDead(_14);
- _5 = const ();
StorageDead(_13);
- StorageDead(_8);
- StorageDead(_6);
goto -> bb1;
}
}
@@ -0,0 +1,101 @@
- // MIR for `borrow_in_loop` before CopyProp
+ // MIR for `borrow_in_loop` after CopyProp
fn borrow_in_loop() -> () {
let mut _0: ();
let mut _1: bool;
let _3: bool;
let mut _4: !;
let mut _5: ();
let mut _7: bool;
let mut _9: bool;
let mut _10: bool;
let mut _11: &bool;
let _12: &bool;
let mut _13: bool;
let mut _14: bool;
let mut _15: bool;
let mut _16: !;
scope 1 {
debug c => _1;
let mut _2: &bool;
let mut _17: &bool;
scope 2 {
debug p => _2;
let _6: bool;
scope 3 {
debug a => _6;
let _8: bool;
scope 4 {
debug b => _8;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_17 = const borrow_in_loop::promoted[0];
_2 = &(*_17);
- StorageLive(_4);
goto -> bb1;
}
bb1: {
- StorageLive(_6);
StorageLive(_7);
_7 = copy (*_2);
_6 = Not(move _7);
StorageDead(_7);
- StorageLive(_8);
StorageLive(_9);
_9 = copy (*_2);
_8 = Not(move _9);
StorageDead(_9);
- StorageLive(_10);
- _10 = copy _6;
- _1 = move _10;
- StorageDead(_10);
+ _1 = copy _6;
StorageLive(_11);
StorageLive(_12);
_12 = &_1;
_11 = &(*_12);
_2 = move _11;
StorageDead(_11);
StorageDead(_12);
StorageLive(_13);
- StorageLive(_14);
- _14 = copy _6;
- StorageLive(_15);
- _15 = copy _8;
- _13 = Ne(move _14, move _15);
+ _13 = Ne(copy _6, copy _8);
switchInt(move _13) -> [0: bb3, otherwise: bb2];
}
bb2: {
- StorageDead(_15);
- StorageDead(_14);
_0 = const ();
StorageDead(_13);
- StorageDead(_8);
- StorageDead(_6);
- StorageDead(_4);
StorageDead(_2);
StorageDead(_1);
return;
}
bb3: {
- StorageDead(_15);
- StorageDead(_14);
- _5 = const ();
StorageDead(_13);
- StorageDead(_8);
- StorageDead(_6);
goto -> bb1;
}
}
@@ -7,14 +7,13 @@
let mut _3: &T;
bb0: {
- _2 = copy _1;
_2 = copy _1;
_3 = &_1;
_0 = opaque::<&T>(copy _3) -> [return: bb1, unwind unreachable];
}
bb1: {
- _0 = opaque::<T>(copy _2) -> [return: bb2, unwind unreachable];
+ _0 = opaque::<T>(copy _1) -> [return: bb2, unwind unreachable];
_0 = opaque::<T>(copy _2) -> [return: bb2, unwind unreachable];
}
bb2: {
@@ -7,14 +7,13 @@
let mut _3: &T;
bb0: {
- _2 = copy _1;
_2 = copy _1;
_3 = &_1;
_0 = opaque::<&T>(copy _3) -> [return: bb1, unwind continue];
}
bb1: {
- _0 = opaque::<T>(copy _2) -> [return: bb2, unwind continue];
+ _0 = opaque::<T>(copy _1) -> [return: bb2, unwind continue];
_0 = opaque::<T>(copy _2) -> [return: bb2, unwind continue];
}
bb2: {
+36 -1
View File
@@ -50,10 +50,11 @@ fn compare_address() -> bool {
fn borrowed<T: Copy + Freeze>(x: T) -> bool {
// CHECK-LABEL: fn borrowed(
// CHECK: bb0: {
// CHECK-NEXT: _2 = copy _1;
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(copy _3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
// CHECK-NEXT: _0 = opaque::<T>(copy _2)
mir! {
{
let a = x;
@@ -94,11 +95,45 @@ fn non_freeze<T: Copy>(x: T) -> bool {
}
}
/// We must not unify a borrowed local with another that may be written-to before the borrow is
/// read again. As we have no aliasing model yet, this means forbidding unifying borrowed locals.
fn borrow_in_loop() {
// CHECK-LABEL: fn borrow_in_loop(
// CHECK: debug c => [[c:_.*]];
// CHECK: debug p => [[p:_.*]];
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
// CHECK-NOT: &[[a]]
// CHECK-NOT: &[[b]]
// CHECK: [[a]] = Not({{.*}});
// CHECK-NOT: &[[a]]
// CHECK-NOT: &[[b]]
// CHECK: [[b]] = Not({{.*}});
// CHECK-NOT: &[[a]]
// CHECK-NOT: &[[b]]
// CHECK: &[[c]]
// CHECK-NOT: &[[a]]
// CHECK-NOT: &[[b]]
let mut c;
let mut p = &false;
loop {
let a = !*p;
let b = !*p;
c = a;
p = &c;
if a != b {
return;
}
}
}
fn main() {
assert!(!compare_address());
non_freeze(5);
borrow_in_loop();
}
// EMIT_MIR borrowed_local.compare_address.CopyProp.diff
// EMIT_MIR borrowed_local.borrowed.CopyProp.diff
// EMIT_MIR borrowed_local.non_freeze.CopyProp.diff
// EMIT_MIR borrowed_local.borrow_in_loop.CopyProp.diff
@@ -16,11 +16,10 @@
_3 = const 'b';
_5 = copy _3;
_6 = &_3;
- _4 = copy _5;
_4 = copy _5;
(*_1) = copy (*_6);
_6 = &_5;
- _7 = dump_var::<char>(copy _4) -> [return: bb1, unwind unreachable];
+ _7 = dump_var::<char>(copy _5) -> [return: bb1, unwind unreachable];
_7 = dump_var::<char>(copy _4) -> [return: bb1, unwind unreachable];
}
bb1: {
+2 -2
View File
@@ -27,13 +27,13 @@ fn main() {
_5 = _3;
// CHECK-NEXT: _6 = &_3;
_6 = &_3;
// CHECK-NOT: {{_.*}} = {{_.*}};
// CHECK-NEXT: _4 = copy _5;
_4 = _5;
// CHECK-NEXT: (*_1) = copy (*_6);
*_1 = *_6;
// CHECK-NEXT: _6 = &_5;
_6 = &_5;
// CHECK-NEXT: _7 = dump_var::<char>(copy _5)
// CHECK-NEXT: _7 = dump_var::<char>(copy _4)
Call(_7 = dump_var(_4), ReturnTo(bb1), UnwindUnreachable())
}
bb1 = { Return() }
@@ -10,18 +10,18 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
let mut _8: &&usize;
let _9: &usize;
let mut _10: &&usize;
let mut _13: bool;
let mut _14: &&usize;
let _15: &usize;
let mut _15: bool;
let mut _16: &&usize;
let mut _19: bool;
let mut _20: &&usize;
let _21: &usize;
let mut _22: &&usize;
let _17: &usize;
let mut _18: &&usize;
let mut _23: bool;
let mut _24: &&usize;
let _25: &usize;
let mut _26: &&usize;
let mut _29: bool;
let mut _30: &&usize;
let _31: &usize;
let mut _32: &&usize;
scope 1 {
debug a => _4;
debug b => _5;
@@ -30,39 +30,47 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _8;
debug other => _10;
let mut _11: &usize;
let mut _12: &usize;
scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _4;
debug other => _6;
let mut _11: usize;
let mut _12: usize;
debug self => _11;
debug other => _12;
let mut _13: usize;
let mut _14: usize;
}
}
scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _14;
debug other => _16;
debug self => _16;
debug other => _18;
let mut _19: &usize;
let mut _20: &usize;
scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _7;
debug other => _5;
let mut _17: usize;
let mut _18: usize;
debug self => _19;
debug other => _20;
let mut _21: usize;
let mut _22: usize;
}
}
scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _20;
debug other => _22;
debug self => _24;
debug other => _26;
let mut _27: &usize;
let mut _28: &usize;
scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _6;
debug other => _4;
debug self => _27;
debug other => _28;
}
}
scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _24;
debug other => _26;
debug self => _30;
debug other => _32;
let mut _33: &usize;
let mut _34: &usize;
scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _5;
debug other => _7;
let mut _27: usize;
let mut _28: usize;
debug self => _33;
debug other => _34;
let mut _35: usize;
let mut _36: usize;
}
}
}
@@ -73,17 +81,23 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
_5 = &((*_3).1: usize);
_6 = &((*_3).2: usize);
_7 = &((*_3).3: usize);
StorageLive(_13);
StorageLive(_15);
StorageLive(_8);
_8 = &_4;
StorageLive(_10);
StorageLive(_9);
_9 = copy _6;
_10 = &_9;
_11 = copy ((*_3).0: usize);
_12 = copy ((*_3).2: usize);
_13 = Le(copy _11, copy _12);
switchInt(move _13) -> [0: bb1, otherwise: bb2];
StorageLive(_11);
StorageLive(_12);
_11 = copy _4;
_12 = copy _6;
_13 = copy ((*_3).0: usize);
_14 = copy ((*_3).2: usize);
_15 = Le(copy _13, copy _14);
StorageDead(_12);
StorageDead(_11);
switchInt(move _15) -> [0: bb1, otherwise: bb2];
}
bb1: {
@@ -97,89 +111,107 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
StorageDead(_9);
StorageDead(_10);
StorageDead(_8);
StorageLive(_19);
StorageLive(_14);
_14 = &_7;
StorageLive(_23);
StorageLive(_16);
StorageLive(_15);
_15 = copy _5;
_16 = &_15;
StorageLive(_17);
_17 = copy ((*_3).3: usize);
_16 = &_7;
StorageLive(_18);
_18 = copy ((*_3).1: usize);
_19 = Le(move _17, move _18);
StorageDead(_18);
StorageDead(_17);
switchInt(move _19) -> [0: bb3, otherwise: bb8];
StorageLive(_17);
_17 = copy _5;
_18 = &_17;
StorageLive(_19);
StorageLive(_20);
_19 = copy _7;
_20 = copy _5;
StorageLive(_21);
_21 = copy ((*_3).3: usize);
StorageLive(_22);
_22 = copy ((*_3).1: usize);
_23 = Le(move _21, move _22);
StorageDead(_22);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
switchInt(move _23) -> [0: bb3, otherwise: bb8];
}
bb3: {
StorageDead(_15);
StorageDead(_17);
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
goto -> bb4;
}
bb4: {
StorageLive(_23);
StorageLive(_20);
_20 = &_6;
StorageLive(_22);
StorageLive(_21);
_21 = copy _4;
_22 = &_21;
_23 = Le(copy _12, copy _11);
switchInt(move _23) -> [0: bb5, otherwise: bb6];
StorageLive(_29);
StorageLive(_24);
_24 = &_6;
StorageLive(_26);
StorageLive(_25);
_25 = copy _4;
_26 = &_25;
StorageLive(_27);
StorageLive(_28);
_27 = copy _6;
_28 = copy _4;
_29 = Le(copy _14, copy _13);
StorageDead(_28);
StorageDead(_27);
switchInt(move _29) -> [0: bb5, otherwise: bb6];
}
bb5: {
StorageDead(_21);
StorageDead(_22);
StorageDead(_20);
StorageDead(_25);
StorageDead(_26);
StorageDead(_24);
_0 = const false;
goto -> bb7;
}
bb6: {
StorageDead(_21);
StorageDead(_22);
StorageDead(_20);
StorageLive(_24);
_24 = &_5;
StorageLive(_26);
StorageLive(_25);
_25 = copy _7;
_26 = &_25;
StorageLive(_27);
_27 = copy ((*_3).1: usize);
StorageLive(_28);
_28 = copy ((*_3).3: usize);
_0 = Le(move _27, move _28);
StorageDead(_28);
StorageDead(_27);
StorageDead(_25);
StorageDead(_26);
StorageDead(_24);
StorageLive(_30);
_30 = &_5;
StorageLive(_32);
StorageLive(_31);
_31 = copy _7;
_32 = &_31;
StorageLive(_33);
StorageLive(_34);
_33 = copy _5;
_34 = copy _7;
StorageLive(_35);
_35 = copy ((*_3).1: usize);
StorageLive(_36);
_36 = copy ((*_3).3: usize);
_0 = Le(move _35, move _36);
StorageDead(_36);
StorageDead(_35);
StorageDead(_34);
StorageDead(_33);
StorageDead(_31);
StorageDead(_32);
StorageDead(_30);
goto -> bb7;
}
bb7: {
StorageDead(_23);
StorageDead(_29);
goto -> bb9;
}
bb8: {
StorageDead(_15);
StorageDead(_17);
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
_0 = const true;
goto -> bb9;
}
bb9: {
StorageDead(_19);
StorageDead(_13);
StorageDead(_23);
StorageDead(_15);
return;
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0
//@ check-pass
//@ only-x86_64
//@ edition: 2024
+49 -26
View File
@@ -8,19 +8,30 @@ fn foo() -> () {
debug y => _1;
debug x => _2;
bb0: {
StorageLive(_1);
_1 = 0_i32;
StorageLive(_2);
StorageLive(_3);
_3 = &_1;
_2 = {coroutine-closure@$DIR/async-closure.rs:9:13: 9:21}(move _3);
StorageDead(_3);
_0 = ();
StorageDead(_2);
StorageDead(_1);
return;
}
}
fn foo::{closure#0}(_1: &{async closure@$DIR/async-closure.rs:9:13: 9:21}) -> {async closure body@$DIR/async-closure.rs:9:22: 11:6} {
let mut _0: {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _2: &i32;
let mut _3: &i32;
debug y => (*((*_1).0: &i32));
bb0: {
_2 = CopyForDeref(((*_1).0: &i32));
_0 = {coroutine@$DIR/async-closure.rs:9:22: 11:6}(_2);
StorageLive(_2);
_3 = CopyForDeref(((*_1).0: &i32));
_2 = &(*_3);
_0 = {coroutine@$DIR/async-closure.rs:9:22: 11:6}(move _2);
StorageDead(_2);
return;
}
}
@@ -28,25 +39,31 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
let mut _0: Poll<()>;
let _3: i32;
let mut _4: &i32;
let mut _5: u32;
let mut _6: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _5: ();
let mut _6: &mut Context<'_>;
let mut _7: u32;
let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _2;
let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _6;
debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
debug y => _3;
bb0: {
_6 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_5 = discriminant((*_6));
switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3];
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_7 = discriminant((*_8));
switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
_7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_7).0: &i32));
_6 = move _2;
StorageLive(_3);
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_9).0: &i32));
_3 = (*_4);
_0 = std::task::Poll::Ready(());
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_8) = 1;
_5 = ();
StorageDead(_3);
_0 = std::task::Poll::Ready(move _5);
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_10) = 1;
return;
}
bb2: {
@@ -60,25 +77,31 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
let mut _0: Poll<()>;
let _3: i32;
let mut _4: &i32;
let mut _5: u32;
let mut _6: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _5: ();
let mut _6: &mut Context<'_>;
let mut _7: u32;
let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _2;
let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _6;
debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
debug y => _3;
bb0: {
_6 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_5 = discriminant((*_6));
switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3];
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_7 = discriminant((*_8));
switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
_7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_7).0: &i32));
_6 = move _2;
StorageLive(_3);
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_9).0: &i32));
_3 = (*_4);
_0 = std::task::Poll::Ready(());
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_8) = 1;
_5 = ();
StorageDead(_3);
_0 = std::task::Poll::Ready(move _5);
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_10) = 1;
return;
}
bb2: {
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Z unpretty=stable-mir -Z mir-opt-level=3
//@ compile-flags: -Z unpretty=stable-mir -Zmir-opt-level=0
//@ check-pass
//@ only-x86_64
//@ needs-unwind unwind edges are different with panic=abort
@@ -2,14 +2,18 @@
// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir.
fn foo(_1: i32) -> i32 {
let mut _0: i32;
let mut _2: (i32, bool);
let mut _2: i32;
let mut _3: (i32, bool);
debug i => _1;
bb0: {
_2 = CheckedAdd(_1, 1_i32);
assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, 1_i32) -> [success: bb1, unwind continue];
StorageLive(_2);
_2 = _1;
_3 = CheckedAdd(_2, 1_i32);
assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, 1_i32) -> [success: bb1, unwind continue];
}
bb1: {
_0 = move (_2.0: i32);
_0 = move (_3.0: i32);
StorageDead(_2);
return;
}
}
@@ -22,15 +26,23 @@ fn bar(_1: &mut Vec<i32>) -> Vec<i32> {
debug vec => _1;
debug new_vec => _2;
bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = &(*_1);
_2 = <Vec<i32> as Clone>::clone(move _3) -> [return: bb1, unwind continue];
}
bb1: {
StorageDead(_3);
StorageLive(_4);
StorageLive(_5);
_5 = &mut _2;
_4 = Vec::<i32>::push(move _5, 1_i32) -> [return: bb2, unwind: bb3];
}
bb2: {
StorageDead(_5);
StorageDead(_4);
_0 = move _2;
StorageDead(_2);
return;
}
bb3: {
@@ -69,6 +81,7 @@ fn demux(_1: u8) -> u8 {
fn main() -> () {
let mut _0: ();
bb0: {
_0 = ();
return;
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0
//@ check-pass
//@ only-x86_64
//@ needs-unwind unwind edges are different with panic=abort
+403 -156
View File
@@ -3,185 +3,398 @@
fn operands(_1: u8) -> () {
let mut _0: ();
let _2: [u8; 10];
let _3: u8;
let _4: usize;
let mut _5: bool;
let _6: u8;
let _7: usize;
let mut _8: (usize, bool);
let mut _9: bool;
let mut _10: (&u8, &u8);
let mut _11: &u8;
let mut _12: &u8;
let _13: &u8;
let _14: &u8;
let mut _15: bool;
let mut _16: u8;
let mut _17: u8;
let _18: core::panicking::AssertKind;
let _19: !;
let mut _20: Option<Arguments<'_>>;
let _21: &u8;
let _22: u8;
let mut _23: (&u8, &u8);
let mut _3: u8;
let _4: u8;
let _5: usize;
let mut _6: bool;
let _7: u8;
let _8: usize;
let mut _9: (usize, bool);
let mut _10: bool;
let _11: ();
let mut _12: (&u8, &u8);
let mut _13: &u8;
let mut _14: &u8;
let _15: &u8;
let _16: &u8;
let mut _17: bool;
let mut _18: u8;
let mut _19: u8;
let mut _20: !;
let _21: core::panicking::AssertKind;
let _22: !;
let mut _23: core::panicking::AssertKind;
let mut _24: &u8;
let mut _25: &u8;
let _26: &u8;
let _25: &u8;
let mut _26: &u8;
let _27: &u8;
let mut _28: bool;
let mut _29: u8;
let mut _30: u8;
let _31: core::panicking::AssertKind;
let _32: !;
let mut _33: Option<Arguments<'_>>;
let _34: (u8, u8);
let _35: u8;
let _36: u8;
let mut _37: (&u8, &u8);
let mut _38: &u8;
let mut _39: &u8;
let _40: &u8;
let _41: &u8;
let mut _42: bool;
let mut _43: u8;
let mut _44: u8;
let _45: core::panicking::AssertKind;
let _46: !;
let mut _47: Option<Arguments<'_>>;
let _48: usize;
let mut _49: &[u8];
let mut _50: &[u8; 10];
let _51: usize;
let _52: &usize;
let mut _53: (&usize, &usize);
let mut _54: &usize;
let mut _55: &usize;
let _56: &usize;
let _57: &usize;
let mut _58: bool;
let mut _59: usize;
let mut _60: usize;
let _61: core::panicking::AssertKind;
let _62: !;
let mut _63: Option<Arguments<'_>>;
let mut _28: Option<Arguments<'_>>;
let _29: &u8;
let _30: u8;
let _31: ();
let mut _32: (&u8, &u8);
let mut _33: &u8;
let mut _34: &u8;
let _35: &u8;
let _36: &u8;
let mut _37: bool;
let mut _38: u8;
let mut _39: u8;
let mut _40: !;
let _41: core::panicking::AssertKind;
let _42: !;
let mut _43: core::panicking::AssertKind;
let mut _44: &u8;
let _45: &u8;
let mut _46: &u8;
let _47: &u8;
let mut _48: Option<Arguments<'_>>;
let _49: (u8, u8);
let mut _50: u8;
let mut _51: u8;
let _52: u8;
let _53: u8;
let _54: ();
let mut _55: (&u8, &u8);
let mut _56: &u8;
let mut _57: &u8;
let _58: &u8;
let _59: &u8;
let mut _60: bool;
let mut _61: u8;
let mut _62: u8;
let mut _63: !;
let _64: core::panicking::AssertKind;
let _65: !;
let mut _66: core::panicking::AssertKind;
let mut _67: &u8;
let _68: &u8;
let mut _69: &u8;
let _70: &u8;
let mut _71: Option<Arguments<'_>>;
let _72: usize;
let mut _73: &[u8];
let mut _74: &[u8; 10];
let _75: usize;
let mut _76: &usize;
let _77: &usize;
let _78: ();
let mut _79: (&usize, &usize);
let mut _80: &usize;
let mut _81: &usize;
let _82: &usize;
let _83: &usize;
let mut _84: bool;
let mut _85: usize;
let mut _86: usize;
let mut _87: !;
let _88: core::panicking::AssertKind;
let _89: !;
let mut _90: core::panicking::AssertKind;
let mut _91: &usize;
let _92: &usize;
let mut _93: &usize;
let _94: &usize;
let mut _95: Option<Arguments<'_>>;
debug val => _1;
debug array => _2;
debug first => _3;
debug last => _6;
debug left_val => _13;
debug right_val => _14;
debug kind => _18;
debug reference => _21;
debug dereferenced => _22;
debug left_val => _26;
debug right_val => _27;
debug kind => _31;
debug tuple => _34;
debug first_again => _35;
debug first_again_again => _36;
debug left_val => _40;
debug right_val => _41;
debug kind => _45;
debug length => _48;
debug size_of => _51;
debug left_val => _56;
debug right_val => _57;
debug kind => _61;
debug first => _4;
debug last => _7;
debug left_val => _15;
debug right_val => _16;
debug kind => _21;
debug reference => _29;
debug dereferenced => _30;
debug left_val => _35;
debug right_val => _36;
debug kind => _41;
debug tuple => _49;
debug first_again => _52;
debug first_again_again => _53;
debug left_val => _58;
debug right_val => _59;
debug kind => _64;
debug length => _72;
debug size_of => _75;
debug left_val => _82;
debug right_val => _83;
debug kind => _88;
bb0: {
_2 = [_1; 10];
_4 = 0_usize;
_5 = Lt(_4, 10_usize);
assert(move _5, "index out of bounds: the length is {} but the index is {}", 10_usize, _4) -> [success: bb1, unwind unreachable];
StorageLive(_2);
StorageLive(_3);
_3 = _1;
_2 = [move _3; 10];
StorageDead(_3);
StorageLive(_4);
StorageLive(_5);
_5 = 0_usize;
_6 = Lt(_5, 10_usize);
assert(move _6, "index out of bounds: the length is {} but the index is {}", 10_usize, _5) -> [success: bb1, unwind unreachable];
}
bb1: {
_3 = _2[_4];
_8 = CheckedSub(10_usize, 1_usize);
assert(!move (_8.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable];
_4 = _2[_5];
StorageDead(_5);
StorageLive(_7);
StorageLive(_8);
_9 = CheckedSub(10_usize, 1_usize);
assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable];
}
bb2: {
_7 = move (_8.0: usize);
_9 = Lt(_7, 10_usize);
assert(move _9, "index out of bounds: the length is {} but the index is {}", 10_usize, _7) -> [success: bb3, unwind unreachable];
_8 = move (_9.0: usize);
_10 = Lt(_8, 10_usize);
assert(move _10, "index out of bounds: the length is {} but the index is {}", 10_usize, _8) -> [success: bb3, unwind unreachable];
}
bb3: {
_6 = _2[_7];
_11 = &_3;
_12 = &_6;
_10 = (move _11, move _12);
_13 = (_10.0: &u8);
_14 = (_10.1: &u8);
_16 = (*_13);
_17 = (*_14);
_15 = Eq(move _16, move _17);
switchInt(move _15) -> [0: bb5, otherwise: bb4];
_7 = _2[_8];
StorageDead(_8);
StorageLive(_11);
StorageLive(_12);
StorageLive(_13);
_13 = &_4;
StorageLive(_14);
_14 = &_7;
_12 = (move _13, move _14);
StorageDead(_14);
StorageDead(_13);
StorageLive(_15);
_15 = (_12.0: &u8);
StorageLive(_16);
_16 = (_12.1: &u8);
StorageLive(_17);
StorageLive(_18);
_18 = (*_15);
StorageLive(_19);
_19 = (*_16);
_17 = Eq(move _18, move _19);
switchInt(move _17) -> [0: bb5, otherwise: bb4];
}
bb4: {
_21 = &_3;
_22 = (*_21);
_24 = &_22;
_25 = &_3;
_23 = (move _24, move _25);
_26 = (_23.0: &u8);
_27 = (_23.1: &u8);
_29 = (*_26);
_30 = (*_27);
_28 = Eq(move _29, move _30);
switchInt(move _28) -> [0: bb7, otherwise: bb6];
StorageDead(_19);
StorageDead(_18);
_11 = ();
StorageDead(_17);
StorageDead(_16);
StorageDead(_15);
StorageDead(_12);
StorageDead(_11);
StorageLive(_29);
_29 = &_4;
StorageLive(_30);
_30 = (*_29);
StorageLive(_31);
StorageLive(_32);
StorageLive(_33);
_33 = &_30;
StorageLive(_34);
_34 = &_4;
_32 = (move _33, move _34);
StorageDead(_34);
StorageDead(_33);
StorageLive(_35);
_35 = (_32.0: &u8);
StorageLive(_36);
_36 = (_32.1: &u8);
StorageLive(_37);
StorageLive(_38);
_38 = (*_35);
StorageLive(_39);
_39 = (*_36);
_37 = Eq(move _38, move _39);
switchInt(move _37) -> [0: bb7, otherwise: bb6];
}
bb5: {
_18 = core::panicking::AssertKind::Eq;
_20 = std::option::Option::None;
_19 = core::panicking::assert_failed::<u8, u8>(move _18, _13, _14, move _20) -> unwind unreachable;
StorageDead(_19);
StorageDead(_18);
StorageLive(_21);
_21 = core::panicking::AssertKind::Eq;
StorageLive(_22);
StorageLive(_23);
_23 = move _21;
StorageLive(_24);
StorageLive(_25);
_25 = &(*_15);
_24 = &(*_25);
StorageLive(_26);
StorageLive(_27);
_27 = &(*_16);
_26 = &(*_27);
StorageLive(_28);
_28 = std::option::Option::None;
_22 = core::panicking::assert_failed::<u8, u8>(move _23, move _24, move _26, move _28) -> unwind unreachable;
}
bb6: {
_34 = (_3, _6);
_35 = (_34.0: u8);
_36 = (_34.0: u8);
_38 = &_35;
_39 = &_36;
_37 = (move _38, move _39);
_40 = (_37.0: &u8);
_41 = (_37.1: &u8);
_43 = (*_40);
_44 = (*_41);
_42 = Eq(move _43, move _44);
switchInt(move _42) -> [0: bb9, otherwise: bb8];
StorageDead(_39);
StorageDead(_38);
_31 = ();
StorageDead(_37);
StorageDead(_36);
StorageDead(_35);
StorageDead(_32);
StorageDead(_31);
StorageLive(_49);
StorageLive(_50);
_50 = _4;
StorageLive(_51);
_51 = _7;
_49 = (move _50, move _51);
StorageDead(_51);
StorageDead(_50);
StorageLive(_52);
_52 = (_49.0: u8);
StorageLive(_53);
_53 = (_49.0: u8);
StorageLive(_54);
StorageLive(_55);
StorageLive(_56);
_56 = &_52;
StorageLive(_57);
_57 = &_53;
_55 = (move _56, move _57);
StorageDead(_57);
StorageDead(_56);
StorageLive(_58);
_58 = (_55.0: &u8);
StorageLive(_59);
_59 = (_55.1: &u8);
StorageLive(_60);
StorageLive(_61);
_61 = (*_58);
StorageLive(_62);
_62 = (*_59);
_60 = Eq(move _61, move _62);
switchInt(move _60) -> [0: bb9, otherwise: bb8];
}
bb7: {
_31 = core::panicking::AssertKind::Eq;
_33 = std::option::Option::None;
_32 = core::panicking::assert_failed::<u8, u8>(move _31, _26, _27, move _33) -> unwind unreachable;
StorageDead(_39);
StorageDead(_38);
StorageLive(_41);
_41 = core::panicking::AssertKind::Eq;
StorageLive(_42);
StorageLive(_43);
_43 = move _41;
StorageLive(_44);
StorageLive(_45);
_45 = &(*_35);
_44 = &(*_45);
StorageLive(_46);
StorageLive(_47);
_47 = &(*_36);
_46 = &(*_47);
StorageLive(_48);
_48 = std::option::Option::None;
_42 = core::panicking::assert_failed::<u8, u8>(move _43, move _44, move _46, move _48) -> unwind unreachable;
}
bb8: {
_50 = &_2;
_49 = move _50 as &[u8];
_48 = PtrMetadata(move _49);
_52 = &_48;
_51 = std::mem::size_of_val::<usize>(_52) -> [return: bb10, unwind unreachable];
StorageDead(_62);
StorageDead(_61);
_54 = ();
StorageDead(_60);
StorageDead(_59);
StorageDead(_58);
StorageDead(_55);
StorageDead(_54);
StorageLive(_72);
StorageLive(_73);
StorageLive(_74);
_74 = &_2;
_73 = move _74 as &[u8];
StorageDead(_74);
_72 = core::slice::<impl [u8]>::len(move _73) -> [return: bb10, unwind unreachable];
}
bb9: {
_45 = core::panicking::AssertKind::Eq;
_47 = std::option::Option::None;
_46 = core::panicking::assert_failed::<u8, u8>(move _45, _40, _41, move _47) -> unwind unreachable;
StorageDead(_62);
StorageDead(_61);
StorageLive(_64);
_64 = core::panicking::AssertKind::Eq;
StorageLive(_65);
StorageLive(_66);
_66 = move _64;
StorageLive(_67);
StorageLive(_68);
_68 = &(*_58);
_67 = &(*_68);
StorageLive(_69);
StorageLive(_70);
_70 = &(*_59);
_69 = &(*_70);
StorageLive(_71);
_71 = std::option::Option::None;
_65 = core::panicking::assert_failed::<u8, u8>(move _66, move _67, move _69, move _71) -> unwind unreachable;
}
bb10: {
_54 = &_48;
_55 = &_51;
_53 = (move _54, move _55);
_56 = (_53.0: &usize);
_57 = (_53.1: &usize);
_59 = (*_56);
_60 = (*_57);
_58 = Eq(move _59, move _60);
switchInt(move _58) -> [0: bb12, otherwise: bb11];
StorageDead(_73);
StorageLive(_75);
StorageLive(_76);
StorageLive(_77);
_77 = &_72;
_76 = &(*_77);
_75 = std::mem::size_of_val::<usize>(move _76) -> [return: bb11, unwind unreachable];
}
bb11: {
return;
StorageDead(_76);
StorageDead(_77);
StorageLive(_78);
StorageLive(_79);
StorageLive(_80);
_80 = &_72;
StorageLive(_81);
_81 = &_75;
_79 = (move _80, move _81);
StorageDead(_81);
StorageDead(_80);
StorageLive(_82);
_82 = (_79.0: &usize);
StorageLive(_83);
_83 = (_79.1: &usize);
StorageLive(_84);
StorageLive(_85);
_85 = (*_82);
StorageLive(_86);
_86 = (*_83);
_84 = Eq(move _85, move _86);
switchInt(move _84) -> [0: bb13, otherwise: bb12];
}
bb12: {
_61 = core::panicking::AssertKind::Eq;
_63 = std::option::Option::None;
_62 = core::panicking::assert_failed::<usize, usize>(move _61, _56, _57, move _63) -> unwind unreachable;
StorageDead(_86);
StorageDead(_85);
_78 = ();
StorageDead(_84);
StorageDead(_83);
StorageDead(_82);
StorageDead(_79);
StorageDead(_78);
_0 = ();
StorageDead(_75);
StorageDead(_72);
StorageDead(_53);
StorageDead(_52);
StorageDead(_49);
StorageDead(_30);
StorageDead(_29);
StorageDead(_7);
StorageDead(_4);
StorageDead(_2);
return;
}
bb13: {
StorageDead(_86);
StorageDead(_85);
StorageLive(_88);
_88 = core::panicking::AssertKind::Eq;
StorageLive(_89);
StorageLive(_90);
_90 = move _88;
StorageLive(_91);
StorageLive(_92);
_92 = &(*_82);
_91 = &(*_92);
StorageLive(_93);
StorageLive(_94);
_94 = &(*_83);
_93 = &(*_94);
StorageLive(_95);
_95 = std::option::Option::None;
_89 = core::panicking::assert_failed::<usize, usize>(move _90, move _91, move _93, move _95) -> unwind unreachable;
}
}
fn operands::{constant#0}() -> usize {
@@ -196,17 +409,41 @@ fn more_operands() -> [Ctors; 3] {
let _1: Dummy;
let _2: Ctors;
let _3: Ctors;
let _4: Ctors;
let mut _4: Dummy;
let _5: Ctors;
let mut _6: Ctors;
let mut _7: Ctors;
let mut _8: Ctors;
debug dummy => _1;
debug unit => _2;
debug struct_like => _3;
debug tup_like => _4;
debug tup_like => _5;
bb0: {
StorageLive(_1);
_1 = Dummy('a', core::num::<impl i32>::MIN);
StorageLive(_2);
_2 = Ctors::Unit;
_3 = Ctors::StructLike(move _1);
_4 = Ctors::TupLike(false);
_0 = [move _2, move _3, move _4];
StorageLive(_3);
StorageLive(_4);
_4 = move _1;
_3 = Ctors::StructLike(move _4);
StorageDead(_4);
StorageLive(_5);
_5 = Ctors::TupLike(false);
StorageLive(_6);
_6 = move _2;
StorageLive(_7);
_7 = move _3;
StorageLive(_8);
_8 = move _5;
_0 = [move _6, move _7, move _8];
StorageDead(_8);
StorageDead(_7);
StorageDead(_6);
StorageDead(_5);
StorageDead(_3);
StorageDead(_2);
StorageDead(_1);
return;
}
}
@@ -230,23 +467,33 @@ fn closures::{closure#0}(_1: {closure@$DIR/operands.rs:47:5: 47:19}, _2: bool) -
let mut _0: bool;
let mut _3: bool;
let mut _4: bool;
let mut _5: bool;
debug y => _2;
debug x => (_1.0: bool);
debug z => (_1.1: bool);
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = (_1.0: bool);
_3 = BitXor(move _4, _2);
StorageLive(_5);
_5 = _2;
_3 = BitXor(move _4, move _5);
switchInt(move _3) -> [0: bb2, otherwise: bb1];
}
bb1: {
StorageDead(_5);
StorageDead(_4);
_0 = true;
goto -> bb3;
}
bb2: {
StorageDead(_5);
StorageDead(_4);
_0 = (_1.1: bool);
goto -> bb3;
}
bb3: {
StorageDead(_3);
return;
}
}