Skip to content

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

Closed
@camelid

Description

@camelid

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

Metadata

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