@@ -352,6 +352,50 @@ emitUnresolvedLabelDiagnostics(DiagnosticEngine &DE,
352
352
}
353
353
}
354
354
355
+ // / Find the target of a break or continue statement without a label.
356
+ // /
357
+ // / \returns the target, if one was found, or \c nullptr if no such target
358
+ // / exists.
359
+ static LabeledStmt *findUnlabeledBreakOrContinueStmtTarget (
360
+ ASTContext &ctx, SourceFile *sourceFile, SourceLoc loc,
361
+ bool isContinue, DeclContext *dc,
362
+ ArrayRef<LabeledStmt *> activeLabeledStmts) {
363
+ for (auto labeledStmt : activeLabeledStmts) {
364
+ // 'break' with no label looks through non-loop structures
365
+ // except 'switch'.
366
+ // 'continue' ignores non-loop structures.
367
+ if (!labeledStmt->requiresLabelOnJump () &&
368
+ (!isContinue || labeledStmt->isPossibleContinueTarget ())) {
369
+ return labeledStmt;
370
+ }
371
+ }
372
+
373
+ // If we're in a defer, produce a tailored diagnostic.
374
+ if (isDefer (dc)) {
375
+ ctx.Diags .diagnose (
376
+ loc, diag::jump_out_of_defer, isContinue ? " continue" : " break" );
377
+ return nullptr ;
378
+ }
379
+
380
+ // If we're dealing with an unlabeled break inside of an 'if' or 'do'
381
+ // statement, produce a more specific error.
382
+ if (!isContinue &&
383
+ llvm::any_of (activeLabeledStmts,
384
+ [&](Stmt *S) -> bool {
385
+ return isa<IfStmt>(S) || isa<DoStmt>(S);
386
+ })) {
387
+ ctx.Diags .diagnose (
388
+ loc, diag::unlabeled_break_outside_loop);
389
+ return nullptr ;
390
+ }
391
+
392
+ // Otherwise produce a generic error.
393
+ ctx.Diags .diagnose (
394
+ loc,
395
+ isContinue ? diag::continue_outside_loop : diag::break_outside_loop);
396
+ return nullptr ;
397
+ }
398
+
355
399
// / Find the target of a break or continue statement.
356
400
// /
357
401
// / \returns the target, if one was found, or \c nullptr if no such target
@@ -361,7 +405,6 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
361
405
SourceLoc loc, Identifier targetName, SourceLoc targetLoc,
362
406
bool isContinue, DeclContext *dc,
363
407
ArrayRef<LabeledStmt *> oldActiveLabeledStmts) {
364
- TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
365
408
366
409
// Retrieve the active set of labeled statements.
367
410
// FIXME: Once everything uses ASTScope lookup, \c oldActiveLabeledStmts
@@ -375,43 +418,37 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
375
418
oldActiveLabeledStmts.rbegin (), oldActiveLabeledStmts.rend ());
376
419
}
377
420
378
- // Pick the nearest break target that matches the specified name .
421
+ // Handle an unlabeled break separately; that's the easy case .
379
422
if (targetName.empty ()) {
380
- for (auto labeledStmt : activeLabeledStmts) {
381
- // 'break' with no label looks through non-loop structures
382
- // except 'switch'.
383
- // 'continue' ignores non-loop structures.
384
- if (!labeledStmt->requiresLabelOnJump () &&
385
- (!isContinue || labeledStmt->isPossibleContinueTarget ())) {
386
- return labeledStmt;
387
- }
388
- }
389
- } else {
390
- // Scan inside out until we find something with the right label.
391
- for (auto labeledStmt : activeLabeledStmts) {
392
- if (targetName == labeledStmt->getLabelInfo ().Name ) {
393
- // Continue cannot be used to repeat switches, use fallthrough instead.
394
- if (isContinue && !labeledStmt->isPossibleContinueTarget ()) {
395
- ctx.Diags .diagnose (
396
- loc, diag::continue_not_in_this_stmt,
397
- isa<SwitchStmt>(labeledStmt) ? " switch" : " if" );
398
- return nullptr ;
399
- }
423
+ return findUnlabeledBreakOrContinueStmtTarget (
424
+ ctx, sourceFile, loc, isContinue, dc, activeLabeledStmts);
425
+ }
400
426
401
- return labeledStmt;
427
+ // Scan inside out until we find something with the right label.
428
+ TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
429
+ for (auto labeledStmt : activeLabeledStmts) {
430
+ if (targetName == labeledStmt->getLabelInfo ().Name ) {
431
+ // Continue cannot be used to repeat switches, use fallthrough instead.
432
+ if (isContinue && !labeledStmt->isPossibleContinueTarget ()) {
433
+ ctx.Diags .diagnose (
434
+ loc, diag::continue_not_in_this_stmt,
435
+ isa<SwitchStmt>(labeledStmt) ? " switch" : " if" );
436
+ return nullptr ;
402
437
}
403
438
404
- unsigned distance =
405
- TypeChecker::getCallEditDistance (
406
- DeclNameRef (targetName),
407
- labeledStmt->getLabelInfo ().Name ,
408
- TypeChecker::UnreasonableCallEditDistance);
409
- if (distance < TypeChecker::UnreasonableCallEditDistance)
410
- labelCorrections.insert (distance, std::move (labeledStmt));
439
+ return labeledStmt;
411
440
}
412
- labelCorrections.filterMaxScoreRange (
413
- TypeChecker::MaxCallEditDistanceFromBestCandidate);
441
+
442
+ unsigned distance =
443
+ TypeChecker::getCallEditDistance (
444
+ DeclNameRef (targetName),
445
+ labeledStmt->getLabelInfo ().Name ,
446
+ TypeChecker::UnreasonableCallEditDistance);
447
+ if (distance < TypeChecker::UnreasonableCallEditDistance)
448
+ labelCorrections.insert (distance, std::move (labeledStmt));
414
449
}
450
+ labelCorrections.filterMaxScoreRange (
451
+ TypeChecker::MaxCallEditDistanceFromBestCandidate);
415
452
416
453
// If we're in a defer, produce a tailored diagnostic.
417
454
if (isDefer (dc)) {
@@ -420,26 +457,6 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
420
457
return nullptr ;
421
458
}
422
459
423
- if (targetName.empty ()) {
424
- // If we're dealing with an unlabeled break inside of an 'if' or 'do'
425
- // statement, produce a more specific error.
426
- if (!isContinue &&
427
- llvm::any_of (activeLabeledStmts,
428
- [&](Stmt *S) -> bool {
429
- return isa<IfStmt>(S) || isa<DoStmt>(S);
430
- })) {
431
- ctx.Diags .diagnose (
432
- loc, diag::unlabeled_break_outside_loop);
433
- return nullptr ;
434
- }
435
-
436
- // Otherwise produce a generic error.
437
- ctx.Diags .diagnose (
438
- loc,
439
- isContinue ? diag::continue_outside_loop : diag::break_outside_loop);
440
- return nullptr ;
441
- }
442
-
443
460
// Provide potential corrections for an incorrect label.
444
461
emitUnresolvedLabelDiagnostics (
445
462
ctx.Diags , targetLoc, targetName, labelCorrections);
0 commit comments