@@ -4,7 +4,7 @@ use clippy_utils::source::{snippet, snippet_indent, snippet_opt};
44use clippy_utils:: ty:: needs_ordered_drop;
55use clippy_utils:: visitors:: any_temporaries_need_ordered_drop;
66use clippy_utils:: { higher, peel_blocks} ;
7- use rustc_ast:: BindingMode ;
7+ use rustc_ast:: { BindingMode , Label } ;
88use rustc_errors:: Applicability ;
99use rustc_hir:: { Block , Expr , ExprKind , LetStmt , MatchSource , Pat , PatKind , Path , QPath , StmtKind , Ty } ;
1010use rustc_lint:: LateContext ;
@@ -26,10 +26,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
2626 _ => return ,
2727 } ;
2828 let has_trailing_exprs = loop_block. stmts . len ( ) + usize:: from ( loop_block. expr . is_some ( ) ) > 1 ;
29-
29+ let loop_label = if let ExprKind :: Loop ( _, label, ..) = expr. kind {
30+ label
31+ } else {
32+ None
33+ } ;
3034 if let Some ( if_let) = higher:: IfLet :: hir ( cx, init)
3135 && let Some ( else_expr) = if_let. if_else
32- && is_simple_break_expr ( else_expr)
36+ && is_simple_break_expr ( else_expr, loop_label )
3337 {
3438 could_be_while_let (
3539 cx,
@@ -40,14 +44,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
4044 let_info,
4145 Some ( if_let. if_then ) ,
4246 ) ;
43- } else if els. is_some_and ( is_simple_break_block)
47+ } else if els. is_some_and ( |b| is_simple_break_block ( b , loop_label ) )
4448 && let Some ( ( pat, _) ) = let_info
4549 {
4650 could_be_while_let ( cx, expr, pat, init, has_trailing_exprs, let_info, None ) ;
4751 } else if let ExprKind :: Match ( scrutinee, [ arm1, arm2] , MatchSource :: Normal ) = init. kind
4852 && arm1. guard . is_none ( )
4953 && arm2. guard . is_none ( )
50- && is_simple_break_expr ( arm2. body )
54+ && is_simple_break_expr ( arm2. body , loop_label )
5155 {
5256 could_be_while_let (
5357 cx,
@@ -61,22 +65,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
6165 }
6266}
6367
64- /// Checks if `block` contains a single unlabeled `break` expression or statement, possibly embedded
65- /// inside other blocks.
66- fn is_simple_break_block ( block : & Block < ' _ > ) -> bool {
68+ /// Checks if `block` contains a single unlabeled and importantly now also a labeled `break`
69+ /// expression or statement, possibly embedded inside other blocks.
70+ fn is_simple_break_block ( block : & Block < ' _ > , looplabel : Option < Label > ) -> bool {
6771 match ( block. stmts , block. expr ) {
68- ( [ s] , None ) => matches ! ( s. kind, StmtKind :: Expr ( e) | StmtKind :: Semi ( e) if is_simple_break_expr( e) ) ,
69- ( [ ] , Some ( e) ) => is_simple_break_expr ( e) ,
72+ ( [ s] , None ) => matches ! ( s. kind, StmtKind :: Expr ( e) | StmtKind :: Semi ( e) if is_simple_break_expr( e, looplabel ) ) ,
73+ ( [ ] , Some ( e) ) => is_simple_break_expr ( e, looplabel ) ,
7074 _ => false ,
7175 }
7276}
7377
74- /// Checks if `expr` contains a single unlabeled `break` expression or statement, possibly embedded
75- /// inside other blocks.
76- fn is_simple_break_expr ( expr : & Expr < ' _ > ) -> bool {
78+ /// Checks if `expr` contains a single unlabeled and importantly now also a labeled `break`
79+ /// expression or statement, possibly embedded inside other blocks.
80+ fn is_simple_break_expr ( expr : & Expr < ' _ > , looplabel : Option < Label > ) -> bool {
7781 match expr. kind {
78- ExprKind :: Block ( b, _) => is_simple_break_block ( b) ,
79- ExprKind :: Break ( dest, None ) => dest. label . is_none ( ) ,
82+ ExprKind :: Block ( b, _) => is_simple_break_block ( b, looplabel ) ,
83+ ExprKind :: Break ( dest, None ) => dest. label . is_none ( ) || dest . label == looplabel ,
8084 _ => false ,
8185 }
8286}
0 commit comments