@@ -347,36 +347,47 @@ emitUnresolvedLabelDiagnostics(DiagnosticEngine &DE,
347
347
}
348
348
}
349
349
350
- // / Find the target of a break statement.
350
+ // / Find the target of a break or continue statement.
351
351
// /
352
352
// / \returns the target, if one was found, or \c nullptr if no such target
353
353
// / exists.
354
- static LabeledStmt *findBreakStmtTarget (
355
- ASTContext &ctx, SourceFile *sourceFile, BreakStmt *breakStmt,
354
+ static LabeledStmt *findBreakOrContinueStmtTarget (
355
+ ASTContext &ctx, SourceFile *sourceFile,
356
+ SourceLoc loc, Identifier targetName, SourceLoc targetLoc,
357
+ bool isContinue,
356
358
Optional<AnyFunctionRef> enclosingFunc) {
357
359
TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
358
360
359
361
// Pick the nearest break target that matches the specified name.
360
- auto activeLabeledStmts = ASTScope::lookupLabeledStmts (
361
- sourceFile, breakStmt->getStartLoc ());
362
- if (breakStmt->getTargetName ().empty ()) {
362
+ auto activeLabeledStmts = ASTScope::lookupLabeledStmts (sourceFile, loc);
363
+ if (targetName.empty ()) {
363
364
for (auto labeledStmt : activeLabeledStmts) {
364
365
// 'break' with no label looks through non-loop structures
365
366
// except 'switch'.
366
- if (!labeledStmt->requiresLabelOnJump ()) {
367
+ // 'continue' ignores non-loop structures.
368
+ if (!labeledStmt->requiresLabelOnJump () &&
369
+ (!isContinue || labeledStmt->isPossibleContinueTarget ())) {
367
370
return labeledStmt;
368
371
}
369
372
}
370
373
} else {
371
374
// Scan inside out until we find something with the right label.
372
375
for (auto labeledStmt : activeLabeledStmts) {
373
- if (breakStmt->getTargetName () == labeledStmt->getLabelInfo ().Name ) {
376
+ if (targetName == labeledStmt->getLabelInfo ().Name ) {
377
+ // Continue cannot be used to repeat switches, use fallthrough instead.
378
+ if (isContinue && !labeledStmt->isPossibleContinueTarget ()) {
379
+ ctx.Diags .diagnose (
380
+ loc, diag::continue_not_in_this_stmt,
381
+ isa<SwitchStmt>(labeledStmt) ? " switch" : " if" );
382
+ return nullptr ;
383
+ }
384
+
374
385
return labeledStmt;
375
386
}
376
387
377
388
unsigned distance =
378
389
TypeChecker::getCallEditDistance (
379
- DeclNameRef (breakStmt-> getTargetName () ),
390
+ DeclNameRef (targetName ),
380
391
labeledStmt->getLabelInfo ().Name ,
381
392
TypeChecker::UnreasonableCallEditDistance);
382
393
if (distance < TypeChecker::UnreasonableCallEditDistance)
@@ -389,31 +400,33 @@ static LabeledStmt *findBreakStmtTarget(
389
400
// If we're in a defer, produce a tailored diagnostic.
390
401
if (isDefer (enclosingFunc)) {
391
402
ctx.Diags .diagnose (
392
- breakStmt-> getLoc () , diag::jump_out_of_defer, " break" );
403
+ loc , diag::jump_out_of_defer, isContinue ? " continue " : " break" );
393
404
return nullptr ;
394
405
}
395
406
396
- if (breakStmt-> getTargetName () .empty ()) {
407
+ if (targetName .empty ()) {
397
408
// If we're dealing with an unlabeled break inside of an 'if' or 'do'
398
409
// statement, produce a more specific error.
399
- if (llvm::any_of (activeLabeledStmts,
410
+ if (!isContinue &&
411
+ llvm::any_of (activeLabeledStmts,
400
412
[&](Stmt *S) -> bool {
401
413
return isa<IfStmt>(S) || isa<DoStmt>(S);
402
414
})) {
403
415
ctx.Diags .diagnose (
404
- breakStmt-> getLoc () , diag::unlabeled_break_outside_loop);
416
+ loc , diag::unlabeled_break_outside_loop);
405
417
return nullptr ;
406
418
}
407
419
408
420
// Otherwise produce a generic error.
409
- ctx.Diags .diagnose (breakStmt->getLoc (), diag::break_outside_loop);
421
+ ctx.Diags .diagnose (
422
+ loc,
423
+ isContinue ? diag::continue_outside_loop : diag::break_outside_loop);
410
424
return nullptr ;
411
425
}
412
426
413
427
// Provide potential corrections for an incorrect label.
414
428
emitUnresolvedLabelDiagnostics (
415
- ctx.Diags , breakStmt->getTargetLoc (), breakStmt->getTargetName (),
416
- labelCorrections);
429
+ ctx.Diags , targetLoc, targetName, labelCorrections);
417
430
return nullptr ;
418
431
}
419
432
@@ -842,72 +855,24 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
842
855
}
843
856
844
857
Stmt *visitBreakStmt (BreakStmt *S) {
845
- if (auto target = findBreakStmtTarget (getASTContext (), DC->getParentSourceFile (), S, TheFunc))
858
+ if (auto target = findBreakOrContinueStmtTarget (
859
+ getASTContext (), DC->getParentSourceFile (), S->getLoc (),
860
+ S->getTargetName (), S->getTargetLoc (), /* isContinue=*/ false ,
861
+ TheFunc)) {
846
862
S->setTarget (target);
863
+ }
847
864
848
865
return S;
849
866
}
850
867
851
868
Stmt *visitContinueStmt (ContinueStmt *S) {
852
- LabeledStmt *Target = nullptr ;
853
- TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
854
- // Scan to see if we are in any non-switch labeled statements (loops). Scan
855
- // inside out.
856
- if (S->getTargetName ().empty ()) {
857
- for (auto I = ActiveLabeledStmts.rbegin (), E = ActiveLabeledStmts.rend ();
858
- I != E; ++I) {
859
- // 'continue' with no label ignores non-loop structures.
860
- if (!(*I)->requiresLabelOnJump () &&
861
- (*I)->isPossibleContinueTarget ()) {
862
- Target = *I;
863
- break ;
864
- }
865
- }
866
- } else {
867
- // Scan inside out until we find something with the right label.
868
- for (auto I = ActiveLabeledStmts.rbegin (), E = ActiveLabeledStmts.rend ();
869
- I != E; ++I) {
870
- if (S->getTargetName () == (*I)->getLabelInfo ().Name ) {
871
- Target = *I;
872
- break ;
873
- } else {
874
- unsigned distance =
875
- TypeChecker::getCallEditDistance (
876
- DeclNameRef (S->getTargetName ()), (*I)->getLabelInfo ().Name ,
877
- TypeChecker::UnreasonableCallEditDistance);
878
- if (distance < TypeChecker::UnreasonableCallEditDistance)
879
- labelCorrections.insert (distance, std::move (*I));
880
- }
881
- }
882
- labelCorrections.filterMaxScoreRange (
883
- TypeChecker::MaxCallEditDistanceFromBestCandidate);
869
+ if (auto target = findBreakOrContinueStmtTarget (
870
+ getASTContext (), DC->getParentSourceFile (), S->getLoc (),
871
+ S->getTargetName (), S->getTargetLoc (), /* isContinue=*/ true ,
872
+ TheFunc)) {
873
+ S->setTarget (target);
884
874
}
885
875
886
- if (Target) {
887
- // Continue cannot be used to repeat switches, use fallthrough instead.
888
- if (!Target->isPossibleContinueTarget ()) {
889
- getASTContext ().Diags .diagnose (
890
- S->getLoc (), diag::continue_not_in_this_stmt,
891
- isa<SwitchStmt>(Target) ? " switch" : " if" );
892
- return nullptr ;
893
- }
894
- } else {
895
- // If we're in a defer, produce a tailored diagnostic.
896
- if (isInDefer ()) {
897
- getASTContext ().Diags .diagnose (S->getLoc (),
898
- diag::jump_out_of_defer, " break" );
899
- } else if (S->getTargetName ().empty ()) {
900
- // If we're dealing with an unlabeled continue, produce a generic error.
901
- getASTContext ().Diags .diagnose (S->getLoc (),
902
- diag::continue_outside_loop);
903
- } else {
904
- emitUnresolvedLabelDiagnostics (getASTContext ().Diags ,
905
- S->getTargetLoc (), S->getTargetName (),
906
- labelCorrections);
907
- }
908
- return nullptr ;
909
- }
910
- S->setTarget (Target);
911
876
return S;
912
877
}
913
878
0 commit comments