Skip to content

Commit 336160a

Browse files
committed
[Statement checker] Simplify findBreakOrContinueStmtTarget.
1 parent 190aeea commit 336160a

File tree

1 file changed

+69
-52
lines changed

1 file changed

+69
-52
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,50 @@ emitUnresolvedLabelDiagnostics(DiagnosticEngine &DE,
352352
}
353353
}
354354

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+
355399
/// Find the target of a break or continue statement.
356400
///
357401
/// \returns the target, if one was found, or \c nullptr if no such target
@@ -361,7 +405,6 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
361405
SourceLoc loc, Identifier targetName, SourceLoc targetLoc,
362406
bool isContinue, DeclContext *dc,
363407
ArrayRef<LabeledStmt *> oldActiveLabeledStmts) {
364-
TopCollection<unsigned, LabeledStmt *> labelCorrections(3);
365408

366409
// Retrieve the active set of labeled statements.
367410
// FIXME: Once everything uses ASTScope lookup, \c oldActiveLabeledStmts
@@ -375,43 +418,37 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
375418
oldActiveLabeledStmts.rbegin(), oldActiveLabeledStmts.rend());
376419
}
377420

378-
// Pick the nearest break target that matches the specified name.
421+
// Handle an unlabeled break separately; that's the easy case.
379422
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+
}
400426

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;
402437
}
403438

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;
411440
}
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));
414449
}
450+
labelCorrections.filterMaxScoreRange(
451+
TypeChecker::MaxCallEditDistanceFromBestCandidate);
415452

416453
// If we're in a defer, produce a tailored diagnostic.
417454
if (isDefer(dc)) {
@@ -420,26 +457,6 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
420457
return nullptr;
421458
}
422459

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-
443460
// Provide potential corrections for an incorrect label.
444461
emitUnresolvedLabelDiagnostics(
445462
ctx.Diags, targetLoc, targetName, labelCorrections);

0 commit comments

Comments
 (0)