"'continue' statement not in loop statement">;
def err_break_not_in_loop_or_switch : Error<
"'break' statement not in loop or switch statement">;
+def warn_loop_ctrl_binds_to_inner : Warning<
+ "'%0' is bound to current loop, GCC binds it to the enclosing loop">,
+ InGroup<GccCompat>;
+def warn_break_binds_to_switch : Warning<
+ "'break' is bound to loop, GCC binds it to switch">,
+ InGroup<GccCompat>;
def err_default_not_in_switch : Error<
"'default' statement not in switch statement">;
def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
/// Init - This is used by the parser to implement scope caching.
///
void Init(Scope *parent, unsigned flags);
+
+ /// \brief Sets up the specified scope flags and adjusts the scope state
+ /// variables accordingly.
+ ///
+ void AddFlags(unsigned Flags);
};
} // end namespace clang
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
Expr *Init);
+ /// \brief Check if the given expression contains 'break' or 'continue'
+ /// statement that produces control flow different from GCC.
+ void CheckBreakContinueBinding(Expr *E);
+
public:
/// \brief Register a magic integral constant to be used as a type tag.
void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
}
Cnt.adjustForControlFlow();
- BreakContinueStack.pop_back();
-
EmitBlock(LoopCond.getBlock());
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
// compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+ BreakContinueStack.pop_back();
+
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure
// to correctly handle break/continue though.
bool EmitBoolCondBranch = true;
llvm::BasicBlock *CondBlock = Continue.getBlock();
EmitBlock(CondBlock);
+ // If the for loop doesn't have an increment we can just use the
+ // condition as the continue block. Otherwise we'll need to create
+ // a block for it (in the current scope, i.e. in the scope of the
+ // condition), and that we will become our continue block.
+ if (S.getInc())
+ Continue = getJumpDestInCurrentScope("for.inc");
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue, &Cnt));
+
// Create a cleanup scope for the condition variable cleanups.
RunCleanupsScope ConditionScope(*this);
}
Cnt.beginRegion(Builder);
- // If the for loop doesn't have an increment we can just use the
- // condition as the continue block. Otherwise we'll need to create
- // a block for it (in the current scope, i.e. in the scope of the
- // condition), and that we will become our continue block.
- if (S.getInc())
- Continue = getJumpDestInCurrentScope("for.inc");
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue, &Cnt));
-
{
// Create a separate cleanup scope for the body, in case it is not
// a compound statement.
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope;
+ unsigned ScopeFlags = Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
// See comments in ParseIfStatement for why we create a scope for the
// condition and a new scope for substatement in C++.
//
+ getCurScope()->AddFlags(Scope::BreakScope);
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
// Names declared in the for-init-statement are in the same declarative-region
// as those declared in the condition.
//
- unsigned ScopeFlags;
+ unsigned ScopeFlags = 0;
if (C99orCXXorObjC)
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
- Scope::DeclScope | Scope::ControlScope;
- else
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+ ScopeFlags = Scope::DeclScope | Scope::ControlScope;
ParseScope ForScope(this, ScopeFlags);
}
}
}
+
+ // Parse the second part of the for specifier.
+ getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
if (!ForEach && !ForRange) {
assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier.
}
return false;
}
+
+void Scope::AddFlags(unsigned FlagsToSet) {
+ assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
+ "Unsupported scope flags");
+ if (FlagsToSet & BreakScope) {
+ assert((Flags & BreakScope) == 0 && "Already set");
+ BreakParent = this;
+ }
+ if (FlagsToSet & ContinueScope) {
+ assert((Flags & ContinueScope) == 0 && "Already set");
+ ContinueParent = this;
+ }
+ Flags |= FlagsToSet;
+}
+
Expr *ConditionExpr = CondResult.take();
if (!ConditionExpr)
return StmtError();
+ CheckBreakContinueBinding(ConditionExpr);
DiagnoseUnusedExprResult(Body);
Expr *Cond, SourceLocation CondRParen) {
assert(Cond && "ActOnDoStmt(): missing expression");
+ CheckBreakContinueBinding(Cond);
ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
if (CondResult.isInvalid())
return StmtError();
return false;
}
- // A visitor to determine if a continue statement is a subexpression.
- class ContinueFinder : public EvaluatedExprVisitor<ContinueFinder> {
- bool Found;
+ // A visitor to determine if a continue or break statement is a
+ // subexpression.
+ class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> {
+ SourceLocation BreakLoc;
+ SourceLocation ContinueLoc;
public:
- ContinueFinder(Sema &S, Stmt* Body) :
- Inherited(S.Context),
- Found(false) {
+ BreakContinueFinder(Sema &S, Stmt* Body) :
+ Inherited(S.Context) {
Visit(Body);
}
- typedef EvaluatedExprVisitor<ContinueFinder> Inherited;
+ typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited;
void VisitContinueStmt(ContinueStmt* E) {
- Found = true;
+ ContinueLoc = E->getContinueLoc();
+ }
+
+ void VisitBreakStmt(BreakStmt* E) {
+ BreakLoc = E->getBreakLoc();
}
- bool ContinueFound() { return Found; }
+ bool ContinueFound() { return ContinueLoc.isValid(); }
+ bool BreakFound() { return BreakLoc.isValid(); }
+ SourceLocation GetContinueLoc() { return ContinueLoc; }
+ SourceLocation GetBreakLoc() { return BreakLoc; }
- }; // end class ContinueFinder
+ }; // end class BreakContinueFinder
// Emit a warning when a loop increment/decrement appears twice per loop
// iteration. The conditions which trigger this warning are:
if (!ProcessIterationStmt(S, LastStmt, LastIncrement, LastDRE)) return;
// Check that the two statements are both increments or both decrements
- // on the same varaible.
+ // on the same variable.
if (LoopIncrement != LastIncrement ||
LoopDRE->getDecl() != LastDRE->getDecl()) return;
- if (ContinueFinder(S, Body).ContinueFound()) return;
+ if (BreakContinueFinder(S, Body).ContinueFound()) return;
S.Diag(LastDRE->getLocation(), diag::warn_redundant_loop_iteration)
<< LastDRE->getDecl() << LastIncrement;
} // end namespace
+
+void Sema::CheckBreakContinueBinding(Expr *E) {
+ if (!E || getLangOpts().CPlusPlus)
+ return;
+ BreakContinueFinder BCFinder(*this, E);
+ Scope *BreakParent = CurScope->getBreakParent();
+ if (BCFinder.BreakFound() && BreakParent) {
+ if (BreakParent->getFlags() & Scope::SwitchScope) {
+ Diag(BCFinder.GetBreakLoc(), diag::warn_break_binds_to_switch);
+ } else {
+ Diag(BCFinder.GetBreakLoc(), diag::warn_loop_ctrl_binds_to_inner)
+ << "break";
+ }
+ } else if (BCFinder.ContinueFound() && CurScope->getContinueParent()) {
+ Diag(BCFinder.GetContinueLoc(), diag::warn_loop_ctrl_binds_to_inner)
+ << "continue";
+ }
+}
+
StmtResult
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, FullExprArg second, Decl *secondVar,
}
}
+ CheckBreakContinueBinding(second.get());
+ CheckBreakContinueBinding(third.get());
+
CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
CheckForRedundantIteration(*this, third.get(), Body);
// placed within the increment code of for loops.
void rdar8014335() {
for (int i = 0 ; i != 10 ; ({ break; })) {
- for ( ; ; ({ ++i; break; })) ;
+ for ( ; ; ({ ++i; break; })) ; // expected-warning {{'break' is bound to current loop, GCC binds it to the enclosing loop}}
// Note that the next value stored to 'i' is never executed
// because the next statement to be executed is the 'break'
// in the increment code of the first loop.
--- /dev/null
+// RUN: %clang_cc1 -Wno-gcc-compat -emit-llvm -o - %s | FileCheck %s
+
+void pr8880_cg_1(int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_1(
+ int i, j;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+ for (i = 2; i != 10 ; i++ )
+// CHECK: [[OUTER_COND]]
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ for (j = 3 ; j < 22; (void)({ ++j; break; j;})) {
+// CHECK: [[INNER_COND]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ *iptr = 7;
+// CHECK: store i32 7,
+// CHECK: br label %[[INNER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_INC]]
+
+// break in 3rd expression of inner loop causes branch to end of inner loop
+
+// CHECK: br label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_END]]
+ }
+// CHECK: br label %[[OUTER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_INC]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret
+}
+
+void pr8880_cg_2(int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_2(
+ int i, j;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+ for (i = 2; i != 10 ; i++ )
+// CHECK: [[OUTER_COND]]
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ for (j = 3 ; j < 22; (void)({ ++j; continue; j;})) {
+// CHECK: [[INNER_COND]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ *iptr = 7;
+// CHECK: store i32 7,
+// CHECK: br label %[[INNER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_INC]]
+
+// continue in 3rd expression of inner loop causes branch to inc of inner loop
+
+// CHECK: br label %[[INNER_INC]]
+// CHECK: [[INNER_END]]
+ }
+// CHECK: br label %[[OUTER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_INC]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret
+}
+
+void pr8880_cg_3(int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_3(
+ int i, j;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+ for (i = 2 ; i != 10 ; i++ )
+// CHECK: [[OUTER_COND]]
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ for (j = 3 ; ({break; j;}); j++) {
+
+// break in 2nd expression of inner loop causes branch to end of inner loop
+
+// CHECK: [[INNER_COND]]
+// CHECK: br label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ *iptr = 7;
+// CHECK: store i32 7,
+// CHECK: br label %[[INNER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_INC]]
+// CHECK: br label %[[INNER_COND]]
+ }
+// CHECK: [[INNER_END]]
+// CHECK: br label %[[OUTER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_INC]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret
+}
+
+void pr8880_cg_4(int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_4(
+ int i, j;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+ for (i = 2 ; i != 10 ; i++ )
+// CHECK: [[OUTER_COND]]
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ for (j = 3 ; ({continue; j;}); j++) {
+
+// continue in 2nd expression of inner loop causes branch to inc of inner loop
+
+// CHECK: [[INNER_COND]]
+// CHECK: br label %[[INNER_INC:[0-9A-Za-z$._]+]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ *iptr = 7;
+// CHECK: store i32 7,
+// CHECK: br label %[[INNER_INC]]
+// CHECK: [[INNER_INC]]
+// CHECK: br label %[[INNER_COND]]
+ }
+// CHECK: [[INNER_END]]
+// CHECK: br label %[[OUTER_INC:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_INC]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret
+}
+
+void pr8880_cg_5(int x, int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_5(
+ int y = 5;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_COND]]
+ while(--x) {
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ while(({ break; --y; })) {
+// CHECK: [[INNER_COND]]
+// CHECK: br label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ *iptr = 7;
+// CHECK: store i32 7,
+ }
+// CHECK: br label %[[INNER_COND]]
+ }
+// CHECK: [[INNER_END]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret void
+}
+
+void pr8880_cg_6(int x, int *iptr) {
+// CHECK-LABEL: define void @pr8880_cg_6(
+ int y = 5;
+// CHECK: br label %[[OUTER_COND:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_COND]]
+ while(--x) {
+// CHECK: label %[[OUTER_BODY:[0-9A-Za-z$._]+]], label %[[OUTER_END:[0-9A-Za-z$._]+]]
+// CHECK: [[OUTER_BODY]]
+// CHECK: br label %[[INNER_BODY:[0-9A-Za-z$._]+]]
+// CHECK: [[INNER_BODY]]
+ do {
+// CHECK: store i32 7,
+ *iptr = 7;
+// CHECK: br label %[[INNER_COND:[0-9A-Za-z$._]+]]
+ } while(({ break; --y; }));
+// CHECK: [[INNER_COND]]
+// CHECK: br label %[[INNER_END:[0-9A-Za-z$._]+]]
+// CHECK: label %[[INNER_BODY:[0-9A-Za-z$._]+]], label %[[INNER_END]]
+ }
+// CHECK: [[INNER_END]]
+// CHECK: br label %[[OUTER_COND]]
+// CHECK: [[OUTER_END]]
+// CHECK: ret void
+}
void foo2() {
continue; /* expected-error {{'continue' statement not in loop statement}} */
}
+
+int pr8880_9 (int first) {
+ switch(({ if (first) { first = 0; break; } 1; })) { // expected-error {{'break' statement not in loop or switch statement}}
+ case 2: return 2;
+ default: return 0;
+ }
+}
+
+void pr8880_24() {
+ for (({break;});;); // expected-error {{'break' statement not in loop or switch statement}}
+}
+
+void pr8880_25() {
+ for (({continue;});;); // expected-error {{'continue' statement not in loop statement}}
+}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -x c++ -Werror %s
+
+int pr8880_1() {
+ int first = 1;
+ for ( ; ({ if (first) { first = 0; continue; } 0; }); )
+ return 0;
+ return 1;
+}
+
+void pr8880_2(int first) {
+ for ( ; ({ if (first) { first = 0; break; } 0; }); ) {}
+}
+
+void pr8880_3(int first) {
+ for ( ; ; (void)({ if (first) { first = 0; continue; } 0; })) {}
+}
+
+void pr8880_4(int first) {
+ for ( ; ; (void)({ if (first) { first = 0; break; } 0; })) {}
+}
+
+void pr8880_5 (int first) {
+ while(({ if (first) { first = 0; continue; } 0; })) {}
+}
+
+void pr8880_6 (int first) {
+ while(({ if (first) { first = 0; break; } 0; })) {}
+}
+
+void pr8880_7 (int first) {
+ do {} while(({ if (first) { first = 0; continue; } 0; }));
+}
+
+void pr8880_8 (int first) {
+ do {} while(({ if (first) { first = 0; break; } 0; }));
+}
+
+void pr8880_10(int i) {
+ for ( ; i != 10 ; i++ )
+ for ( ; ; (void)({ ++i; continue; i;})) {} // expected-warning{{'continue' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_11(int i) {
+ for ( ; i != 10 ; i++ )
+ for ( ; ; (void)({ ++i; break; i;})) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_12(int i, int j) {
+ for ( ; i != 10 ; i++ )
+ for ( ; ({if (i) continue; i;}); j++) {} // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_13(int i, int j) {
+ for ( ; i != 10 ; i++ )
+ for ( ; ({if (i) break; i;}); j++) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_14(int i) {
+ for ( ; i != 10 ; i++ )
+ while(({if (i) break; i;})) {} // expected-warning {{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_15(int i) {
+ while (--i)
+ while(({if (i) continue; i;})) {} // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_16(int i) {
+ for ( ; i != 10 ; i++ )
+ do {} while(({if (i) break; i;})); // expected-warning {{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_17(int i) {
+ for ( ; i != 10 ; i++ )
+ do {} while(({if (i) continue; i;})); // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}}
+}
+
+void pr8880_18(int x, int y) {
+ while(x > 0)
+ switch(({if(y) break; y;})) {
+ case 2: x = 0;
+ }
+}
+
+void pr8880_19(int x, int y) {
+ switch(x) {
+ case 1:
+ switch(({if(y) break; y;})) {
+ case 2: x = 0;
+ }
+ }
+}
+
+void pr8880_20(int x, int y) {
+ switch(x) {
+ case 1:
+ while(({if (y) break; y;})) {} //expected-warning {{'break' is bound to loop, GCC binds it to switch}}
+ }
+}
+
+void pr8880_21(int x, int y) {
+ switch(x) {
+ case 1:
+ do {} while(({if (y) break; y;})); //expected-warning {{'break' is bound to loop, GCC binds it to switch}}
+ }
+}
+
+void pr8880_22(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ; (void)({ ++y; break; y;})) {} // expected-warning{{'break' is bound to loop, GCC binds it to switc}}
+ }
+}
+
+void pr8880_23(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; break; y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}}
+ }
+}
}
}
-// PR 8880
-// FIXME: Clang should reject this, since GCC does. Previously this
-// was causing a crash in the CFG builder.
int test_pr8880() {
int first = 1;
for ( ; ({ if (first) { first = 0; continue; } 0; }); )