Skip to content
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

Scrutinee dropped after if-let body #133677

Open
Aquam4n opened this issue Nov 30, 2024 · 6 comments
Open

Scrutinee dropped after if-let body #133677

Aquam4n opened this issue Nov 30, 2024 · 6 comments
Labels
A-lifetimes Area: Lifetimes / regions C-discussion Category: Discussion or questions that doesn't represent real issues. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Aquam4n
Copy link

Aquam4n commented Nov 30, 2024

Objects inside block expressions in the scrutinee of an if-let statement are not dropped before the body.

This is inconsistent both with declaring a temporary variable, e.g. x in test #2, and let-else behavior in test #3.

I tried this code:

fn main() {
	struct S(i32);
	impl Drop for S {
		fn drop(&mut self) {
			println!("Dropped S {}", self.0)
		}
	}

	println!("--- test 1");
	{
		println!("Before if-let");
		if let _ = { S(1).0 } {
			println!("Inside body");
		}
	}

	println!("--- test 2");
	{
		println!("Before if-let");
		let x = { S(2).0 };
		if let _ = x {
			println!("Inside body");
		}
	}

	println!("--- test 3");
	{
		println!("Before let-else");
		let _ = ({ S(3).0 }) else { unreachable!() };
		println!("After let-else");
	}
}

I expected to see this happen:

--- test 1
Before if-let
Dropped S 1
Inside body
--- test 2
Before if-let
Dropped S 2
Inside body
--- test 3
Before let-else
Dropped S 3
After let-else

Instead, this happened:

--- test 1
Before if-let
Inside body
Dropped S 1
--- test 2
Before if-let
Dropped S 2
Inside body
--- test 3
Before let-else
Dropped S 3
After let-else

Meta

Same behavior on both stable and nightly.

rustc --version --verbose:

rustc 1.82.0 (f6e511eec 2024-10-15)
binary: rustc
commit-hash: f6e511eec7342f59a25f7c0534f1dbea00d01b14
commit-date: 2024-10-15
host: x86_64-unknown-linux-gnu
release: 1.82.0
LLVM version: 19.1.1
@Aquam4n Aquam4n added the C-bug Category: This is a bug. label Nov 30, 2024
@theemathas
Copy link
Contributor

This is working as intended. For related discussion, see https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html and #131154

@Aquam4n
Copy link
Author

Aquam4n commented Dec 1, 2024

This is working as intended. For related discussion, see https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html and #131154

No. Allow me to elucidate. Temporaries in the scrutinee are not the same as temporaries inside a block expression in the scrutinee.

Take a look at:

fn main() {
	struct S(i32);
	impl Drop for S {
		fn drop(&mut self) {
			println!("Dropped S {}", self.0)
		}
	}

	println!("--- test 4");
	{
		println!("Before if-let");
		if let _ = { S(4).0 } {
			println!("Inside body");
		}
	}
	println!("--- test 5");
	{
		println!("Before if-let");
		if let _ = { let x = S(5).0; x } {
			println!("Inside body");
		}
	}
}

This prints

--- test 4
Before if-let
Inside body
Dropped S 4
--- test 5
Before if-let
Dropped S 5
Inside body

, it should print

--- test 4
Before if-let
Dropped S 4
Inside body
--- test 5
Before if-let
Dropped S 5
Inside body

@theemathas
Copy link
Contributor

@rustbot labels +needs-triage

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Dec 1, 2024
@bjorn3
Copy link
Member

bjorn3 commented Dec 1, 2024

@Aquam4n
Copy link
Author

Aquam4n commented Dec 1, 2024

Everything works they way you expect in the 2024 edition: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=c7245eb79cc6379d3cc19875401925ad So this is indeed fixed by https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html

It does work, but it's not supposed to according to this description:

The 2024 Edition shortens the lifetime of the temporaries to the point where the then-block is completely evaluated or the program control enters the else block.

Maybe block expressions in the scrutinee were fixed by accident in the 2024 edition?

Also, it isn't fixed by that, it just so happens to be fixed for some reason. Again, temporaries in the scrutinee are unrelated to temporaries in block expressions in the scrutinee.

@bjorn3
Copy link
Member

bjorn3 commented Dec 1, 2024

I think both https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html and https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html individually fixed this. Before the latter change all temporaries of the tail expression of a block had their lifetime extended to match the context within which the block appeared, so before https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html let a = { S(1).0 } is supposed to have the exact same lifetimes as let a = S(1).0 and by extension if let _ = { S(1).0 } is supposed to have the same lifetimes as if let _ = S(1).0, which before https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html would drop S after the end of the if statement.

@lolbinarycat lolbinarycat added A-lifetimes Area: Lifetimes / regions T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Dec 1, 2024
@jieyouxu jieyouxu added C-discussion Category: Discussion or questions that doesn't represent real issues. and removed C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Dec 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions C-discussion Category: Discussion or questions that doesn't represent real issues. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants