@@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
53
53
54
54
fn visit_expr ( & mut self , e : & ' hir hir:: Expr < ' hir > ) {
55
55
match e. kind {
56
- hir:: ExprKind :: Loop ( ref b, _, source) => {
56
+ hir:: ExprKind :: Loop ( ref b, _, source, _ ) => {
57
57
self . with_context ( Loop ( source) , |v| v. visit_block ( & b) ) ;
58
58
}
59
59
hir:: ExprKind :: Closure ( _, ref function_decl, b, span, movability) => {
@@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
68
68
hir:: ExprKind :: Block ( ref b, Some ( _label) ) => {
69
69
self . with_context ( LabeledBlock , |v| v. visit_block ( & b) ) ;
70
70
}
71
- hir:: ExprKind :: Break ( label , ref opt_expr) => {
71
+ hir:: ExprKind :: Break ( break_label , ref opt_expr) => {
72
72
if let Some ( e) = opt_expr {
73
73
self . visit_expr ( e) ;
74
74
}
75
75
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" ) {
77
77
// If we emitted an error about an unlabeled break in a labeled
78
78
// block, we don't need any further checking for this break any more
79
79
return ;
80
80
}
81
81
82
- let loop_id = match label . target_id {
82
+ let loop_id = match break_label . target_id {
83
83
Ok ( loop_id) => Some ( loop_id) ,
84
84
Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
85
85
Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
@@ -89,49 +89,89 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
89
89
Err ( hir:: LoopIdError :: UnresolvedLabel ) => None ,
90
90
} ;
91
91
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 ;
96
94
}
97
95
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
+ }
102
102
ref r => {
103
103
span_bug ! ( e. span, "break label resolved to a non-loop: {:?}" , r)
104
104
}
105
- } )
105
+ }
106
106
} else {
107
- None
107
+ ( None , None , None )
108
108
} ;
109
109
match loop_kind {
110
110
None | Some ( hir:: LoopSource :: Loop ) => ( ) ,
111
111
Some ( kind) => {
112
- struct_span_err ! (
112
+ let mut err = struct_span_err ! (
113
113
self . sess,
114
114
e. span,
115
115
E0571 ,
116
116
"`break` with value from a `{}` loop" ,
117
117
kind. name( )
118
- )
119
- . span_label (
118
+ ) ;
119
+ err . span_label (
120
120
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 (
125
133
e. span ,
126
134
& 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) )
130
143
) ,
131
- "break" . to_string ( ) ,
132
144
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 ( ) ;
135
175
}
136
176
}
137
177
}
0 commit comments