@@ -2,7 +2,6 @@ use std::collections::BTreeMap;
22use std:: fmt;
33
44use Context :: * ;
5- use rustc_ast:: Label ;
65use rustc_hir as hir;
76use rustc_hir:: attrs:: AttributeKind ;
87use rustc_hir:: def:: DefKind ;
@@ -42,8 +41,8 @@ enum Context {
4241 ConstBlock ,
4342 /// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`.
4443 LoopMatch {
45- /// The label of the labeled block (not of the loop itself).
46- labeled_block : Label ,
44+ /// The destination pointing to the labeled block (not to the loop itself).
45+ labeled_block : Destination ,
4746 } ,
4847}
4948
@@ -186,18 +185,18 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
186185 {
187186 self . with_context ( UnlabeledBlock ( b. span . shrink_to_lo ( ) ) , |v| v. visit_block ( b) ) ;
188187 }
189- hir:: ExprKind :: Break ( break_label , ref opt_expr) => {
188+ hir:: ExprKind :: Break ( break_destination , ref opt_expr) => {
190189 if let Some ( e) = opt_expr {
191190 self . visit_expr ( e) ;
192191 }
193192
194- if self . require_label_in_labeled_block ( e. span , & break_label , "break" ) {
193+ if self . require_label_in_labeled_block ( e. span , & break_destination , "break" ) {
195194 // If we emitted an error about an unlabeled break in a labeled
196195 // block, we don't need any further checking for this break any more
197196 return ;
198197 }
199198
200- let loop_id = match break_label . target_id {
199+ let loop_id = match break_destination . target_id {
201200 Ok ( loop_id) => Some ( loop_id) ,
202201 Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
203202 Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
@@ -212,18 +211,25 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
212211
213212 // A `#[const_continue]` must break to a block in a `#[loop_match]`.
214213 if find_attr ! ( self . tcx. hir_attrs( e. hir_id) , AttributeKind :: ConstContinue ( _) ) {
215- if let Some ( break_label) = break_label. label {
216- let is_target_label = |cx : & Context | match cx {
217- Context :: LoopMatch { labeled_block } => {
218- break_label. ident . name == labeled_block. ident . name
219- }
220- _ => false ,
221- } ;
214+ let Some ( label) = break_destination. label else {
215+ let span = e. span ;
216+ self . tcx . dcx ( ) . emit_fatal ( ConstContinueBadLabel { span } ) ;
217+ } ;
222218
223- if !self . cx_stack . iter ( ) . rev ( ) . any ( is_target_label) {
224- let span = break_label. ident . span ;
225- self . tcx . dcx ( ) . emit_fatal ( ConstContinueBadLabel { span } ) ;
219+ let is_target_label = |cx : & Context | match cx {
220+ Context :: LoopMatch { labeled_block } => {
221+ // NOTE: with macro expansion, the label's span might be different here
222+ // even though it does still refer to the same HIR node. A block
223+ // can't have two labels, so the hir_id is a unique identifier.
224+ assert ! ( labeled_block. target_id. is_ok( ) ) ; // see `is_loop_match`.
225+ break_destination. target_id == labeled_block. target_id
226226 }
227+ _ => false ,
228+ } ;
229+
230+ if !self . cx_stack . iter ( ) . rev ( ) . any ( is_target_label) {
231+ let span = label. ident . span ;
232+ self . tcx . dcx ( ) . emit_fatal ( ConstContinueBadLabel { span } ) ;
227233 }
228234 }
229235
@@ -249,7 +255,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
249255 Some ( kind) => {
250256 let suggestion = format ! (
251257 "break{}" ,
252- break_label
258+ break_destination
253259 . label
254260 . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
255261 ) ;
@@ -259,7 +265,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
259265 kind : kind. name ( ) ,
260266 suggestion,
261267 loop_label,
262- break_label : break_label . label ,
268+ break_label : break_destination . label ,
263269 break_expr_kind : & break_expr. kind ,
264270 break_expr_span : break_expr. span ,
265271 } ) ;
@@ -268,7 +274,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
268274 }
269275
270276 let sp_lo = e. span . with_lo ( e. span . lo ( ) + BytePos ( "break" . len ( ) as u32 ) ) ;
271- let label_sp = match break_label . label {
277+ let label_sp = match break_destination . label {
272278 Some ( label) => sp_lo. with_hi ( label. ident . span . hi ( ) ) ,
273279 None => sp_lo. shrink_to_lo ( ) ,
274280 } ;
@@ -416,7 +422,7 @@ impl<'hir> CheckLoopVisitor<'hir> {
416422 & self ,
417423 e : & ' hir hir:: Expr < ' hir > ,
418424 body : & ' hir hir:: Block < ' hir > ,
419- ) -> Option < Label > {
425+ ) -> Option < Destination > {
420426 if !find_attr ! ( self . tcx. hir_attrs( e. hir_id) , AttributeKind :: LoopMatch ( _) ) {
421427 return None ;
422428 }
@@ -438,8 +444,8 @@ impl<'hir> CheckLoopVisitor<'hir> {
438444
439445 let hir:: ExprKind :: Assign ( _, rhs_expr, _) = loop_body_expr. kind else { return None } ;
440446
441- let hir:: ExprKind :: Block ( _ , label) = rhs_expr. kind else { return None } ;
447+ let hir:: ExprKind :: Block ( block , label) = rhs_expr. kind else { return None } ;
442448
443- label
449+ Some ( Destination { label, target_id : Ok ( block . hir_id ) } )
444450 }
445451}
0 commit comments