rust-lang / rust-lang/rust

Implicit returns and missing semicolons after `return` might cause a different drop order

Open
#131,313 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-destructors C-discussion T-lang
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code:

struct D(&'static str);
impl Drop for D {
    fn drop(&mut self) {
        println!("dropping {}", self.0);
    }
}

fn f1() {
    println!("===== f1 =====");
    let _local = D("drop initialized first");
    (D("drop initialized second"), ()).1
}

fn f2() {
    println!("===== f2 =====");
    let _local = D("drop initialized first");
    (D("drop initialized second"), ()).1;
}

fn f3() {
    println!("===== f3 =====");
    let _local = D("drop initialized first");
    return (D("drop initialized second"), ()).1
}

fn f4() {
    println!("===== f4 =====");
    let _local = D("drop initialized first");
    return (D("drop initialized second"), ()).1;
}

fn f5() {
    println!("===== f5 =====");
    let _local = D("drop initialized first");
    let result = (D("drop initialized second"), ()).1;
    result
}

fn main() {
    f1();
    f2();
    f3();
    f4();
    f5();
}

I expected to see this happen:
All these functions should do exactly the same. The parameters would be dropped in opposite initialization order.
To my understanding of Rust, implicitly and explicitly returning the last argument should do the same.
Also the semicolon after a return shouldn't make a difference.
And binding the result of something to a variable and then returning it, should also do the same.

Instead, this happened:
f1 and f3 drop parameters in initialization order while f2, f4 and f5 drop parameters in opposite initialization order.
It's especially weird that the semicolon after the return has any effect. cargo fmt will add semicolons after return.
So if this is intentional, there's a bug in cargo fmt. Formatting should never do a semantic change.
So when reproducing this bug, be sure to turn off automatic formatting if you have it enabled.

I also had some discussion with somebody on Reddit.
It seems to be necessary for lifetimes of temporary values to work correctly.

But I still think, this is confusing. So at least the return case should be fixed. The compiler could just implicitly add a semicolon after the return.

And for implicit return values, even if it's just the implicit return value of a subscope, the let transformation (like in f5) should fix the issue.
And since it's possible to generally fiix this with code, I'm sure this can also be fixed in the compiler.

Meta

rustc --version --verbose:

rustc 1.81.0 (eeb90cda1 2024-09-04)
binary: rustc
commit-hash: eeb90cda1969383f56a2637cbd3037bdf598841c
commit-date: 2024-09-04
host: x86_64-unknown-linux-gnu
release: 1.81.0
LLVM version: 18.1.7

(no backtrace available, since it doesn't crash)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported f1–f5 examples with the stated rustc version, comparing behavior with and without semicolons and after cargo fmt. Investigate the compiler's treatment of return expressions, temporaries, and drop order; the issue is done when the intended semantics are agreed and covered by regression tests without formatting changing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.