Skip to content

Conversation

WaffleLapkin
Copy link
Member

this is required as otherwise drops of &mut refs count as a usage of a
'two-phase temporary' causing an ICE.

fixes #128097

The underlying issue is that the current code generates drops for &mut which are later counted as a second use of a two-phase temporary:

bat t.rs -p

#![expect(incomplete_features)]
#![feature(explicit_tail_calls)]

fn f(x: &mut ()) {
    let _y = String::new();
    become f(x);
}

fn main() {}

rustc t.rs -Zdump_mir=f

error: internal compiler error: compiler/rustc_borrowck/src/borrow_set.rs:298:17: found two uses for 2-phase borrow temporary _4: bb2[1] and bb3[0]
 --> t.rs:6:5
  |
6 |     become f(x);
  |     ^^^^^^^^^^^


thread 'rustc' panicked at compiler/rustc_borrowck/src/borrow_set.rs:298:17:
Box<dyn Any>
stack backtrace:
[REDACTED]

error: aborting due to 1 previous error

bat ./mir_dump/t.f.-------.renumber.0.mir -p -lrust

// MIR for `f` 0 renumber

fn f(_1: &mut ()) -> () {
    debug x => _1;
    let mut _0: ();
    let mut _2: !;
    let _3: std::string::String;
    let mut _4: &mut ();
    scope 1 {
        debug _y => _3;
    }

    bb0: {
        StorageLive(_3);
        _3 = String::new() -> [return: bb1, unwind: bb4];
    }

    bb1: {
        FakeRead(ForLet(None), _3);
        StorageLive(_4);
        _4 = &mut (*_1);
        drop(_3) -> [return: bb2, unwind: bb3];
    }

    bb2: {
        StorageDead(_3);
        tailcall f(Spanned { node: move _4, span: t.rs:6:14: 6:15 (#0) });
    }

    bb3 (cleanup): {
        drop(_4) -> [return: bb4, unwind terminate(cleanup)];
    }

    bb4 (cleanup): {
        resume;
    }
}

Note how _4 is moved into the tail call in bb2and dropped inbb3`.

This PR adds a check that the locals we drop need dropping.

r? @oli-obk (feel free to reassign, I'm not sure who would be a good reviewer, but thought you might have an idea)
cc @beepster4096, since you wrote the original drop implementation.

this is required as otherwise drops of `&mut` refs count as a usage of a
'two-phase temporary' causing an ICE.
@WaffleLapkin WaffleLapkin added A-destructors Area: Destructors (`Drop`, …) F-explicit_tail_calls `#![feature(explicit_tail_calls)]` labels Jan 24, 2025
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 24, 2025
@rust-log-analyzer

This comment has been minimized.

@oli-obk
Copy link
Contributor

oli-obk commented Jan 24, 2025

r=me with crash test removed and comment updated

@rust-log-analyzer

This comment has been minimized.

I'm not sure why the span improved but that's nice!
@rustbot
Copy link
Collaborator

rustbot commented Jan 24, 2025

The Miri subtree was changed

cc @rust-lang/miri

@WaffleLapkin
Copy link
Member Author

@bors r=@oli-obk

@bors
Copy link
Collaborator

bors commented Jan 24, 2025

📌 Commit 9b82f20 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 24, 2025
bors added a commit to rust-lang-ci/rust that referenced this pull request Jan 24, 2025
…iaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang#135415 (Add `File already exists` error doc to `hard_link` function)
 - rust-lang#135581 (Separate Builder methods from tcx)
 - rust-lang#135728 (document order of items in iterator from drain)
 - rust-lang#135749 (Do not assume const params are printed after type params)
 - rust-lang#135829 (Rustc dev guide subtree update)
 - rust-lang#135938 (Add memory layout documentation to generic NonZero<T>)
 - rust-lang#135949 (Use short type string in E0308 secondary span label)
 - rust-lang#135976 (Don't drop types with no drop glue when building drops for tailcalls)
 - rust-lang#135998 ([rustdoc] Fix indent of trait items on mobile)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 99e34a4 into rust-lang:master Jan 25, 2025
6 checks passed
@rustbot rustbot added this to the 1.86.0 milestone Jan 25, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Jan 25, 2025
Rollup merge of rust-lang#135976 - WaffleLapkin:tailcall-nodrop, r=oli-obk

Don't drop types with no drop glue when building drops for tailcalls

this is required as otherwise drops of `&mut` refs count as a usage of a
'two-phase temporary' causing an ICE.

fixes rust-lang#128097

The underlying issue is that the current code generates drops for `&mut` which are later counted as a second use of a two-phase temporary:

`bat t.rs -p`
```rust
#![expect(incomplete_features)]
#![feature(explicit_tail_calls)]

fn f(x: &mut ()) {
    let _y = String::new();
    become f(x);
}

fn main() {}
```
`rustc t.rs -Zdump_mir=f`
```text
error: internal compiler error: compiler/rustc_borrowck/src/borrow_set.rs:298:17: found two uses for 2-phase borrow temporary _4: bb2[1] and bb3[0]
 --> t.rs:6:5
  |
6 |     become f(x);
  |     ^^^^^^^^^^^

thread 'rustc' panicked at compiler/rustc_borrowck/src/borrow_set.rs:298:17:
Box<dyn Any>
stack backtrace:
[REDACTED]

error: aborting due to 1 previous error
```
`bat ./mir_dump/t.f.-------.renumber.0.mir -p -lrust`
```rust
// MIR for `f` 0 renumber

fn f(_1: &mut ()) -> () {
    debug x => _1;
    let mut _0: ();
    let mut _2: !;
    let _3: std::string::String;
    let mut _4: &mut ();
    scope 1 {
        debug _y => _3;
    }

    bb0: {
        StorageLive(_3);
        _3 = String::new() -> [return: bb1, unwind: bb4];
    }

    bb1: {
        FakeRead(ForLet(None), _3);
        StorageLive(_4);
        _4 = &mut (*_1);
        drop(_3) -> [return: bb2, unwind: bb3];
    }

    bb2: {
        StorageDead(_3);
        tailcall f(Spanned { node: move _4, span: t.rs:6:14: 6:15 (#0) });
    }

    bb3 (cleanup): {
        drop(_4) -> [return: bb4, unwind terminate(cleanup)];
    }

    bb4 (cleanup): {
        resume;
    }
}
```

Note how `_4 is moved into the tail call in `bb2` and dropped in `bb3`.

This PR adds a check that the locals we drop need dropping.

r? `@oli-obk` (feel free to reassign, I'm not sure who would be a good reviewer, but thought you might have an idea)
cc `@beepster4096,` since you wrote the original drop implementation.
@WaffleLapkin WaffleLapkin deleted the tailcall-nodrop branch January 25, 2025 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-destructors Area: Destructors (`Drop`, …) F-explicit_tail_calls `#![feature(explicit_tail_calls)]` S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

compiler/rustc_borrowck/src/borrow_set.rs:250:17: found two uses for 2-phase borrow temporary
5 participants