-
Notifications
You must be signed in to change notification settings - Fork 13.8k
[beta-1.91] Warn on future errors from temporary lifetimes shortening in Rust 1.92 #147056
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: beta
Are you sure you want to change the base?
[beta-1.91] Warn on future errors from temporary lifetimes shortening in Rust 1.92 #147056
Conversation
This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @vakaras Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
r? @davidtwco rustbot has assigned @davidtwco. Use |
There was a problem hiding this 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.
static_assert_size!(Expr<'_>, 72); | ||
static_assert_size!(Expr<'_>, 80); |
There was a problem hiding this comment.
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.
@future_incompatible = FutureIncompatibleInfo { | ||
reason: FutureIncompatibilityReason::FutureReleaseError, | ||
reference: "<https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#macro-extended-temporary-scopes>", | ||
}; |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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.
); | ||
|
||
tcx.node_span_lint(MACRO_EXTENDED_TEMPORARY_SCOPES, lint_root, labels, |diag| { | ||
diag.primary_message("temporary lifetime shortening in Rust 1.92"); |
There was a problem hiding this comment.
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:
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"); |
There was a problem hiding this comment.
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?
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:Implementation-wise, this reuses the existing temporary scoping FCW machinery introduced for the
tail_expr_drop_order
edition lint: this addsBackwardIncompatibleDropHint
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:
cc @traviscross
@rustbot label +T-lang
Footnotes
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
. ↩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. ↩