11use Context :: * ;
22
3- use rustc_errors:: { struct_span_err, Applicability } ;
43use rustc_hir as hir;
54use rustc_hir:: def_id:: LocalDefId ;
65use rustc_hir:: intravisit:: { self , Visitor } ;
@@ -13,6 +12,11 @@ use rustc_session::Session;
1312use rustc_span:: hygiene:: DesugaringKind ;
1413use rustc_span:: Span ;
1514
15+ use crate :: errors:: {
16+ BreakInsideAsyncBlock , BreakInsideClosure , BreakNonLoop , ContinueLabeledBlock , OutsideLoop ,
17+ UnlabeledCfInWhileCondition , UnlabeledInLabeledBlock ,
18+ } ;
19+
1620#[ derive( Clone , Copy , Debug , PartialEq ) ]
1721enum Context {
1822 Normal ,
@@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
9094 Ok ( loop_id) => Some ( loop_id) ,
9195 Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
9296 Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
93- self . emit_unlabled_cf_in_while_condition ( e. span , "break" ) ;
97+ self . sess . emit_err ( UnlabeledCfInWhileCondition {
98+ span : e. span ,
99+ cf_type : "break" ,
100+ } ) ;
94101 None
95102 }
96103 Err ( hir:: LoopIdError :: UnresolvedLabel ) => None ,
@@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
116123 match loop_kind {
117124 None | Some ( hir:: LoopSource :: Loop ) => ( ) ,
118125 Some ( kind) => {
119- let mut err = struct_span_err ! (
120- self . sess,
121- e. span,
122- E0571 ,
123- "`break` with value from a `{}` loop" ,
124- kind. name( )
125- ) ;
126- err. span_label (
127- e. span ,
128- "can only break with a value inside `loop` or breakable block" ,
126+ let suggestion = format ! (
127+ "break{}" ,
128+ break_label
129+ . label
130+ . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
129131 ) ;
130- if let Some ( head) = head {
131- err. span_label (
132- head,
133- & format ! (
134- "you can't `break` with a value in a `{}` loop" ,
135- kind. name( )
136- ) ,
137- ) ;
138- }
139- err. span_suggestion (
140- e. span ,
141- & format ! (
142- "use `break` on its own without a value inside this `{}` loop" ,
143- kind. name( ) ,
144- ) ,
145- format ! (
146- "break{}" ,
147- break_label
148- . label
149- . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
150- ) ,
151- Applicability :: MaybeIncorrect ,
152- ) ;
153- if let ( Some ( label) , None ) = ( loop_label, break_label. label ) {
154- match break_expr. kind {
155- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
156- None ,
157- hir:: Path {
158- segments : [ segment] ,
159- res : hir:: def:: Res :: Err ,
160- ..
161- } ,
162- ) ) if label. ident . to_string ( )
163- == format ! ( "'{}" , segment. ident) =>
164- {
165- // This error is redundant, we will have already emitted a
166- // suggestion to use the label when `segment` wasn't found
167- // (hence the `Res::Err` check).
168- err. delay_as_bug ( ) ;
169- }
170- _ => {
171- err. span_suggestion (
172- break_expr. span ,
173- "alternatively, you might have meant to use the \
174- available loop label",
175- label. ident ,
176- Applicability :: MaybeIncorrect ,
177- ) ;
178- }
179- }
180- }
181- err. emit ( ) ;
132+ self . sess . emit_err ( BreakNonLoop {
133+ span : e. span ,
134+ head,
135+ kind : kind. name ( ) ,
136+ suggestion,
137+ loop_label,
138+ break_label : break_label. label ,
139+ break_expr_kind : & break_expr. kind ,
140+ break_expr_span : break_expr. span ,
141+ } ) ;
182142 }
183143 }
184144 }
@@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
191151 match destination. target_id {
192152 Ok ( loop_id) => {
193153 if let Node :: Block ( block) = self . hir_map . find ( loop_id) . unwrap ( ) {
194- struct_span_err ! (
195- self . sess,
196- e. span,
197- E0696 ,
198- "`continue` pointing to a labeled block"
199- )
200- . span_label ( e. span , "labeled blocks cannot be `continue`'d" )
201- . span_label ( block. span , "labeled block the `continue` points to" )
202- . emit ( ) ;
154+ self . sess . emit_err ( ContinueLabeledBlock {
155+ span : e. span ,
156+ block_span : block. span ,
157+ } ) ;
203158 }
204159 }
205160 Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
206- self . emit_unlabled_cf_in_while_condition ( e. span , "continue" ) ;
161+ self . sess . emit_err ( UnlabeledCfInWhileCondition {
162+ span : e. span ,
163+ cf_type : "continue" ,
164+ } ) ;
207165 }
208166 Err ( _) => { }
209167 }
@@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
226184 }
227185
228186 fn require_break_cx ( & self , name : & str , span : Span ) {
229- let err_inside_of = |article, ty, closure_span| {
230- struct_span_err ! ( self . sess, span, E0267 , "`{}` inside of {} {}" , name, article, ty)
231- . span_label ( span, format ! ( "cannot `{}` inside of {} {}" , name, article, ty) )
232- . span_label ( closure_span, & format ! ( "enclosing {}" , ty) )
233- . emit ( ) ;
234- } ;
235-
236187 match self . cx {
237188 LabeledBlock | Loop ( _) => { }
238- Closure ( closure_span) => err_inside_of ( "a" , "closure" , closure_span) ,
239- AsyncClosure ( closure_span) => err_inside_of ( "an" , "`async` block" , closure_span) ,
189+ Closure ( closure_span) => {
190+ self . sess . emit_err ( BreakInsideClosure { span, closure_span, name } ) ;
191+ }
192+ AsyncClosure ( closure_span) => {
193+ self . sess . emit_err ( BreakInsideAsyncBlock { span, closure_span, name } ) ;
194+ }
240195 Normal | AnonConst => {
241- struct_span_err ! ( self . sess, span, E0268 , "`{}` outside of a loop" , name)
242- . span_label ( span, format ! ( "cannot `{}` outside of a loop" , name) )
243- . emit ( ) ;
196+ self . sess . emit_err ( OutsideLoop { span, name } ) ;
244197 }
245198 }
246199 }
@@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
251204 label : & Destination ,
252205 cf_type : & str ,
253206 ) -> bool {
254- if !span. is_desugaring ( DesugaringKind :: QuestionMark ) && self . cx == LabeledBlock {
255- if label. label . is_none ( ) {
256- struct_span_err ! (
257- self . sess,
258- span,
259- E0695 ,
260- "unlabeled `{}` inside of a labeled block" ,
261- cf_type
262- )
263- . span_label (
264- span,
265- format ! (
266- "`{}` statements that would diverge to or through \
267- a labeled block need to bear a label",
268- cf_type
269- ) ,
270- )
271- . emit ( ) ;
272- return true ;
273- }
207+ if !span. is_desugaring ( DesugaringKind :: QuestionMark )
208+ && self . cx == LabeledBlock
209+ && label. label . is_none ( )
210+ {
211+ self . sess . emit_err ( UnlabeledInLabeledBlock { span, cf_type } ) ;
212+ return true ;
274213 }
275214 false
276215 }
277- fn emit_unlabled_cf_in_while_condition ( & mut self , span : Span , cf_type : & str ) {
278- struct_span_err ! (
279- self . sess,
280- span,
281- E0590 ,
282- "`break` or `continue` with no label in the condition of a `while` loop"
283- )
284- . span_label ( span, format ! ( "unlabeled `{}` in the condition of a `while` loop" , cf_type) )
285- . emit ( ) ;
286- }
287216}
0 commit comments