Skip to content

for loop desugaring treats the loop's trailing expression in unusual way #61902

Open
@petrochenkov

Description

@petrochenkov
Contributor

Namely, it's treated as a semicolon-less statement in a middle of the block.

// Like this:
fn main() {
    { 0 } // <- semicolon-less statement in a middle of the block

    ()
}

This is unusual because

  • No other block construction or loop does this.
  • The desugared form cannot be written in source code (it will either need a semicolon, or will be considered trailing).

Git blame says that the behavior was introduced by @Zoxc in #42265.

We cannot remove this behavior because it appears to be useful and code will break if it's removed.
We can, however, use it in other block constructions for which the block's trailing expression does not represent its result.

Block construction Trailing expression is the result
if cond { ... } [else { ... }] Yes
if let pat = expr { ... } [else { ... }] Yes
while cond { ... } No
while let pat = expr { ... } No
for pat in expr { ... } No
loop { ... } No
[unsafe] { ... } Yes
async { ... } ???
try { ... } Yes

Activity

added
C-bugCategory: This is a bug.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
T-langRelevant to the language team
on Jun 16, 2019
petrochenkov

petrochenkov commented on Jun 20, 2019

@petrochenkov
ContributorAuthor

We can, however, use it in other block constructions for which the block's trailing expression does not represent its result.

Or, perhaps, avoid the lifetime prolonging behavior for trailing non-result expressions (aka trailing expressions in loops) somewhere at MIR lowering time.

With #61988 merged that's going to be very simple:

Block construction Trailing expression is the result
hir::ExprKind::Block Yes
hir::ExprKind::Loop No
eddyb

eddyb commented on Jun 23, 2019

@eddyb
Member

Or, perhaps, avoid the lifetime prolonging behavior for trailing non-result expressions (aka trailing expressions in loops) somewhere at MIR lowering time.

I think all of the scoping is still controlled by rustc::middle::region, FWIW (that module should've been renamed whenever the contents were renamed...)

oskgo

oskgo commented on Jul 4, 2024

@oskgo
Contributor

Triage:

The current desugaring of for can be written using loop (#90352), so there should no longer be any special behavior here.

I suspect that the regressions in the crater run would have been rejected by NLL, either because the originals were unsound, or because they hit NLL regressions (#62170), and those are no longer relevant with NLL being on by default. The crates I looked at were all using the 2015 edition, which would have been using Lexical Lifetimes before Rust 1.63.

I think this issue is outdated and should be closed, but I can't be 100% confident with there being no simple original repro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @eddyb@jonas-schievink@petrochenkov@oskgo

        Issue actions

          `for` loop desugaring treats the loop's trailing expression in unusual way · Issue #61902 · rust-lang/rust