11use Context :: * ;
22
33use rustc_hir as hir;
4- use rustc_hir:: def_id:: LocalModDefId ;
4+ use rustc_hir:: def_id:: { LocalDefId , LocalModDefId } ;
55use rustc_hir:: intravisit:: { self , Visitor } ;
66use rustc_hir:: { Destination , Movability , Node } ;
77use rustc_middle:: hir:: map:: Map ;
@@ -10,19 +10,21 @@ use rustc_middle::query::Providers;
1010use rustc_middle:: ty:: TyCtxt ;
1111use rustc_session:: Session ;
1212use rustc_span:: hygiene:: DesugaringKind ;
13- use rustc_span:: Span ;
13+ use rustc_span:: { BytePos , Span } ;
1414
1515use crate :: errors:: {
1616 BreakInsideAsyncBlock , BreakInsideClosure , BreakNonLoop , ContinueLabeledBlock , OutsideLoop ,
17- UnlabeledCfInWhileCondition , UnlabeledInLabeledBlock ,
17+ OutsideLoopSuggestion , UnlabeledCfInWhileCondition , UnlabeledInLabeledBlock ,
1818} ;
1919
2020#[ derive( Clone , Copy , Debug , PartialEq ) ]
2121enum Context {
2222 Normal ,
23+ Fn ,
2324 Loop ( hir:: LoopSource ) ,
2425 Closure ( Span ) ,
2526 AsyncClosure ( Span ) ,
27+ UnlabeledBlock ( Span ) ,
2628 LabeledBlock ,
2729 Constant ,
2830}
@@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
6062 self . with_context ( Constant , |v| intravisit:: walk_inline_const ( v, c) ) ;
6163 }
6264
65+ fn visit_fn (
66+ & mut self ,
67+ fk : hir:: intravisit:: FnKind < ' hir > ,
68+ fd : & ' hir hir:: FnDecl < ' hir > ,
69+ b : hir:: BodyId ,
70+ _: Span ,
71+ id : LocalDefId ,
72+ ) {
73+ self . with_context ( Fn , |v| intravisit:: walk_fn ( v, fk, fd, b, id) ) ;
74+ }
75+
76+ fn visit_trait_item ( & mut self , trait_item : & ' hir hir:: TraitItem < ' hir > ) {
77+ self . with_context ( Fn , |v| intravisit:: walk_trait_item ( v, trait_item) ) ;
78+ }
79+
80+ fn visit_impl_item ( & mut self , impl_item : & ' hir hir:: ImplItem < ' hir > ) {
81+ self . with_context ( Fn , |v| intravisit:: walk_impl_item ( v, impl_item) ) ;
82+ }
83+
6384 fn visit_expr ( & mut self , e : & ' hir hir:: Expr < ' hir > ) {
6485 match e. kind {
6586 hir:: ExprKind :: Loop ( ref b, _, source, _) => {
@@ -83,6 +104,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
83104 hir:: ExprKind :: Block ( ref b, Some ( _label) ) => {
84105 self . with_context ( LabeledBlock , |v| v. visit_block ( & b) ) ;
85106 }
107+ hir:: ExprKind :: Block ( ref b, None ) if matches ! ( self . cx, Fn ) => {
108+ self . with_context ( Normal , |v| v. visit_block ( & b) ) ;
109+ }
110+ hir:: ExprKind :: Block ( ref b, None )
111+ if matches ! ( self . cx, Normal | Constant | UnlabeledBlock ( _) ) =>
112+ {
113+ self . with_context ( UnlabeledBlock ( b. span . shrink_to_lo ( ) ) , |v| v. visit_block ( & b) ) ;
114+ }
86115 hir:: ExprKind :: Break ( break_label, ref opt_expr) => {
87116 if let Some ( e) = opt_expr {
88117 self . visit_expr ( e) ;
@@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
147176 }
148177 }
149178
150- self . require_break_cx ( "break" , e. span ) ;
179+ let sp_lo = e. span . with_lo ( e. span . lo ( ) + BytePos ( "break" . len ( ) as u32 ) ) ;
180+ let label_sp = match break_label. label {
181+ Some ( label) => sp_lo. with_hi ( label. ident . span . hi ( ) ) ,
182+ None => sp_lo. shrink_to_lo ( ) ,
183+ } ;
184+ self . require_break_cx ( "break" , e. span , label_sp) ;
151185 }
152186 hir:: ExprKind :: Continue ( destination) => {
153187 self . require_label_in_labeled_block ( e. span , & destination, "continue" ) ;
@@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
169203 }
170204 Err ( _) => { }
171205 }
172- self . require_break_cx ( "continue" , e. span )
206+ self . require_break_cx ( "continue" , e. span , e . span )
173207 }
174208 _ => intravisit:: walk_expr ( self , e) ,
175209 }
@@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
187221 self . cx = old_cx;
188222 }
189223
190- fn require_break_cx ( & self , name : & str , span : Span ) {
224+ fn require_break_cx ( & self , name : & str , span : Span , break_span : Span ) {
225+ let is_break = name == "break" ;
191226 match self . cx {
192227 LabeledBlock | Loop ( _) => { }
193228 Closure ( closure_span) => {
@@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
196231 AsyncClosure ( closure_span) => {
197232 self . sess . emit_err ( BreakInsideAsyncBlock { span, closure_span, name } ) ;
198233 }
199- Normal | Constant => {
200- self . sess . emit_err ( OutsideLoop { span, name, is_break : name == "break" } ) ;
234+ UnlabeledBlock ( block_span) if is_break && block_span. ctxt ( ) == break_span. ctxt ( ) => {
235+ let suggestion = Some ( OutsideLoopSuggestion { block_span, break_span } ) ;
236+ self . sess . emit_err ( OutsideLoop { span, name, is_break, suggestion } ) ;
237+ }
238+ Normal | Constant | Fn | UnlabeledBlock ( _) => {
239+ self . sess . emit_err ( OutsideLoop { span, name, is_break, suggestion : None } ) ;
201240 }
202241 }
203242 }
0 commit comments