Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -6341,6 +6341,12 @@ "'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; +def warn_break_binds_to_switch : Warning< + "'break' is bound to loop, GCC binds it to switch">, + InGroup; 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">; Index: cfe/trunk/include/clang/Sema/Scope.h =================================================================== --- cfe/trunk/include/clang/Sema/Scope.h +++ cfe/trunk/include/clang/Sema/Scope.h @@ -354,6 +354,11 @@ /// 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 Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -7917,6 +7917,10 @@ 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, Index: cfe/trunk/lib/CodeGen/CGStmt.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGStmt.cpp +++ cfe/trunk/lib/CodeGen/CGStmt.cpp @@ -614,8 +614,6 @@ } Cnt.adjustForControlFlow(); - BreakContinueStack.pop_back(); - EmitBlock(LoopCond.getBlock()); // C99 6.8.5.2: "The evaluation of the controlling expression takes place @@ -626,6 +624,8 @@ // 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; @@ -673,6 +673,16 @@ 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); @@ -710,16 +720,6 @@ } 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. Index: cfe/trunk/lib/Parse/ParseStmt.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseStmt.cpp +++ cfe/trunk/lib/Parse/ParseStmt.cpp @@ -1168,7 +1168,7 @@ // 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); @@ -1206,6 +1206,7 @@ // 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)); @@ -1417,12 +1418,9 @@ // 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); @@ -1537,6 +1535,9 @@ } } } + + // 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. Index: cfe/trunk/lib/Sema/Scope.cpp =================================================================== --- cfe/trunk/lib/Sema/Scope.cpp +++ cfe/trunk/lib/Sema/Scope.cpp @@ -69,3 +69,18 @@ } 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; +} + Index: cfe/trunk/lib/Sema/SemaStmt.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp +++ cfe/trunk/lib/Sema/SemaStmt.cpp @@ -1205,6 +1205,7 @@ Expr *ConditionExpr = CondResult.take(); if (!ConditionExpr) return StmtError(); + CheckBreakContinueBinding(ConditionExpr); DiagnoseUnusedExprResult(Body); @@ -1221,6 +1222,7 @@ Expr *Cond, SourceLocation CondRParen) { assert(Cond && "ActOnDoStmt(): missing expression"); + CheckBreakContinueBinding(Cond); ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc); if (CondResult.isInvalid()) return StmtError(); @@ -1483,25 +1485,33 @@ return false; } - // A visitor to determine if a continue statement is a subexpression. - class ContinueFinder : public EvaluatedExprVisitor { - bool Found; + // A visitor to determine if a continue or break statement is a + // subexpression. + class BreakContinueFinder : public EvaluatedExprVisitor { + 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 Inherited; + typedef EvaluatedExprVisitor 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: @@ -1530,11 +1540,11 @@ 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; @@ -1544,6 +1554,25 @@ } // 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, @@ -1567,6 +1596,9 @@ } } + CheckBreakContinueBinding(second.get()); + CheckBreakContinueBinding(third.get()); + CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); CheckForRedundantIteration(*this, third.get(), Body); Index: cfe/trunk/test/Analysis/dead-stores.c =================================================================== --- cfe/trunk/test/Analysis/dead-stores.c +++ cfe/trunk/test/Analysis/dead-stores.c @@ -480,7 +480,7 @@ // 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. Index: cfe/trunk/test/CodeGen/PR8880.c =================================================================== --- cfe/trunk/test/CodeGen/PR8880.c +++ cfe/trunk/test/CodeGen/PR8880.c @@ -0,0 +1,173 @@ +// 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 +} Index: cfe/trunk/test/Parser/bad-control.c =================================================================== --- cfe/trunk/test/Parser/bad-control.c +++ cfe/trunk/test/Parser/bad-control.c @@ -7,3 +7,18 @@ 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}} +} Index: cfe/trunk/test/Sema/loop-control.c =================================================================== --- cfe/trunk/test/Sema/loop-control.c +++ cfe/trunk/test/Sema/loop-control.c @@ -0,0 +1,121 @@ +// 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}} + } +} Index: cfe/trunk/test/Sema/statements.c =================================================================== --- cfe/trunk/test/Sema/statements.c +++ cfe/trunk/test/Sema/statements.c @@ -90,9 +90,6 @@ } } -// 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; }); )