llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Sirraide

<details>
<summary>Changes</summary>

tl;dr: This makes e.g. `while (({ break; })) {}` ill-formed.

GCC used to allow this a long time ago (&lt; GCC 9 I believe), but eventually 
removed support for it; we originally allowed this both for GCC compatibility 
and because there was actual code in the wild using it (see Richard’s comment 
here for more background: 
https://github.com/llvm/llvm-project/pull/152606#issuecomment-3166130973).

Note that this _is_ still allowed inside another loop, e.g. this
```c++
for (;;) {
    while (({ break; true; })) {}
}
```
is well-formed; the `break` here will break out of the `for` loop.

Removing support for this gets rid of quite a bit of code and has a few more 
benefits:

1. Currently, GCC and Clang _disagree_ on the meaning of this construct in 
nested loops: in the code snippet above, Clang breaks out of the `while` loop, 
whereas GCC breaks out of the `for` loop; this patch changes Clang to align 
with GCC here. As a result, we can also remove code that emits a warning for 
such cases.

2. It frees up a bit in `ScopeFlags::Flags`, which is a good thing because I 
need one for expansion statements, and we’re out of bits. This is because we 
currently use a bit as a hack to disallow `continue` inside the declaration of 
the condition variable (because we’d `continue` to the condition before 
initialising the variable); this bit becomes obsolete with this patch because 
`continue` is now disallowed entirely within the condition (if there is no 
outer loop).

    Without this change, I’d have to refactor `Flags` to be a 64-bit integer, 
which would also entail updating every place where we use an `unsigned` to 
store score flags.

There is another change that I needed to make here: we currently suppress 
`-Wcomma` (which warns about comma operators, because in most contexts, you 
probably didn’t mean to use one) in some places, including the third part of a 
C-style `for` loop. This is implemented by checking if we’re in a `BreakScope | 
ContinueScope`, but those scope flags are now only set when parsing the loop 
body. Instead, we now check for `ControlScope`. This requires us to also set 
that flag in C90 mode, but that seems to be harmless as the only use of 
`ControlScope` I was able to find is in C++ code paths, where that bit was 
already set anyway.

When we introduced named loops for C2y, we purposefully didn’t support labeled 
break/continue in the condition, so there’s nothing to be done there (we 
already have tests for this too).


---

Patch is 37.23 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/198436.diff


16 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+31) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (-9) 
- (modified) clang/include/clang/Parse/Parser.h (+1-5) 
- (modified) clang/include/clang/Sema/Scope.h (+16-24) 
- (modified) clang/include/clang/Sema/Sema.h (-4) 
- (modified) clang/lib/Parse/ParseExprCXX.cpp (+5-25) 
- (modified) clang/lib/Parse/ParseStmt.cpp (+14-32) 
- (modified) clang/lib/Sema/Scope.cpp (+18-13) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+1-9) 
- (modified) clang/lib/Sema/SemaStmt.cpp (-35) 
- (modified) clang/test/Analysis/dead-stores.c (-14) 
- (modified) clang/test/CoverageMapping/break.c (-11) 
- (added) clang/test/Sema/break-continue-cond.c (+114) 
- (modified) clang/test/Sema/loop-control.c (+25-25) 
- (modified) clang/test/Sema/statements.c (+1-1) 
- (modified) clang/test/SemaCXX/scope-check.cpp (+6-10) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f5660f9670eae..320a1926d7f02 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -40,6 +40,37 @@ Potentially Breaking Changes
 C/C++ Language Potentially Breaking Changes
 -------------------------------------------
 
+- Clang now makes it ill-formed to try to ``break`` out of or ``continue`` a 
loop inside its own condition,
+  increment, or init-statement in all C and C++ language modes. This means 
that code such as
+
+  .. code-block:: c++
+
+    while (({ break; })) {}
+
+  is now ill-formed. An outer loop can still be broken out of or continued so 
long as the inner loop is
+  in the body of the outer loop:
+
+  .. code-block:: c++
+
+    // Ok, this breaks out of the 'for' loop.
+    for (;;) {
+      while (({ break; true; })) {}
+    }
+
+    // Error: can't break out of the 'for' loop from within its own increment.
+    for (;;({ while (({ break; true; })) {} })) {}
+
+  This also resolves a divergence from GCC: in a construct such as
+
+  .. code-block:: c++
+
+    for (;;) {
+      while (({ break; true; })) {}
+    }
+
+  Clang would previously ``break`` out of the ``while`` loop, whereas GCC 
(since version 9) would
+  ``break`` out of the ``for`` loop here. Now, Clang and GCC both break out of 
the ``for`` loop.
+
 C++ Specific Potentially Breaking Changes
 -----------------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d7dd20d6a45e4..0be5d2ffa2f49 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6899,9 +6899,6 @@ def note_goto_ms_asm_label : Note<
 def warn_unused_label : Warning<"unused label %0">,
   InGroup<UnusedLabel>, DefaultIgnore;
 
-def err_continue_from_cond_var_init : Error<
-  "cannot jump from this continue statement to the loop increment; "
-  "jump bypasses initialization of loop condition variable">;
 def err_goto_into_protected_scope : Error<
   "cannot jump from this goto statement to its label">;
 def ext_goto_into_protected_scope : ExtWarn<
@@ -11191,9 +11188,6 @@ def err_break_continue_label_not_found : Error<
   "%select{loop or 'switch'|loop}0">;
 def err_continue_switch : Error<
   "label of 'continue' refers to a 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 err_omp_bind_required_on_loop : Error<
   "expected 'bind' clause for 'loop' construct without an enclosing OpenMP "
   "construct">;
@@ -11201,9 +11195,6 @@ def err_omp_loop_reduction_clause : Error<
   "'reduction' clause not allowed with '#pragma omp loop bind(teams)'">;
 def err_omp_split_counts_not_one_omp_fill : Error<
   "exactly one 'omp_fill' must appear in the 'counts' clause">;
-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">;
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index dc3dc8a4ae0e9..c6c492b4980af 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -5035,16 +5035,12 @@ class Parser : public CodeCompletionHandler {
   /// present will be parsed and stored here, and a null result will be
   /// returned.
   ///
-  /// \param EnterForConditionScope If true, enter a continue/break scope at 
the
-  /// appropriate moment for a 'for' loop.
-  ///
   /// \returns The parsed condition.
   Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
                                           SourceLocation Loc,
                                           Sema::ConditionKind CK,
                                           bool MissingOK,
-                                          ForRangeInfo *FRI = nullptr,
-                                          bool EnterForConditionScope = false);
+                                          ForRangeInfo *FRI = nullptr);
   DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext 
Context,
                                                       ParsedAttributes &Attrs);
 
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 0d1c0ff6a1e91..ab6471f907e59 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -140,10 +140,12 @@ class Scope {
     /// This is the scope of a C++ catch statement.
     CatchScope = 0x1000000,
 
-    /// This is a scope in which a condition variable is currently being
-    /// parsed. If such a scope is a ContinueScope, it's invalid to jump to the
-    /// continue block from here.
-    ConditionVarScope = 0x2000000,
+    /// This is the scope corresponding to a C++26 expansion statement.
+    ///
+    /// NOTE: While currently unused, this flag is reserved for the
+    /// implementation of expansion statements; do not remove it or
+    /// reuse it for anything else.
+    ExpansionStmtScope = 0x2000000,
 
     /// This is a scope of some OpenMP directive with
     /// order clause which specifies concurrent
@@ -274,11 +276,6 @@ class Scope {
 
   /// Get the label that precedes this scope.
   LabelDecl *getPrecedingLabel() const { return PrecedingLabel; }
-  void setPrecedingLabel(LabelDecl *LD) {
-    assert((Flags & BreakScope || Flags & ContinueScope) &&
-           "not a loop or switch");
-    PrecedingLabel = LD;
-  }
 
   /// isBlockScope - Return true if this scope correspond to a closure.
   bool isBlockScope() const { return Flags & BlockScope; }
@@ -306,17 +303,6 @@ class Scope {
     return const_cast<Scope*>(this)->getContinueParent();
   }
 
-  // Set whether we're in the scope of a condition variable, where 'continue'
-  // is disallowed despite being a continue scope.
-  void setIsConditionVarScope(bool InConditionVarScope) {
-    Flags = (Flags & ~ConditionVarScope) |
-            (InConditionVarScope ? ConditionVarScope : NoScope);
-  }
-
-  bool isConditionVarScope() const {
-    return Flags & ConditionVarScope;
-  }
-
   /// getBreakParent - Return the closest scope that a break statement
   /// would be affected by.
   Scope *getBreakParent() {
@@ -636,6 +622,16 @@ class Scope {
   /// is an ancestor of the other.
   bool Contains(const Scope& rhs) const { return Depth < rhs.Depth; }
 
+  /// Mark that we're entering the body of a loop (for, while, do).
+  void EnterLoopBody(LabelDecl *PrecedingLabel);
+
+  /// Mark that we're entering the body of a switch statement.
+  void EnterSwitchBody(LabelDecl *PrecedingLabel);
+
+  /// Mark that we're leaving the body of a loop; this is only needed for do
+  /// loops where the condition follows the loop body.
+  void LeaveLoopBody();
+
   /// containedInPrototypeScope - Return true if this or a parent scope
   /// is a FunctionPrototypeScope.
   bool containedInPrototypeScope() const;
@@ -659,10 +655,6 @@ class Scope {
   /// Init - This is used by the parser to implement scope caching.
   void Init(Scope *parent, unsigned flags);
 
-  /// Sets up the specified scope flags and adjusts the scope state
-  /// variables accordingly.
-  void AddFlags(unsigned Flags);
-
   void dumpImpl(raw_ostream &OS) const;
   void dump() const;
 };
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5202244cee2a7..e71794b2d92c9 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11338,10 +11338,6 @@ class Sema final : public SemaBase {
   /// issuing a diagnostic and returning false if not.
   bool checkMustTailAttr(const Stmt *St, const Attr &MTA);
 
-  /// Check if the given expression contains 'break' or 'continue'
-  /// statement that produces control flow different from GCC.
-  void CheckBreakContinueBinding(Expr *E);
-
   ///@}
 
   //
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 39c61f4b5bf5c..5646597622832 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1865,25 +1865,11 @@ 
Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
   return DG;
 }
 
-Sema::ConditionResult
-Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
-                          Sema::ConditionKind CK, bool MissingOK,
-                          ForRangeInfo *FRI, bool EnterForConditionScope) {
-  // Helper to ensure we always enter a continue/break scope if requested.
-  struct ForConditionScopeRAII {
-    Scope *S;
-    void enter(bool IsConditionVariable) {
-      if (S) {
-        S->AddFlags(Scope::BreakScope | Scope::ContinueScope);
-        S->setIsConditionVarScope(IsConditionVariable);
-      }
-    }
-    ~ForConditionScopeRAII() {
-      if (S)
-        S->setIsConditionVarScope(false);
-    }
-  } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr};
-
+Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
+                                                SourceLocation Loc,
+                                                Sema::ConditionKind CK,
+                                                bool MissingOK,
+                                                ForRangeInfo *FRI) {
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
   PreferredType.enterCondition(Actions, Tok.getLocation());
 
@@ -1907,9 +1893,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, 
SourceLocation Loc,
   // Determine what kind of thing we have.
   switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) {
   case ConditionOrInitStatement::Expression: {
-    // If this is a for loop, we're entering its condition.
-    ForConditionScope.enter(/*IsConditionVariable=*/false);
-
     ProhibitAttributes(attrs);
 
     // We can have an empty expression here.
@@ -1983,9 +1966,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, 
SourceLocation Loc,
     break;
   }
 
-  // If this is a for loop, we're entering its condition.
-  ForConditionScope.enter(/*IsConditionVariable=*/true);
-
   // type-specifier-seq
   DeclSpec DS(AttrFactory);
   ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 1a45ed66950be..37f142e059930 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1697,8 +1697,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation 
*TrailingElseLoc,
   // 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);
-  getCurScope()->setPrecedingLabel(PrecedingLabel);
+  getCurScope()->EnterSwitchBody(PrecedingLabel);
   ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, 
Tok.is(tok::l_brace));
 
   // We have incremented the mangling number for the SwitchScope and the
@@ -1742,12 +1741,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation 
*TrailingElseLoc,
   // while, for, and switch statements are local to the if, while, for, or
   // switch statement (including the controlled statement).
   //
-  unsigned ScopeFlags;
-  if (C99orCXX)
-    ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
-                 Scope::DeclScope  | Scope::ControlScope;
-  else
-    ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+  unsigned ScopeFlags = Scope::ControlScope | (C99orCXX ? Scope::DeclScope : 
0);
   ParseScope WhileScope(this, ScopeFlags);
 
   // Parse the condition.
@@ -1762,7 +1756,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation 
*TrailingElseLoc,
   // combinations, so diagnose that here in OpenACC mode.
   SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
   getActions().OpenACC().ActOnWhileStmt(WhileLoc);
-  getCurScope()->setPrecedingLabel(PrecedingLabel);
+  getCurScope()->EnterLoopBody(PrecedingLabel);
 
   // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do 
this
@@ -1800,19 +1794,14 @@ StmtResult Parser::ParseDoStatement(LabelDecl 
*PrecedingLabel) {
 
   // C99 6.8.5p5 - In C99, the do statement is a block.  This is not
   // the case for C90.  Start the loop scope.
-  unsigned ScopeFlags;
-  if (getLangOpts().C99)
-    ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
-  else
-    ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
-
+  unsigned ScopeFlags = getLangOpts().C99 ? Scope::DeclScope : 0;
   ParseScope DoScope(this, ScopeFlags);
 
   // OpenACC Restricts a do-while-loop inside of certain construct/clause
   // combinations, so diagnose that here in OpenACC mode.
   SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
   getActions().OpenACC().ActOnDoStmt(DoLoc);
-  getCurScope()->setPrecedingLabel(PrecedingLabel);
+  getCurScope()->EnterLoopBody(PrecedingLabel);
 
   // C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause. We only do this
@@ -1832,7 +1821,7 @@ StmtResult Parser::ParseDoStatement(LabelDecl 
*PrecedingLabel) {
   InnerScope.Exit();
 
   // Reset this to disallow break/continue out of the condition.
-  getCurScope()->setPrecedingLabel(nullptr);
+  getCurScope()->LeaveLoopBody();
 
   if (Tok.isNot(tok::kw_while)) {
     if (!Body.isInvalid()) {
@@ -1928,10 +1917,12 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // Names declared in the for-init-statement are in the same 
declarative-region
   // as those declared in the condition.
   //
-  unsigned ScopeFlags = 0;
-  if (C99orCXXorObjC)
-    ScopeFlags = Scope::DeclScope | Scope::ControlScope;
-
+  // Always enter a ControlScope, even in C90 mode; this is harmless as it
+  // doesn't cause declarations to bind to this scope. We use this to avoid
+  // diagnosing a comma operator in e.g. the third part of a for loop when
+  // '-Wcomma' is enabled.
+  unsigned ScopeFlags =
+      Scope::ControlScope | (C99orCXXorObjC ? Scope::DeclScope : 0);
   ParseScope ForScope(this, ScopeFlags);
 
   BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -2112,8 +2103,7 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
         SecondPart = ParseCXXCondition(
             /*InitStmt=*/nullptr, ForLoc, CK,
             // FIXME: recovery if we don't see another semi!
-            /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr,
-            /*EnterForConditionScope=*/true);
+            /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr);
 
         if (ForRangeInfo.ParsedForRangeDecl()) {
           Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
@@ -2143,9 +2133,6 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
         }
 
       } else {
-        // We permit 'continue' and 'break' in the condition of a for loop.
-        getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
-
         ExprResult SecondExpr = ParseExpression();
         if (SecondExpr.isInvalid())
           SecondPart = Sema::ConditionError();
@@ -2157,11 +2144,6 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
     }
   }
 
-  // Enter a break / continue scope, if we didn't already enter one while
-  // parsing the second part.
-  if (!getCurScope()->isContinueScope())
-    getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
-
   // Parse the third part of the for statement.
   if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
     if (Tok.isNot(tok::semi)) {
@@ -2230,7 +2212,7 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
 
   // Set this only right before parsing the body to disallow break/continue in
   // the other parts.
-  getCurScope()->setPrecedingLabel(PrecedingLabel);
+  getCurScope()->EnterLoopBody(PrecedingLabel);
 
   // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do 
this
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index e66cce255230b..fc79b1a056ed9 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -113,18 +113,23 @@ bool Scope::containedInPrototypeScope() const {
   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;
+void Scope::EnterLoopBody(LabelDecl *LD) {
+  Flags |= BreakScope | ContinueScope;
+  BreakParent = ContinueParent = this;
+  PrecedingLabel = LD;
+}
+
+void Scope::EnterSwitchBody(LabelDecl *LD) {
+  Flags |= BreakScope;
+  BreakParent = this;
+  PrecedingLabel = LD;
+}
+
+void Scope::LeaveLoopBody() {
+  Flags &= ~(BreakScope | ContinueScope);
+  BreakParent = getParent()->BreakParent;
+  ContinueParent = getParent()->ContinueParent;
+  PrecedingLabel = nullptr;
 }
 
 // The algorithm for updating NRVO candidate is as follows:
@@ -229,7 +234,7 @@ void Scope::dumpImpl(raw_ostream &OS) const {
       {CompoundStmtScope, "CompoundStmtScope"},
       {ClassInheritanceScope, "ClassInheritanceScope"},
       {CatchScope, "CatchScope"},
-      {ConditionVarScope, "ConditionVarScope"},
+      {ExpansionStmtScope, "ExpansionStmtScope"},
       {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},
       {LambdaScope, "LambdaScope"},
       {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5b89236b11824..521a8516ac179 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14636,15 +14636,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, 
SourceLocation Loc) {
   // The listed locations are the initialization and increment portions
   // of a for loop.  The additional checks are on the condition of
   // if statements, do/while loops, and for loops.
-  // Differences in scope flags for C89 mode requires the extra logic.
-  const unsigned ForIncrementFlags =
-      getLangOpts().C99 || getLangOpts().CPlusPlus
-          ? Scope::ControlScope | Scope::ContinueScope | Scope::BreakScope
-          : Scope::ContinueScope | Scope::BreakScope;
-  const unsigned ForInitFlags = Scope::ControlScope | Scope::DeclScope;
-  const unsigned ScopeFlags = getCurScope()->getFlags();
-  if ((ScopeFlags & ForIncrementFlags) == ForIncrementFlags ||
-      (ScopeFlags & ForInitFlags) == ForInitFlags)
+  if (getCurScope()->isControlScope())
     return;
 
   // If there are multiple comma operators used together, get the RHS of the
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 531147ef35b08..1d3c462833c7d 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1794,7 +1794,6 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc,
     return StmtError();
 
   auto CondVal = Cond.get();
-  CheckBreakContinueBinding(CondVal.second);
 
   if (CondVal.second &&
       !Diags.isIgnored(diag::warn_comma_operator, 
CondVal.second->getExprLoc()))
@@ -1822,7 +1821,6 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
                   Expr *Cond, SourceLocation CondRParen) {
   assert(Cond && "ActOnDoStmt(): missing expression");
 
-  CheckBreakContinueBinding(Cond);
   ExprResult CondResult = CheckBooleanCondition(DoLoc, Cond);
   if (CondResult.isInvalid())
     return StmtError();
@@ -1833,11 +1831,6 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
     return StmtError();
   Cond = CondResult.get();
 
-  // Only call the CommaVisitor for C89 due to differences in scope flags.
-  if (Cond && !getLangOpts().C99 && !getLangOpts().CPlusPlus &&
-      !Diags.isIgnored(diag::warn_comma_operator, Cond->getExprLoc()))
-    CommaVisitor(*this).Visit(Cond);
-
   // OpenACC3.3 2.14.4:
   // The update directive is executable.  It must not appear in place of the
   // statement following an 'if',...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/198436
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to