r199897 - Fix to PR8880 (clang dies processing a for loop)

Serge Pavlov sepavloff at gmail.com
Thu Jan 23 07:05:00 PST 2014


Author: sepavloff
Date: Thu Jan 23 09:05:00 2014
New Revision: 199897

URL: http://llvm.org/viewvc/llvm-project?rev=199897&view=rev
Log:
Fix to PR8880 (clang dies processing a for loop)

Due to statement expressions supported as GCC extension, it is possible
to put 'break' or 'continue' into a loop/switch statement but outside
its body, for example:

    for ( ; ({ if (first) { first = 0; continue; } 0; }); )

This code is rejected by GCC if compiled in C mode but is accepted in C++
code. GCC bug 44715 tracks this discrepancy. Clang used code generation
that differs from GCC in both modes: only statement of the third
expression of 'for' behaves as if it was inside loop body.

This change makes code generation more close to GCC, considering 'break'
or 'continue' statement in condition and increment expressions of a
loop as it was inside the loop body. It also adds error for the cases
when 'break'/'continue' appear outside loop due to this syntax. If
code generation differ from GCC, warning is issued.

Differential Revision: http://llvm-reviews.chandlerc.com/D2518

Added:
    cfe/trunk/test/CodeGen/PR8880.c
    cfe/trunk/test/Sema/loop-control.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Scope.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/Scope.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/Analysis/dead-stores.c
    cfe/trunk/test/Parser/bad-control.c
    cfe/trunk/test/Sema/statements.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 23 09:05:00 2014
@@ -6341,6 +6341,12 @@ def err_continue_not_in_loop : Error<
   "'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">;

Modified: cfe/trunk/include/clang/Sema/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Scope.h (original)
+++ cfe/trunk/include/clang/Sema/Scope.h Thu Jan 23 09:05:00 2014
@@ -354,6 +354,11 @@ public:
   /// 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

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 23 09:05:00 2014
@@ -7917,6 +7917,10 @@ private:
   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,

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu Jan 23 09:05:00 2014
@@ -614,8 +614,6 @@ void CodeGenFunction::EmitDoStmt(const D
   }
   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 @@ void CodeGenFunction::EmitDoStmt(const D
   // 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 @@ void CodeGenFunction::EmitForStmt(const
   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 @@ void CodeGenFunction::EmitForStmt(const
   }
   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.

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Thu Jan 23 09:05:00 2014
@@ -1168,7 +1168,7 @@ StmtResult Parser::ParseSwitchStatement(
   // 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 @@ StmtResult Parser::ParseSwitchStatement(
   // 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 @@ StmtResult Parser::ParseForStatement(Sou
   // 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 @@ StmtResult Parser::ParseForStatement(Sou
       }
     }
   }
+
+  // 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.

Modified: cfe/trunk/lib/Sema/Scope.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Scope.cpp?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Scope.cpp (original)
+++ cfe/trunk/lib/Sema/Scope.cpp Thu Jan 23 09:05:00 2014
@@ -69,3 +69,18 @@ bool Scope::containedInPrototypeScope()
   }
   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;
+}
+

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jan 23 09:05:00 2014
@@ -1205,6 +1205,7 @@ Sema::ActOnWhileStmt(SourceLocation Whil
   Expr *ConditionExpr = CondResult.take();
   if (!ConditionExpr)
     return StmtError();
+  CheckBreakContinueBinding(ConditionExpr);
 
   DiagnoseUnusedExprResult(Body);
 
@@ -1221,6 +1222,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc,
                   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 @@ namespace {
     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:
@@ -1530,11 +1540,11 @@ namespace {
     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 @@ namespace {
 
 } // 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 @@ Sema::ActOnForStmt(SourceLocation ForLoc
     }
   }
 
+  CheckBreakContinueBinding(second.get());
+  CheckBreakContinueBinding(third.get());
+
   CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
   CheckForRedundantIteration(*this, third.get(), Body);
 

Modified: cfe/trunk/test/Analysis/dead-stores.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dead-stores.c?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dead-stores.c (original)
+++ cfe/trunk/test/Analysis/dead-stores.c Thu Jan 23 09:05:00 2014
@@ -480,7 +480,7 @@ int f26_nestedblocks() {
 // 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.

Added: cfe/trunk/test/CodeGen/PR8880.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/PR8880.c?rev=199897&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/PR8880.c (added)
+++ cfe/trunk/test/CodeGen/PR8880.c Thu Jan 23 09:05:00 2014
@@ -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
+}

Modified: cfe/trunk/test/Parser/bad-control.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/bad-control.c?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/test/Parser/bad-control.c (original)
+++ cfe/trunk/test/Parser/bad-control.c Thu Jan 23 09:05:00 2014
@@ -7,3 +7,18 @@ void foo() {
 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}}
+}

Added: cfe/trunk/test/Sema/loop-control.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/loop-control.c?rev=199897&view=auto
==============================================================================
--- cfe/trunk/test/Sema/loop-control.c (added)
+++ cfe/trunk/test/Sema/loop-control.c Thu Jan 23 09:05:00 2014
@@ -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}}
+  }
+}

Modified: cfe/trunk/test/Sema/statements.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/statements.c?rev=199897&r1=199896&r2=199897&view=diff
==============================================================================
--- cfe/trunk/test/Sema/statements.c (original)
+++ cfe/trunk/test/Sema/statements.c Thu Jan 23 09:05:00 2014
@@ -90,9 +90,6 @@ void foo(enum x X) {
   }
 }
 
-// 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; }); )





More information about the cfe-commits mailing list