Skip to content

Commit a8b0e5f

Browse files
committed
Auto merge of rust-lang#11627 - y21:issue11616, r=giraffate
[`needless_return_with_question_mark`]: don't lint if never type is used for coercion Fixes rust-lang#11616 When we have something like ```rs let _x: String = { return Err(())?; }; ``` we shouldn't suggest removing the `return` because the `!`-ness of `return` is used to coerce the enclosing block to some other type. That will lead to a typeck error without a diverging expression like `return`. changelog: [`needless_return_with_question_mark`]: don't lint if `return`s never typed-ness is used for coercion
2 parents 4d56366 + a74fa97 commit a8b0e5f

4 files changed

+64
-3
lines changed

clippy_lints/src/returns.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use core::ops::ControlFlow;
77
use rustc_errors::Applicability;
88
use rustc_hir::intravisit::FnKind;
99
use rustc_hir::{
10-
Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
10+
Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
11+
StmtKind,
1112
};
1213
use rustc_lint::{LateContext, LateLintPass, LintContext};
1314
use rustc_middle::lint::in_external_macro;
15+
use rustc_middle::ty::adjustment::Adjust;
1416
use rustc_middle::ty::{self, GenericArgKind, Ty};
1517
use rustc_session::{declare_lint_pass, declare_tool_lint};
1618
use rustc_span::def_id::LocalDefId;
@@ -158,6 +160,22 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
158160

159161
declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
160162

163+
/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This
164+
/// is the case when the enclosing block expression is coerced to some other type, which only works
165+
/// because of the never-ness of `return` expressions
166+
fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
167+
cx.tcx
168+
.hir()
169+
.parent_iter(stmt_hir_id)
170+
.find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
171+
.is_some_and(|e| {
172+
cx.typeck_results()
173+
.expr_adjustments(e)
174+
.iter()
175+
.any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
176+
})
177+
}
178+
161179
impl<'tcx> LateLintPass<'tcx> for Return {
162180
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
163181
if !in_external_macro(cx.sess(), stmt.span)
@@ -173,6 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
173191
&& let [.., final_stmt] = block.stmts
174192
&& final_stmt.hir_id != stmt.hir_id
175193
&& !is_from_proc_macro(cx, expr)
194+
&& !stmt_needs_never_type(cx, stmt.hir_id)
176195
{
177196
span_lint_and_sugg(
178197
cx,

tests/ui/needless_return_with_question_mark.fixed

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
clippy::unit_arg,
66
clippy::useless_conversion,
77
clippy::diverging_sub_expression,
8+
clippy::let_unit_value,
89
unused
910
)]
1011

@@ -59,3 +60,20 @@ fn main() -> Result<(), ()> {
5960

6061
Err(())
6162
}
63+
64+
fn issue11616() -> Result<(), ()> {
65+
let _x: String = {
66+
return Err(())?;
67+
};
68+
let _x: () = {
69+
Err(())?;
70+
//~^ ERROR: unneeded `return` statement with `?` operator
71+
};
72+
let _x = match 1 {
73+
1 => vec![1, 2],
74+
_ => {
75+
return Err(())?;
76+
},
77+
};
78+
Ok(())
79+
}

tests/ui/needless_return_with_question_mark.rs

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
clippy::unit_arg,
66
clippy::useless_conversion,
77
clippy::diverging_sub_expression,
8+
clippy::let_unit_value,
89
unused
910
)]
1011

@@ -59,3 +60,20 @@ fn main() -> Result<(), ()> {
5960

6061
Err(())
6162
}
63+
64+
fn issue11616() -> Result<(), ()> {
65+
let _x: String = {
66+
return Err(())?;
67+
};
68+
let _x: () = {
69+
return Err(())?;
70+
//~^ ERROR: unneeded `return` statement with `?` operator
71+
};
72+
let _x = match 1 {
73+
1 => vec![1, 2],
74+
_ => {
75+
return Err(())?;
76+
},
77+
};
78+
Ok(())
79+
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
error: unneeded `return` statement with `?` operator
2-
--> $DIR/needless_return_with_question_mark.rs:28:5
2+
--> $DIR/needless_return_with_question_mark.rs:29:5
33
|
44
LL | return Err(())?;
55
| ^^^^^^^ help: remove it
66
|
77
= note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::needless_return_with_question_mark)]`
99

10-
error: aborting due to previous error
10+
error: unneeded `return` statement with `?` operator
11+
--> $DIR/needless_return_with_question_mark.rs:69:9
12+
|
13+
LL | return Err(())?;
14+
| ^^^^^^^ help: remove it
15+
16+
error: aborting due to 2 previous errors
1117

0 commit comments

Comments
 (0)