Skip to content

StorageLive is added on a local that was already live #88649

Closed

Description

Miri's CI started failing recently, with an error similar to:

error: Undefined Behavior: StorageLive on a local that was already live
 --> foo.rs:9:52
  |
9 |             Foo::Variant1(x) | Foo::Variant2(x) if x => {}
  |                                                    ^ StorageLive on a local that was already live
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

It seems likely that this is a regression from #88572. cc @matthewjasper

Thanks to @hyd-dev for doing the original minimization.

MCVE

enum Foo {
    Variant1(bool),
    Variant2(bool),
}

fn main() {
    loop {
        match Foo::Variant1(true) {
            Foo::Variant1(x) | Foo::Variant2(x) if x => {}
            _ => {}
        }
    }
}

Generated MIR (from right after building)

// MIR for `main` 0 mir_map

fn main() -> () {
    let mut _0: ();                      // return place in scope 0 at foo.rs:6:11: 6:11
    let mut _1: !;                       // in scope 0 at foo.rs:7:5: 12:6
    let mut _2: ();                      // in scope 0 at foo.rs:6:1: 13:2
    let mut _3: Foo;                     // in scope 0 at foo.rs:8:15: 8:34
    let mut _4: isize;                   // in scope 0 at foo.rs:9:13: 9:29
    let mut _5: &Foo;                    // in scope 0 at foo.rs:8:15: 8:34
    let _6: bool;                        // in scope 0 at foo.rs:9:27: 9:28
    let _7: &bool;                       // in scope 0 at foo.rs:9:27: 9:28
    let mut _8: bool;                    // in scope 0 at foo.rs:9:52: 9:53
    let mut _9: bool;                    // in scope 0 at foo.rs:9:52: 9:53
    scope 1 {
        debug x => _6;                   // in scope 1 at foo.rs:9:27: 9:28
        debug x => _7;                   // in scope 1 at foo.rs:9:27: 9:28
    }

    bb0: {
        StorageLive(_1);                 // scope 0 at foo.rs:7:5: 12:6
        goto -> bb1;                     // scope 0 at foo.rs:7:5: 12:6
    }

    bb1: {
        falseUnwind -> [real: bb2, cleanup: bb19]; // scope 0 at foo.rs:7:5: 12:6
    }

    bb2: {
        StorageLive(_3);                 // scope 0 at foo.rs:8:15: 8:34
        _3 = Foo::Variant1(const true);  // scope 0 at foo.rs:8:15: 8:34
        FakeRead(ForMatchedPlace(None), _3); // scope 0 at foo.rs:8:15: 8:34
        _4 = discriminant(_3);           // scope 0 at foo.rs:8:15: 8:34
        switchInt(move _4) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at foo.rs:8:9: 8:34
    }

    bb3: {
        falseEdge -> [real: bb8, imaginary: bb5]; // scope 0 at foo.rs:9:13: 9:29
    }

    bb4: {
        _2 = const ();                   // scope 0 at foo.rs:10:18: 10:20
        goto -> bb16;                    // scope 0 at foo.rs:10:18: 10:20
    }

    bb5: {
        falseEdge -> [real: bb12, imaginary: bb4]; // scope 0 at foo.rs:9:32: 9:48
    }

    bb6: {
        goto -> bb4;                     // scope 0 at foo.rs:8:9: 8:34
    }

    bb7: {
        _2 = const ();                   // scope 1 at foo.rs:9:57: 9:59
        StorageDead(_6);                 // scope 0 at foo.rs:9:58: 9:59
        StorageDead(_9);                 // scope 0 at foo.rs:9:58: 9:59
        StorageDead(_7);                 // scope 0 at foo.rs:9:58: 9:59
        goto -> bb16;                    // scope 0 at foo.rs:9:58: 9:59
    }

    bb8: {
        StorageLive(_7);                 // scope 0 at foo.rs:9:27: 9:28
        _7 = &((_3 as Variant1).0: bool); // scope 0 at foo.rs:9:27: 9:28
        _5 = &shallow _3;                // scope 0 at foo.rs:8:15: 8:34
        StorageLive(_8);                 // scope 0 at foo.rs:9:52: 9:53
        _8 = (*_7);                      // scope 0 at foo.rs:9:52: 9:53
        switchInt(move _8) -> [false: bb10, otherwise: bb9]; // scope 0 at foo.rs:9:52: 9:53
    }

    bb9: {
        FakeRead(ForMatchGuard, _5);     // scope 0 at foo.rs:9:52: 9:53
        FakeRead(ForGuardBinding, _7);   // scope 0 at foo.rs:9:52: 9:53
        StorageLive(_6);                 // scope 0 at foo.rs:9:27: 9:28
        _6 = ((_3 as Variant1).0: bool); // scope 0 at foo.rs:9:27: 9:28
        goto -> bb7;                     // scope 0 at foo.rs:8:9: 11:10
    }

    bb10: {
        goto -> bb11;                    // scope 0 at foo.rs:9:52: 9:53
    }

    bb11: {
        StorageDead(_8);                 // scope 0 at foo.rs:9:58: 9:59
        StorageDead(_7);                 // scope 0 at foo.rs:9:58: 9:59
        falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at foo.rs:9:52: 9:53
    }

    bb12: {
        StorageLive(_7);                 // scope 0 at foo.rs:9:46: 9:47
        _7 = &((_3 as Variant2).0: bool); // scope 0 at foo.rs:9:46: 9:47
        _5 = &shallow _3;                // scope 0 at foo.rs:8:15: 8:34
        StorageLive(_9);                 // scope 0 at foo.rs:9:52: 9:53
        _9 = (*_7);                      // scope 0 at foo.rs:9:52: 9:53
        switchInt(move _9) -> [false: bb14, otherwise: bb13]; // scope 0 at foo.rs:9:52: 9:53
    }

    bb13: {
        FakeRead(ForMatchGuard, _5);     // scope 0 at foo.rs:9:52: 9:53
        FakeRead(ForGuardBinding, _7);   // scope 0 at foo.rs:9:52: 9:53
        StorageLive(_6);                 // scope 0 at foo.rs:9:46: 9:47
        _6 = ((_3 as Variant2).0: bool); // scope 0 at foo.rs:9:46: 9:47
        goto -> bb7;                     // scope 0 at foo.rs:8:9: 11:10
    }

    bb14: {
        goto -> bb15;                    // scope 0 at foo.rs:9:52: 9:53
    }

    bb15: {
        StorageDead(_9);                 // scope 0 at foo.rs:9:58: 9:59
        StorageDead(_7);                 // scope 0 at foo.rs:9:58: 9:59
        falseEdge -> [real: bb6, imaginary: bb4]; // scope 0 at foo.rs:9:52: 9:53
    }

    bb16: {
        StorageDead(_3);                 // scope 0 at foo.rs:12:5: 12:6
        goto -> bb1;                     // scope 0 at foo.rs:7:5: 12:6
    }

    bb17: {
        unreachable;                     // scope 0 at foo.rs:7:5: 12:6
    }

    bb18: {
        StorageDead(_1);                 // scope 0 at foo.rs:12:5: 12:6
        return;                          // scope 0 at foo.rs:13:2: 13:2
    }

    bb19 (cleanup): {
        resume;                          // scope 0 at foo.rs:6:1: 13:2
    }
}

EDIT: updated the MIR output so it's from the latest nightly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-nightlyPerformance or correctness regression from stable to nightly.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions