@@ -2,7 +2,6 @@ use std::collections::BTreeMap;
2
2
use std:: fmt;
3
3
4
4
use Context :: * ;
5
- use rustc_ast:: Label ;
6
5
use rustc_hir as hir;
7
6
use rustc_hir:: attrs:: AttributeKind ;
8
7
use rustc_hir:: def:: DefKind ;
@@ -42,8 +41,8 @@ enum Context {
42
41
ConstBlock ,
43
42
/// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`.
44
43
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 ,
47
46
} ,
48
47
}
49
48
@@ -186,18 +185,18 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
186
185
{
187
186
self . with_context ( UnlabeledBlock ( b. span . shrink_to_lo ( ) ) , |v| v. visit_block ( b) ) ;
188
187
}
189
- hir:: ExprKind :: Break ( break_label , ref opt_expr) => {
188
+ hir:: ExprKind :: Break ( break_destination , ref opt_expr) => {
190
189
if let Some ( e) = opt_expr {
191
190
self . visit_expr ( e) ;
192
191
}
193
192
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" ) {
195
194
// If we emitted an error about an unlabeled break in a labeled
196
195
// block, we don't need any further checking for this break any more
197
196
return ;
198
197
}
199
198
200
- let loop_id = match break_label . target_id {
199
+ let loop_id = match break_destination . target_id {
201
200
Ok ( loop_id) => Some ( loop_id) ,
202
201
Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
203
202
Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
@@ -212,18 +211,25 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
212
211
213
212
// A `#[const_continue]` must break to a block in a `#[loop_match]`.
214
213
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
+ } ;
222
218
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
226
226
}
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 } ) ;
227
233
}
228
234
}
229
235
@@ -249,7 +255,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
249
255
Some ( kind) => {
250
256
let suggestion = format ! (
251
257
"break{}" ,
252
- break_label
258
+ break_destination
253
259
. label
254
260
. map_or_else( String :: new, |l| format!( " {}" , l. ident) )
255
261
) ;
@@ -259,7 +265,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
259
265
kind : kind. name ( ) ,
260
266
suggestion,
261
267
loop_label,
262
- break_label : break_label . label ,
268
+ break_label : break_destination . label ,
263
269
break_expr_kind : & break_expr. kind ,
264
270
break_expr_span : break_expr. span ,
265
271
} ) ;
@@ -268,7 +274,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
268
274
}
269
275
270
276
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 {
272
278
Some ( label) => sp_lo. with_hi ( label. ident . span . hi ( ) ) ,
273
279
None => sp_lo. shrink_to_lo ( ) ,
274
280
} ;
@@ -416,7 +422,7 @@ impl<'hir> CheckLoopVisitor<'hir> {
416
422
& self ,
417
423
e : & ' hir hir:: Expr < ' hir > ,
418
424
body : & ' hir hir:: Block < ' hir > ,
419
- ) -> Option < Label > {
425
+ ) -> Option < Destination > {
420
426
if !find_attr ! ( self . tcx. hir_attrs( e. hir_id) , AttributeKind :: LoopMatch ( _) ) {
421
427
return None ;
422
428
}
@@ -438,8 +444,8 @@ impl<'hir> CheckLoopVisitor<'hir> {
438
444
439
445
let hir:: ExprKind :: Assign ( _, rhs_expr, _) = loop_body_expr. kind else { return None } ;
440
446
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 } ;
442
448
443
- label
449
+ Some ( Destination { label, target_id : Ok ( block . hir_id ) } )
444
450
}
445
451
}
0 commit comments