@@ -7,10 +7,12 @@ use core::ops::ControlFlow;
7
7
use rustc_errors:: Applicability ;
8
8
use rustc_hir:: intravisit:: FnKind ;
9
9
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 ,
11
12
} ;
12
13
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
13
14
use rustc_middle:: lint:: in_external_macro;
15
+ use rustc_middle:: ty:: adjustment:: Adjust ;
14
16
use rustc_middle:: ty:: { self , GenericArgKind , Ty } ;
15
17
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
16
18
use rustc_span:: def_id:: LocalDefId ;
@@ -158,6 +160,22 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
158
160
159
161
declare_lint_pass ! ( Return => [ LET_AND_RETURN , NEEDLESS_RETURN , NEEDLESS_RETURN_WITH_QUESTION_MARK ] ) ;
160
162
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
+
161
179
impl < ' tcx > LateLintPass < ' tcx > for Return {
162
180
fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
163
181
if !in_external_macro ( cx. sess ( ) , stmt. span )
@@ -173,6 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
173
191
&& let [ .., final_stmt] = block. stmts
174
192
&& final_stmt. hir_id != stmt. hir_id
175
193
&& !is_from_proc_macro ( cx, expr)
194
+ && !stmt_needs_never_type ( cx, stmt. hir_id )
176
195
{
177
196
span_lint_and_sugg (
178
197
cx,
0 commit comments