Repository navigation
1.96 beta regression: "lua does not live long enough", take 2 #155902
Copy link
Copy link
Closed
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-destructorsArea: Destructors (`Drop`, …)Area: Destructors (`Drop`, …)A-fmtArea: `core::fmt`Area: `core::fmt`A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-bugCategory: This is a bug.Category: This is a bug.P-criticalCritical priorityCritical priorityS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.Performance or correctness regression from stable to beta.
Milestone
Description
Turns out that the #154988 regression wasn't completely fixed by the #154994 PR. (That regression was in turn caused by #154074, which fixes the #153850 regression).
Regression found by the 1.96 beta crater run.
[INFO] [stdout] error[E0597]: `lua` does not live long enough
[INFO] [stdout] --> src/transpile/lua.rs:51:30
[INFO] [stdout] |
[INFO] [stdout] 18 | #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
[INFO] [stdout] | -
[INFO] [stdout] | |
[INFO] [stdout] | `lua` dropped here while still borrowed
[INFO] [stdout] | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `(LuaValue<'_>,)`
[INFO] [stdout] ...
[INFO] [stdout] 25 | let lua = Lua::new();
[INFO] [stdout] | --- binding `lua` declared here
[INFO] [stdout] ...
[INFO] [stdout] 51 | let lua_result = lua
[INFO] [stdout] | ^^^ borrowed value does not live long enough
[INFO] [stdout] ...
[INFO] [stdout] 62 | self.handle_lua_result(dbg!(lua_result)).map_err(|err| {
[INFO] [stdout] | ---------------- a temporary with access to the borrow is created here ...
[INFO] [stdout] |
[INFO] [stdout] = note: the temporary is part of an expression at the end of a block;
[INFO] [stdout] consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
[INFO] [stdout] help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
[INFO] [stdout] |
[INFO] [stdout] 62 ~ let x = self.handle_lua_result(dbg!(lua_result)).map_err(|err| {
[INFO] [stdout] 63 | handler.receive(err.clone());
[INFO] [stdout] 64 | err
[INFO] [stdout] 65 ~ }); x
[INFO] [stdout] |
[INFO] [stdout]
[INFO] [stdout]
[INFO] [stdout] For more information about this error, try `rustc --explain E0597`.
cc @dianne
Metadata
Metadata
Assignees
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-destructorsArea: Destructors (`Drop`, …)Area: Destructors (`Drop`, …)A-fmtArea: `core::fmt`Area: `core::fmt`A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-bugCategory: This is a bug.Category: This is a bug.P-criticalCritical priorityCritical priorityS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.Performance or correctness regression from stable to beta.
Activity
theemathas commentedon Apr 28, 2026
Minimized (requires edition 2021, not 2024):
Error output on beta
This is the same as #154988 (comment) except that
Fooalso implementsDrop.theemathas commentedon Apr 28, 2026
This code (based on the expansion of
dbg!) errors in edition 2021, and I don't understand why:Error output
dianne commentedon Apr 28, 2026
Oh no, is this because of drop order on the unwind path? If
Foodoesn't implementDrop, there's no conflict because we don't putStorageDeads in cleanup blocks. But ifFoodoes implementDrop, we end up with a drop forfooon the unwind path before the drop for the(bar,)temp due to Rust 2021 tail expr scopes. My idea was that we'd move out of that temp before it's a problem, but if we panic before then, that might not be the case.I tested this hunch and it seems maybe correct? The conflicting location is the drop terminator for
fooin a cleanup block. In contrast, for the reproducer in #154988 (comment) (i.e. for pre-#154994dbg!and noDropimpl forFoo), the conflicting location was theStorageDeadforfooon the happy path.This really isn't something we should have to worry about in
dbg!.. maybe it's time to give up on tricky solutions and just do it withsuper let? Though withsuper letin the state it's in right now it'd still be a bit tricky, unfortunately.dianne commentedon Apr 28, 2026
As for how we can end up unwinding between creating the
(bar,)temporary and moving out of it, as far as I can tell it's because we first movebarinto a temporary to be used as the operand for the tuple constructor, which is dropped immediately after constructing the tuple. Of course, this can't actually panic at runtime because it's always uninitialized at that point; aiui drop elaboration will replace that drop with a goto. But since borrowck happens first, the cfg still has that edge there (and I assume if we did move drop elaboration first, we'd use aFalseUnwindto keep the static semantics the same.. though I wouldn't say it's particularly easy to reason about this way).12 remaining items
orlp commentedon May 17, 2026
It appears that wrapping the evaluated tuple in an identity function solves this problem. That is, replacing this line:
rust/library/std/src/macros.rs
Line 388 in ba0949a
with
theemathas commentedon May 18, 2026
Just a
{}block is sufficient to get rid of the error. This doesn't make any sense.theemathas commentedon May 18, 2026
Comparison of the MIR of the two functions
The difference in the MIR is where the control flow goes if the destructor of
Barpanics. This destructor seems to be, for some reason, ran immediately afterBaris moved into the tuple.MIR of works
MIR of fails
theemathas commentedon May 18, 2026
I've filed this weirdness as #156713.
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
theemathas commentedon May 23, 2026
This issue is fixed by #156772.
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472
Auto merge of #156589 - cuviper:revert-dbg-tearing, r=the8472