summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaStmt.cpp')
-rw-r--r--clang/lib/Sema/SemaStmt.cpp92
1 files changed, 73 insertions, 19 deletions
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index bc1ddb80961a..ae0bb616beb8 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1271,8 +1271,8 @@ static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
QualType CondType = Cond->getType();
QualType CaseType = Case->getType();
- const EnumType *CondEnumType = CondType->getAs<EnumType>();
- const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
+ const EnumType *CondEnumType = CondType->getAsCanonical<EnumType>();
+ const EnumType *CaseEnumType = CaseType->getAsCanonical<EnumType>();
if (!CondEnumType || !CaseEnumType)
return;
@@ -1590,12 +1590,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// we still do the analysis to preserve this information in the AST
// (which can be used by flow-based analyes).
//
- const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>();
-
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond &&
- ET) {
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ CondTypeBeforePromotion->isEnumeralType()) {
+ const auto *ED = CondTypeBeforePromotion->castAsEnumDecl();
if (!ED->isCompleteDefinition() || ED->enumerators().empty())
goto enum_out;
@@ -1730,8 +1728,7 @@ void
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
Expr *SrcExpr) {
- const auto *ET = DstType->getAs<EnumType>();
- if (!ET)
+ if (!DstType->isEnumeralType())
return;
if (!SrcType->isIntegerType() ||
@@ -1741,7 +1738,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
if (SrcExpr->isTypeDependent() || SrcExpr->isValueDependent())
return;
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = DstType->castAsEnumDecl();
if (!ED->isClosed())
return;
@@ -2125,12 +2122,12 @@ namespace {
typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited;
void VisitContinueStmt(const ContinueStmt* E) {
- ContinueLoc = E->getContinueLoc();
+ ContinueLoc = E->getKwLoc();
}
void VisitBreakStmt(const BreakStmt* E) {
if (!InSwitch)
- BreakLoc = E->getBreakLoc();
+ BreakLoc = E->getKwLoc();
}
void VisitSwitchStmt(const SwitchStmt* S) {
@@ -3278,9 +3275,55 @@ static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc,
}
}
-StmtResult
-Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
- Scope *S = CurScope->getContinueParent();
+static Scope *FindLabeledBreakContinueScope(Sema &S, Scope *CurScope,
+ SourceLocation KWLoc,
+ LabelDecl *Target,
+ SourceLocation LabelLoc,
+ bool IsContinue) {
+ assert(Target && "not a named break/continue?");
+ Scope *Found = nullptr;
+ for (Scope *Scope = CurScope; Scope; Scope = Scope->getParent()) {
+ if (Scope->isFunctionScope())
+ break;
+
+ if (Scope->isOpenACCComputeConstructScope()) {
+ S.Diag(KWLoc, diag::err_acc_branch_in_out_compute_construct)
+ << /*branch*/ 0 << /*out of*/ 0;
+ return nullptr;
+ }
+
+ if (Scope->isBreakOrContinueScope() &&
+ Scope->getPrecedingLabel() == Target) {
+ Found = Scope;
+ break;
+ }
+ }
+
+ if (Found) {
+ if (IsContinue && !Found->isContinueScope()) {
+ S.Diag(LabelLoc, diag::err_continue_switch);
+ return nullptr;
+ }
+ return Found;
+ }
+
+ S.Diag(LabelLoc, diag::err_break_continue_label_not_found) << IsContinue;
+ return nullptr;
+}
+
+StmtResult Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope,
+ LabelDecl *Target, SourceLocation LabelLoc) {
+ Scope *S;
+ if (Target) {
+ S = FindLabeledBreakContinueScope(*this, CurScope, ContinueLoc, Target,
+ LabelLoc,
+ /*IsContinue=*/true);
+ if (!S)
+ return StmtError();
+ } else {
+ S = CurScope->getContinueParent();
+ }
+
if (!S) {
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
@@ -3302,16 +3345,27 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);
- return new (Context) ContinueStmt(ContinueLoc);
+ return new (Context) ContinueStmt(ContinueLoc, LabelLoc, Target);
}
-StmtResult
-Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
- Scope *S = CurScope->getBreakParent();
+StmtResult Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope,
+ LabelDecl *Target, SourceLocation LabelLoc) {
+ Scope *S;
+ if (Target) {
+ S = FindLabeledBreakContinueScope(*this, CurScope, BreakLoc, Target,
+ LabelLoc,
+ /*IsContinue=*/false);
+ if (!S)
+ return StmtError();
+ } else {
+ S = CurScope->getBreakParent();
+ }
+
if (!S) {
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
}
+
if (S->isOpenMPLoopScope())
return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
<< "break");
@@ -3332,7 +3386,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);
- return new (Context) BreakStmt(BreakLoc);
+ return new (Context) BreakStmt(BreakLoc, LabelLoc, Target);
}
Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E,