Skip to content
/ rust Public
forked from rust-lang/rust

Commit 712e0e3

Browse files
authored
Rollup merge of rust-lang#133753 - dingxiangfei2009:reduce-false-positive-if-let-rescope, r=jieyouxu
Reduce false positives on some common cases from if-let-rescope lint r? ``@jieyouxu`` We would like to identify a very common case in the ecosystem in which we do not need to apply the lint suggestion for the new Edition 2024 `if let` semantics. In this patch we excluded linting from `if let`s in statements and block tail expressions. In these simple cases, new Edition 2024 drop orders are identical to those of Edition 2021 and prior. However, conservatively we should still lint for the other cases, because [this example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2113df5ce78f161d32a1190faf5c7469) shows that the drop order changes are very pronounced, some of which are even sensitive to runtime data.
2 parents dd03d84 + 2d61c09 commit 712e0e3

File tree

4 files changed

+47
-40
lines changed

4 files changed

+47
-40
lines changed

compiler/rustc_lint/src/if_let_rescope.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,11 @@ fn expr_parent_is_else(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
103103
}
104104

105105
fn expr_parent_is_stmt(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
106-
let Some((_, hir::Node::Stmt(stmt))) = tcx.hir().parent_iter(hir_id).next() else {
107-
return false;
106+
let mut parents = tcx.hir().parent_iter(hir_id);
107+
let stmt = match parents.next() {
108+
Some((_, hir::Node::Stmt(stmt))) => stmt,
109+
Some((_, hir::Node::Block(_) | hir::Node::Arm(_))) => return true,
110+
_ => return false,
108111
};
109112
let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = stmt.kind else { return false };
110113
expr.hir_id == hir_id

tests/ui/drop/lint-if-let-rescope.fixed

+18-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl Drop for Droppy {
1414
}
1515
}
1616
impl Droppy {
17-
fn get(&self) -> Option<u8> {
17+
const fn get(&self) -> Option<u8> {
1818
None
1919
}
2020
}
@@ -62,11 +62,10 @@ fn main() {
6262
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
6363
}
6464

65-
if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } {
66-
//~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
67-
//~| WARN: this changes meaning in Rust 2024
68-
//~| HELP: the value is now dropped here in Edition 2024
69-
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
65+
if let () = { if let Some(_value) = Droppy.get() {} } {
66+
// This should not lint.
67+
// This `if let` sits is a tail expression of a block.
68+
// In Edition 2024, the temporaries are dropped before exiting the surrounding block.
7069
}
7170

7271
#[rustfmt::skip]
@@ -94,4 +93,17 @@ fn main() {
9493
//~| HELP: the value is now dropped here in Edition 2024
9594
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
9695
}
96+
97+
// We want to keep the `if let`s below as direct descendents of match arms,
98+
// so the formatting is suppressed.
99+
#[rustfmt::skip]
100+
match droppy().get() {
101+
_ => if let Some(_value) = droppy().get() {},
102+
// Should not lint
103+
// There is implicitly a block surrounding the `if let`.
104+
// Given that it is a tail expression, the temporaries are dropped duly before
105+
// the execution is exiting the `match`.
106+
}
107+
108+
if let Some(_value) = droppy().get() {}
97109
}

tests/ui/drop/lint-if-let-rescope.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl Drop for Droppy {
1414
}
1515
}
1616
impl Droppy {
17-
fn get(&self) -> Option<u8> {
17+
const fn get(&self) -> Option<u8> {
1818
None
1919
}
2020
}
@@ -63,10 +63,9 @@ fn main() {
6363
}
6464

6565
if let () = { if let Some(_value) = Droppy.get() {} } {
66-
//~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
67-
//~| WARN: this changes meaning in Rust 2024
68-
//~| HELP: the value is now dropped here in Edition 2024
69-
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
66+
// This should not lint.
67+
// This `if let` sits is a tail expression of a block.
68+
// In Edition 2024, the temporaries are dropped before exiting the surrounding block.
7069
}
7170

7271
#[rustfmt::skip]
@@ -94,4 +93,17 @@ fn main() {
9493
//~| HELP: the value is now dropped here in Edition 2024
9594
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
9695
}
96+
97+
// We want to keep the `if let`s below as direct descendents of match arms,
98+
// so the formatting is suppressed.
99+
#[rustfmt::skip]
100+
match droppy().get() {
101+
_ => if let Some(_value) = droppy().get() {},
102+
// Should not lint
103+
// There is implicitly a block surrounding the `if let`.
104+
// Given that it is a tail expression, the temporaries are dropped duly before
105+
// the execution is exiting the `match`.
106+
}
107+
108+
if let Some(_value) = droppy().get() {}
97109
}

tests/ui/drop/lint-if-let-rescope.stderr

+7-27
Original file line numberDiff line numberDiff line change
@@ -112,27 +112,7 @@ LL | if let Some(1) = { match Droppy.get() { Some(_value) => { Some(1) } _ =
112112
| ~~~~~ +++++++++++++++++ ~~~~ +
113113

114114
error: `if let` assigns a shorter lifetime since Edition 2024
115-
--> $DIR/lint-if-let-rescope.rs:65:22
116-
|
117-
LL | if let () = { if let Some(_value) = Droppy.get() {} } {
118-
| ^^^^^^^^^^^^^^^^^^^------^^^^^^
119-
| |
120-
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
121-
|
122-
= warning: this changes meaning in Rust 2024
123-
= note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
124-
help: the value is now dropped here in Edition 2024
125-
--> $DIR/lint-if-let-rescope.rs:65:55
126-
|
127-
LL | if let () = { if let Some(_value) = Droppy.get() {} } {
128-
| ^
129-
help: a `match` with a single arm can preserve the drop order up to Edition 2021
130-
|
131-
LL | if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } {
132-
| ~~~~~ +++++++++++++++++ ++++++++
133-
134-
error: `if let` assigns a shorter lifetime since Edition 2024
135-
--> $DIR/lint-if-let-rescope.rs:73:12
115+
--> $DIR/lint-if-let-rescope.rs:72:12
136116
|
137117
LL | if (if let Some(_value) = droppy().get() { true } else { false }) {
138118
| ^^^^^^^^^^^^^^^^^^^--------^^^^^^
@@ -142,7 +122,7 @@ LL | if (if let Some(_value) = droppy().get() { true } else { false }) {
142122
= warning: this changes meaning in Rust 2024
143123
= note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
144124
help: the value is now dropped here in Edition 2024
145-
--> $DIR/lint-if-let-rescope.rs:73:53
125+
--> $DIR/lint-if-let-rescope.rs:72:53
146126
|
147127
LL | if (if let Some(_value) = droppy().get() { true } else { false }) {
148128
| ^
@@ -152,7 +132,7 @@ LL | if (match droppy().get() { Some(_value) => { true } _ => { false }}) {
152132
| ~~~~~ +++++++++++++++++ ~~~~ +
153133

154134
error: `if let` assigns a shorter lifetime since Edition 2024
155-
--> $DIR/lint-if-let-rescope.rs:79:21
135+
--> $DIR/lint-if-let-rescope.rs:78:21
156136
|
157137
LL | } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
158138
| ^^^^^^^^^^^^^^^^^^^--------^^^^^^
@@ -162,7 +142,7 @@ LL | } else if (((if let Some(_value) = droppy().get() { true } else { false
162142
= warning: this changes meaning in Rust 2024
163143
= note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
164144
help: the value is now dropped here in Edition 2024
165-
--> $DIR/lint-if-let-rescope.rs:79:62
145+
--> $DIR/lint-if-let-rescope.rs:78:62
166146
|
167147
LL | } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
168148
| ^
@@ -172,7 +152,7 @@ LL | } else if (((match droppy().get() { Some(_value) => { true } _ => { fal
172152
| ~~~~~ +++++++++++++++++ ~~~~ +
173153

174154
error: `if let` assigns a shorter lifetime since Edition 2024
175-
--> $DIR/lint-if-let-rescope.rs:91:15
155+
--> $DIR/lint-if-let-rescope.rs:90:15
176156
|
177157
LL | while (if let Some(_value) = droppy().get() { false } else { true }) {
178158
| ^^^^^^^^^^^^^^^^^^^--------^^^^^^
@@ -182,7 +162,7 @@ LL | while (if let Some(_value) = droppy().get() { false } else { true }) {
182162
= warning: this changes meaning in Rust 2024
183163
= note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
184164
help: the value is now dropped here in Edition 2024
185-
--> $DIR/lint-if-let-rescope.rs:91:57
165+
--> $DIR/lint-if-let-rescope.rs:90:57
186166
|
187167
LL | while (if let Some(_value) = droppy().get() { false } else { true }) {
188168
| ^
@@ -191,5 +171,5 @@ help: a `match` with a single arm can preserve the drop order up to Edition 2021
191171
LL | while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
192172
| ~~~~~ +++++++++++++++++ ~~~~ +
193173

194-
error: aborting due to 8 previous errors
174+
error: aborting due to 7 previous errors
195175

0 commit comments

Comments
 (0)