Skip to content

Conversation

dianne
Copy link
Contributor

@dianne dianne commented Sep 26, 2025

Pursuant to discussion on Zulip, this implements a future-compatibility warning lint macro_extended_temporary_scopes for errors in Rust 1.92 caused by #145838:

warning: temporary lifetime shortening in Rust 1.92
  --> $DIR/macro-extended-temporary-scopes.rs:54:14
   |
LL |             &struct_temp().field
   |              ^^^^^^^^^^^^^ this expression creates a temporary value...
...
LL |         } else {
   |         - ...which will be dropped at the end of this block in Rust 1.92
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see <https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#macro-extended-temporary-scopes>
   = note: consider using a `let` binding to create a longer lived value

Implementation-wise, this reuses the existing temporary scoping FCW machinery introduced for the tail_expr_drop_order edition lint: this adds BackwardIncompatibleDropHint statements to the MIR at the end of the shortened scopes for affected temporaries; these are then checked in borrowck to warn if the temporary is used after the future drop hint. There are trade-offs here: on one hand, I believe this gives some assurance over ad-hoc pattern-recognition that there are no false positives1. On the other hand, this fails to lint on future dangling raw pointers and it complicates the potential addition of explanatory diagnostics or suggestions2. I'm hopeful that the limitation around dangling pointers won't be relevant in real code, though; the only real instance we've seen of breakage so far is future errors in formatting macro invocations, which this should be able to catch.

Release logistics notes:

  • This PR targets the beta branch directly, since the breakage it's a FCW for is landing in the next Rust version.
  • Temporary lifetime extension for blocks #146098 undoes the breakage this is a FCW for. If that behavior is merged and stabilizes in Rust 1.92, this PR should be reverted (or shouldn't be merged) in order to avoid spurious warnings.

cc @traviscross

@rustbot label +T-lang

Footnotes

  1. In particular, more syntactic approaches are complicated by having to avoid warning on promoted constants; they'd either be full of holes, they'd need a lot of extra logic, or they'd need to hack more MIR-to-HIR mapping into PromoteTemps.

  2. It's definitely possible to add more context and a suggestion, but the ways I've thought of to do so are either too hacky or too complex to feel appropriate for a last-minute direct-to-beta lint.

@rustbot
Copy link
Collaborator

rustbot commented Sep 26, 2025

This PR changes MIR

cc @oli-obk, @RalfJung, @JakobDegen, @vakaras

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@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 Sep 26, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 26, 2025

r? @davidtwco

rustbot has assigned @davidtwco.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the T-lang Relevant to the language team label Sep 26, 2025
Copy link
Contributor Author

@dianne dianne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A general note: since this isn't targeting master, I've included a fair bit of single-purpose code. It's possible some of the generalizations to BackwardIncompatibleDropHint handling would be good to have for future FCWs, but everything new is made to be one-off and temporary.

Also, a note about the ping for changing the MIR: I believe that's from adding another case to BackwardIncompatibleDropReason.

And about changing MIR transforms: that's from making the significant-drop-reordering part of tail_expr_drop_order only fire on BackwardIncompatibleDropReason::Edition2024. It already checks the edition, so I figure it makes sense to check the BackwardIncompatibleDropReason too.

View changes since this review

Comment on lines -1128 to +1130
static_assert_size!(Expr<'_>, 72);
static_assert_size!(Expr<'_>, 80);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be avoidable. Let me know if it's worth trying to fix.

Comment on lines +5245 to +5248
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "<https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#macro-extended-temporary-scopes>",
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, the reference link shouldn't be tied to the lint's stabilization, but there's not currently a great reference that both includes a complete explanation of the breakage and how to work around it.

Also, I haven't included report_in_deps: true but since the breakage is hitting in the next version it might be warranted.


tcx.node_span_lint(MACRO_EXTENDED_TEMPORARY_SCOPES, lint_root, labels, |diag| {
diag.primary_message("temporary lifetime shortening in Rust 1.92");
diag.note("consider using a `let` binding to create a longer lived value");
Copy link
Contributor Author

@dianne dianne Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opted to use the "consider using a let binding" note from real borrowck diagnostics for simplicity, rather than providing a machine-applicable suggestion. To illustrate, consider real Rust 1.92 nightly diagnostics for the future breakage here:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:18:13
   |
18 |     pin!({ &temp() });
   |     --------^^^^^----
   |     |       |    |
   |     |       |    temporary value is freed at the end of this statement
   |     |       creates a temporary value which is freed while still in use
   |     borrow later stored here
   |
   = note: consider using a `let` binding to create a longer lived value

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:19:17
   |
19 |     pin!({ &mut [()] });
   |            -----^^^-
   |            |    |  |
   |            |    |  temporary value is freed at the end of this statement
   |            |    creates a temporary value which is freed while still in use
   |            borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

Note the differing spans. In many instances, the conflicting use reported in diagnostics is an implicit reborrow rather than the actual use in the macro expansion. I think getting more helpful diagnostics would either require:

  • Improving the actual borrowck diagnostic, then using that machinery.
  • Forcing maximal MIR-to-HIR mapping via source scopes when forward-incompatible drops are detected, then using bespoke diagnostic information stored earlier in compilation (e.g. the HIR source of forward-incompatible scope extension).

Another awkward aspect of that span imprecision is (without doing either of those things) it's hard to tell when adding a let statement actually can help. In non-pathological cases it should always either help or come with another note that the diagnostic originates in an external macro, so for simplicity, I've opted to always include it.

@traviscross traviscross added I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-0 Lang team prioritization drag level 0.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. labels Sep 26, 2025
);

tcx.node_span_lint(MACRO_EXTENDED_TEMPORARY_SCOPES, lint_root, labels, |diag| {
diag.primary_message("temporary lifetime shortening in Rust 1.92");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message seems like it'd be difficult to understand without context — to me, it almost seems like it's been cut off partway through. It might be better to be explicit here:

Suggested change
diag.primary_message("temporary lifetime shortening in Rust 1.92");
diag.primary_message("this temporary's lifetime will be shortened starting in Rust 1.92");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit difficult to understand as-is.. though I wonder if there's a way to write it without "this" in the primary message. My original take was "this temporary value's lifetime will shorten in Rust 1.92", but I moved away from it because something didn't feel right to me about the "this" and it felt redundant with the label. Maybe it would be fine?

@dianne dianne force-pushed the fcw-super-let-init-borrow-shortening branch from 1dc4b0d to 2ecbcc5 Compare September 29, 2025 07:36
@rustbot
Copy link
Collaborator

rustbot commented Sep 29, 2025

Some changes occurred in match lowering

cc @Nadrieril

@dianne
Copy link
Contributor Author

dianne commented Sep 29, 2025

I haven't adjusted the wording yet, but I did some renaming and I've added logic to also lint on shortening lifetimes for internal temporaries created by pin! and format_args!. These weren't initially caught since they're implemented in the compiler as local variables that follow temporary scoping rules (hence the match lowering change; that's where variables' drops are scheduled). This is much less likely to be relevant, but it's possible if someone was using format_args! with constant-promotable arguments in if branches in string formatting. e.g.

println!("{:?}{}",
    (),
    if true {
        format_args!("{:?}", Promotable)
    } else {
        format_args!("")
    }
);

It's a much more niche situation admittedly, but it compiles on stable/beta and not nightly (and it wasn't caught previously).

@rust-log-analyzer

This comment has been minimized.

@dianne dianne force-pushed the fcw-super-let-init-borrow-shortening branch from 2ecbcc5 to 5d1246e Compare September 29, 2025 08:04
@rustbot
Copy link
Collaborator

rustbot commented Sep 29, 2025

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rustbot rustbot added the T-clippy Relevant to the Clippy team. label Sep 29, 2025
@davidtwco
Copy link
Member

r? @jackh726 who reviewed the original PR

@rustbot rustbot assigned jackh726 and unassigned davidtwco Sep 29, 2025
@jackh726
Copy link
Member

I haven't looked at this too deeply yet, but my general initial thought is this is a lot of code changes for something that is only going to hit beta with no prior testing on nightly. It really concerns me, I'm not sure about other compiler folks.

Copy link
Member

@samueltardieu samueltardieu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy changes review: no concerns about the mechanical changes.

View changes since this review

@jackh726 jackh726 added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Oct 1, 2025
@jackh726
Copy link
Member

jackh726 commented Oct 1, 2025

Still haven't gotten to review this properly, but going to go ahead and add the nomination label to get a feel for what others think.

@traviscross traviscross removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-clippy Relevant to the Clippy team. labels Oct 1, 2025
@traviscross
Copy link
Contributor

We've decided to break this; we want to accept this one-version FCW, and we're waiving our 10-day final comment period.

Obviously it's compiler's call whether to accept the beta backport.

@rfcbot fcp merge

@rust-rfcbot
Copy link
Collaborator

rust-rfcbot commented Oct 1, 2025

Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rust-rfcbot rust-rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Oct 1, 2025
@tmandry
Copy link
Member

tmandry commented Oct 1, 2025

@rfcbot reviewed

@rust-rfcbot rust-rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Oct 1, 2025
@rust-rfcbot
Copy link
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@nikomatsakis
Copy link
Contributor

@rfcbot reviewed

@joshtriplett
Copy link
Member

Approving this, but let's keep a careful eye on the pre-release crater runs since this is a bunch of new code that isn't on top of tree.

@theemathas
Copy link
Contributor

The crater run for 1.91 is already ongoing. Will we need another crater run for specifically this PR?

@traviscross traviscross added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Oct 2, 2025
@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-0 Lang team prioritization drag level 0.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. labels Oct 2, 2025
@apiraino
Copy link
Contributor

apiraino commented Oct 2, 2025

Beta backport accepted as per compiler team on Zulip, though it wasn't an easy and clear decision. Normally we'd suggest reverting breakage changes and give us time to bake a fix properly, this time we feel there was not an easy way forward so this backport is not the ideal solution.

@rustbot label +beta-accepted

@rustbot rustbot added the beta-accepted Accepted for backporting to the compiler in the beta channel. label Oct 2, 2025
@cuviper
Copy link
Member

cuviper commented Oct 2, 2025

Note: since this PR is directly against beta, I'm not going to handle the "backport" as I usually would from T-release. Whoever is reviewing this from the compiler side, please go ahead with r+ when you're ready.

@bors rollup=never

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta-accepted Accepted for backporting to the compiler in the beta channel. beta-nominated Nominated for backporting to the compiler in the beta channel. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-lang Relevant to the language team
Projects
None yet
Development

Successfully merging this pull request may close these issues.