@@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
5353
5454 fn visit_expr ( & mut self , e : & ' hir hir:: Expr < ' hir > ) {
5555 match e. kind {
56- hir:: ExprKind :: Loop ( ref b, _, source) => {
56+ hir:: ExprKind :: Loop ( ref b, _, source, _ ) => {
5757 self . with_context ( Loop ( source) , |v| v. visit_block ( & b) ) ;
5858 }
5959 hir:: ExprKind :: Closure ( _, ref function_decl, b, span, movability) => {
@@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
6868 hir:: ExprKind :: Block ( ref b, Some ( _label) ) => {
6969 self . with_context ( LabeledBlock , |v| v. visit_block ( & b) ) ;
7070 }
71- hir:: ExprKind :: Break ( label , ref opt_expr) => {
71+ hir:: ExprKind :: Break ( break_label , ref opt_expr) => {
7272 if let Some ( e) = opt_expr {
7373 self . visit_expr ( e) ;
7474 }
7575
76- if self . require_label_in_labeled_block ( e. span , & label , "break" ) {
76+ if self . require_label_in_labeled_block ( e. span , & break_label , "break" ) {
7777 // If we emitted an error about an unlabeled break in a labeled
7878 // block, we don't need any further checking for this break any more
7979 return ;
8080 }
8181
82- let loop_id = match label . target_id {
82+ let loop_id = match break_label . target_id {
8383 Ok ( loop_id) => Some ( loop_id) ,
8484 Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
8585 Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
@@ -89,49 +89,89 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
8989 Err ( hir:: LoopIdError :: UnresolvedLabel ) => None ,
9090 } ;
9191
92- if let Some ( loop_id) = loop_id {
93- if let Node :: Block ( _) = self . hir_map . find ( loop_id) . unwrap ( ) {
94- return ;
95- }
92+ if let Some ( Node :: Block ( _) ) = loop_id. and_then ( |id| self . hir_map . find ( id) ) {
93+ return ;
9694 }
9795
98- if opt_expr. is_some ( ) {
99- let loop_kind = if let Some ( loop_id) = loop_id {
100- Some ( match self . hir_map . expect_expr ( loop_id) . kind {
101- hir:: ExprKind :: Loop ( _, _, source) => source,
96+ if let Some ( break_expr) = opt_expr {
97+ let ( head, loop_label, loop_kind) = if let Some ( loop_id) = loop_id {
98+ match self . hir_map . expect_expr ( loop_id) . kind {
99+ hir:: ExprKind :: Loop ( _, label, source, sp) => {
100+ ( Some ( sp) , label, Some ( source) )
101+ }
102102 ref r => {
103103 span_bug ! ( e. span, "break label resolved to a non-loop: {:?}" , r)
104104 }
105- } )
105+ }
106106 } else {
107- None
107+ ( None , None , None )
108108 } ;
109109 match loop_kind {
110110 None | Some ( hir:: LoopSource :: Loop ) => ( ) ,
111111 Some ( kind) => {
112- struct_span_err ! (
112+ let mut err = struct_span_err ! (
113113 self . sess,
114114 e. span,
115115 E0571 ,
116116 "`break` with value from a `{}` loop" ,
117117 kind. name( )
118- )
119- . span_label (
118+ ) ;
119+ err . span_label (
120120 e. span ,
121- "can only break with a value inside \
122- `loop` or breakable block",
123- )
124- . span_suggestion (
121+ "can only break with a value inside `loop` or breakable block" ,
122+ ) ;
123+ if let Some ( head) = head {
124+ err. span_label (
125+ head,
126+ & format ! (
127+ "you can't `break` with a value in a `{}` loop" ,
128+ kind. name( )
129+ ) ,
130+ ) ;
131+ }
132+ err. span_suggestion (
125133 e. span ,
126134 & format ! (
127- "instead, use `break` on its own \
128- without a value inside this `{}` loop",
129- kind. name( )
135+ "use `break` on its own without a value inside this `{}` loop" ,
136+ kind. name( ) ,
137+ ) ,
138+ format ! (
139+ "break{}" ,
140+ break_label
141+ . label
142+ . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
130143 ) ,
131- "break" . to_string ( ) ,
132144 Applicability :: MaybeIncorrect ,
133- )
134- . emit ( ) ;
145+ ) ;
146+ if let ( Some ( label) , None ) = ( loop_label, break_label. label ) {
147+ match break_expr. kind {
148+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
149+ None ,
150+ hir:: Path {
151+ segments : [ segment] ,
152+ res : hir:: def:: Res :: Err ,
153+ ..
154+ } ,
155+ ) ) if label. ident . to_string ( )
156+ == format ! ( "'{}" , segment. ident) =>
157+ {
158+ // This error is redundant, we will have already emitted a
159+ // suggestion to use the label when `segment` wasn't found
160+ // (hence the `Res::Err` check).
161+ err. delay_as_bug ( ) ;
162+ }
163+ _ => {
164+ err. span_suggestion (
165+ break_expr. span ,
166+ "alternatively, you might have meant to use the \
167+ available loop label",
168+ label. ident . to_string ( ) ,
169+ Applicability :: MaybeIncorrect ,
170+ ) ;
171+ }
172+ }
173+ }
174+ err. emit ( ) ;
135175 }
136176 }
137177 }
0 commit comments