-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Temporary lifetime extension for blocks #146098
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: master
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
78995b7
to
2e55e56
Compare
@rustbot label -stable-nominated I'm not intending to stable-nominate this, at least. Someone else can, but I don't expect it's needed or that it would be accepted. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment has been minimized.
This comment has been minimized.
2e55e56
to
eafdca9
Compare
Does this only affect code in Rust 2024, or would you expect any visible difference in earlier editions? |
Suppose we have a macro Or to generalize this, the aim of this PR is that in a non-extending context, If new expressions are added to Rust that are both extending and temporary scopes, I'd want this behavior to apply to them as well. |
Since this would effectively reduce the scope of the Rust 2024 tail expression temporary scope change, we'd also want to be sure to reflect that in the behavior of the |
I haven't done extensive testing, but see this test diff for that lint: lint-tail-expr-drop-order-borrowck.rs. I'm applying the lifetime extension rules on all editions, and lifetime extension prevents the temporary scope from being registered as potentially forwards-incompatible (even though the extended scopes are technically the same as the old scopes in old editions). Though I think I've convinced myself at this point that lifetime extension doesn't need to be applied to block tails of non-extending old-edition blocks1, so potentially the lint change could be implemented in some other way instead. Footnotes
|
☔ The latest upstream changes (presumably #146666) made this pull request unmergeable. Please resolve the merge conflicts. |
Co-authored-by: Travis Cross <tc@traviscross.com>
This is the real-world way that the unintentional stabilization of lifetime extension for format arguments was used.
eafdca9
to
e649bbe
Compare
I've made some revisions. This should now properly handle I think the implementation will likely need optimization and cleanup, but it might take a bit of refactoring to get it to a good place, so I'd like to get a vibe check on the design first, if there's room for it in a lang team meeting. @rustbot label +I-lang-nominated |
Is there a way to tell where instruction count regressions are from? Looking at the wall time breakdown from the detailed report pages though, it looks like this doesn't make Footnotes
|
Cachegrind can be used to show function-level profiling results using https://github.com/rust-lang/rustc-perf:
|
Thanks! Looking at the diff for the cargo (full) test, it indeed looks like the instruction count increase for that test is in llvm; the diff was dominated by changes in llvm instruction counts (mostly increases). I couldn't find any functions in If the llvm perf regression in that test and the incremental perf regression in |
This seems like a relatively involved change that indeed could have effect on (LLVM) codegen. I think that in light of that the small regressions are justifiable, especially if you also have some ideas about how it could be improved in the future. |
I've opened a PR to fix the imprecise array/slice index temporary scopes at #147083. There may be other instances of imprecise temporary scoping in MIR building that this PR would interact with, but that's at least a start. |
@dianne I can probably review this PR At Some Point:tm: but it'll take a bit before I have the time to properly dig into the surrounding context of lifetime extension stuff, and I imagine it'll also take a while to get up to speed on that :thinking: If there's someone already up to speed on this that could review this PR that might be better but otherwise this is fine :+1: |
Unfortunately, I'm not sure who all on review rotation would have lifetime extension fresh in mind. Maybe @jackh726 since you reviewed my last temporary scoping PR recently? Otherwise, thanks in advance! ^^ |
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🎉 Experiment
Footnotes
|
@craterbot run p=1 mode=build-and-test crates=https://crater-reports.s3.amazonaws.com/pr-146098/retry-regressed-list.txt |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
The WLambda regression (https://crater-reports.s3.amazonaws.com/pr-146098/try%23028592fec99e54cc92def5a2a849c673b066dd93/gh/WeirdConstructor.WBlockDSP/log.txt) looks real. It uses a raw pointer cast, If necessary, I think it'd be possible to lint on raw borrows (and raw pointer casts of borrow expressions) that would be extended by this PR and (when possible) suggest non-extending alternatives (such as |
It's probably worth making the PR to WLambda in any case. Whatever we do, their code would certainly be made clearer and better by not relying on this. Once they merge it, it'd be then maybe worth notifying any dependents that need to update. Let us know what you think after looking through the test failures (I know, those are hard to go through). If we can put out an FCW here, that's always going to be an easier decision for us to make than taking the breakage directly. |
🎉 Experiment
Footnotes
|
WLambda still seems to be the only build failure. This time it appeared in the root results as well. For the tests, 87's still quite a few; a rerun might be worthwhile? In the mean time, I'll start looking over them in batches; it'll be good to identify flaky tests regardless (but it'd take a few days to get through all 87). The first 16 test failures (all spurious regressions)
|
@craterbot run p=5 mode=build-and-test crates=https://crater-reports.s3.amazonaws.com/pr-146098-1/retry-regressed-list.txt |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
PR opened to WLambda: WeirdConstructor/WLambda#17 |
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
This implements a revised version of the temporary lifetime extension semantics I suggested in #145838 (comment), with the goal of making temporary lifetimes and drop order more consistent between extending and non-extending blocks. As a consequence, this undoes the breaking change introduced by #145838 (but in exchange has a much larger surface area).
The change this PR hopes to enforce is a general rule: any expression's temporaries should have the same relative drop order regardless of whether the expression is in an extending context or not:
let _ = $expr;
anddrop($expr);
should have the same drop order. To achieve that, this PR applies lifetime extension rules to blocks:now extends the lifetime of
temp()
to outlive the block tail in Rust 2024 regardless of whether the block is an extending expression in alet
statement initializer (in which context it was already extended to outlive the block before this PR). The scoping rules for tails of extending blocks remain the same: extending subexpressions' temporary scopes are extended based on the source of the lifetime extension (e.g. to match the scope of a parentlet
statement's bindings). For blocks not extended by any other source, extending borrows in the tail expression now share a temporary scope with the result of the block. This can in turn extend nested blocks within blocks' tail expressions:Since this uses the same rules as
let
, it only applies to extending sub-expressions.This also applies to
if
expressions' blocks since lifetime extension applies toif
blocks' tail expressions, meaning it affects all editions. This is where breakage from #145838 was observed:now extends
temp()
to have the same temporary scope as the result of theif
expression.As a further consequence, this makes
super let
inif
expressions' blocks more consistent with block expressions:previously only worked in extending contexts (since the
super let
s would be extended), and now it works everywhere.I don't think this is ready to merge yet. It should have a Reference PR, it will need a lang FCP, and it may need other things as well.
@rustbot label +T-lang