11use clippy_utils:: diagnostics:: span_lint_and_sugg;
2- use clippy_utils:: visitors:: { for_each_expr, for_each_expr_without_closures} ;
2+ use clippy_utils:: visitors:: { Descend , for_each_expr, for_each_expr_without_closures} ;
33use core:: ops:: ControlFlow ;
44use rustc_data_structures:: fx:: FxHashMap ;
55use rustc_errors:: Applicability ;
66use rustc_hir:: def:: { DefKind , Res } ;
7- use rustc_hir:: { Body , Expr , ExprKind , HirId , LetStmt , PatKind , StmtKind } ;
7+ use rustc_hir:: { BlockCheckMode , Body , Expr , ExprKind , HirId , LetStmt , PatKind , StmtKind , UnsafeSource } ;
88use rustc_lint:: LateContext ;
99use rustc_middle:: ty:: { Ty , TypeVisitableExt } ;
1010use rustc_span:: Span ;
@@ -55,7 +55,11 @@ fn collect_binding_from_let<'a>(
5555 let_expr : & rustc_hir:: LetExpr < ' a > ,
5656 bindings : & mut FxHashMap < HirId , BindingInfo < ' a > > ,
5757) {
58- if let_expr. ty . is_none ( ) || let_expr. span . from_expansion ( ) || has_generic_return_type ( cx, let_expr. init ) {
58+ if let_expr. ty . is_none ( )
59+ || let_expr. span . from_expansion ( )
60+ || has_generic_return_type ( cx, let_expr. init )
61+ || contains_unsafe ( let_expr. init )
62+ {
5963 return ;
6064 }
6165
@@ -82,7 +86,9 @@ fn collect_binding_from_local<'a>(
8286) {
8387 if let_stmt. ty . is_none ( )
8488 || let_stmt. span . from_expansion ( )
85- || let_stmt. init . is_some_and ( |init| has_generic_return_type ( cx, init) )
89+ || let_stmt
90+ . init
91+ . is_some_and ( |init| has_generic_return_type ( cx, init) || contains_unsafe ( init) )
8692 {
8793 return ;
8894 }
@@ -103,8 +109,48 @@ fn collect_binding_from_local<'a>(
103109 }
104110}
105111
112+ fn contains_unsafe ( expr : & Expr < ' _ > ) -> bool {
113+ for_each_expr_without_closures ( expr, |e| {
114+ if let ExprKind :: Block ( block, _) = e. kind
115+ && let BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) = block. rules
116+ {
117+ return ControlFlow :: Break ( ( ) ) ;
118+ }
119+ ControlFlow :: Continue ( ( ) )
120+ } )
121+ . is_some ( )
122+ }
123+
106124fn has_generic_return_type ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
107125 match & expr. kind {
126+ ExprKind :: Block ( block, _) => {
127+ if let Some ( tail_expr) = block. expr {
128+ return has_generic_return_type ( cx, tail_expr) ;
129+ }
130+ false
131+ } ,
132+ ExprKind :: If ( _, then_block, else_expr) => {
133+ has_generic_return_type ( cx, then_block) || else_expr. is_some_and ( |e| has_generic_return_type ( cx, e) )
134+ } ,
135+ ExprKind :: Match ( _, arms, _) => arms. iter ( ) . any ( |arm| has_generic_return_type ( cx, arm. body ) ) ,
136+ ExprKind :: Loop ( block, label, ..) => for_each_expr_without_closures ( * block, |e| {
137+ match e. kind {
138+ ExprKind :: Loop ( ..) => {
139+ // Unlabeled breaks inside nested loops target the inner loop, not ours
140+ return ControlFlow :: Continue ( Descend :: No ) ;
141+ } ,
142+ ExprKind :: Break ( dest, Some ( break_expr) ) => {
143+ let targets_this_loop =
144+ dest. label . is_none ( ) || dest. label . map ( |l| l. ident ) == label. map ( |l| l. ident ) ;
145+ if targets_this_loop && has_generic_return_type ( cx, break_expr) {
146+ return ControlFlow :: Break ( ( ) ) ;
147+ }
148+ } ,
149+ _ => { } ,
150+ }
151+ ControlFlow :: Continue ( Descend :: Yes )
152+ } )
153+ . is_some ( ) ,
108154 ExprKind :: MethodCall ( ..) => {
109155 if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
110156 let sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
@@ -158,7 +204,6 @@ fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) ->
158204 match parent {
159205 rustc_hir:: Node :: Expr ( parent_expr) => {
160206 match & parent_expr. kind {
161- // Closure body is a separate type inference context
162207 ExprKind :: Closure ( _) => return false ,
163208 ExprKind :: Call ( callee, _) => {
164209 if let ExprKind :: Path ( qpath) = & callee. kind {
0 commit comments