<div dir="ltr">Should this be in -Wextra-semi? It seems weird to have to pass both -Wextra-semi and -Wextra-semi-stmt.<div><br></div><div>(Also, we generally try to not add DefaultIgnore warnings. I think this is a useful warning though, and other than others in this thread I think it'd be good to have -Wextra-semi in -Wall. But I don't feel strongly about that part.)</div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Nov 20, 2018 at 2:01 PM Roman Lebedev via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: lebedevri<br>
Date: Tue Nov 20 10:59:05 2018<br>
New Revision: 347339<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=347339&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=347339&view=rev</a><br>
Log:<br>
[clang][Parse] Diagnose useless null statements / empty init-statements<br>
<br>
Summary:<br>
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.<br>
While that is great, there is at least one more source of need-less semis - 'null statements'.<br>
Sometimes, they are needed:<br>
```<br>
for(int x = 0; continueToDoWork(x); x++)<br>
  ; // Ugly code, but the semi is needed here.<br>
```<br>
<br>
But sometimes they are just there for no reason:<br>
```<br>
switch(X) {<br>
case 0:<br>
  return -2345;<br>
case 5:<br>
  return 0;<br>
default:<br>
  return 42;<br>
}; // <- oops<br>
<br>
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.<br>
```<br>
<br>
Additionally:<br>
```<br>
if(; // <- empty init-statement<br>
   true)<br>
  ;<br>
<br>
switch (; // empty init-statement<br>
        x) {<br>
  ...<br>
}<br>
<br>
for (; // <- empty init-statement<br>
     int y : S())<br>
  ;<br>
}<br>
<br>
As usual, things may or may not go sideways in the presence of macros.<br>
While evaluating this diag on my codebase of interest, it was unsurprisingly<br>
discovered that Google Test macros are *very* prone to this.<br>
And it seems many issues are deep within the GTest itself, not<br>
in the snippets passed from the codebase that uses GTest.<br>
<br>
So after some thought, i decided not do issue a diagnostic if the semi<br>
is within *any* macro, be it either from the normal header, or system header.<br>
<br>
Fixes [[ <a href="https://bugs.llvm.org/show_bug.cgi?id=39111" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_bug.cgi?id=39111</a> | PR39111 ]]<br>
<br>
Reviewers: rsmith, aaron.ballman, efriedma<br>
<br>
Reviewed By: aaron.ballman<br>
<br>
Subscribers: cfe-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D52695" rel="noreferrer" target="_blank">https://reviews.llvm.org/D52695</a><br>
<br>
Added:<br>
    cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp<br>
    cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp<br>
Modified:<br>
    cfe/trunk/docs/ReleaseNotes.rst<br>
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
    cfe/trunk/include/clang/Parse/Parser.h<br>
    cfe/trunk/lib/Parse/ParseExprCXX.cpp<br>
    cfe/trunk/lib/Parse/ParseStmt.cpp<br>
<br>
Modified: cfe/trunk/docs/ReleaseNotes.rst<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ReleaseNotes.rst?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ReleaseNotes.rst?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/docs/ReleaseNotes.rst (original)<br>
+++ cfe/trunk/docs/ReleaseNotes.rst Tue Nov 20 10:59:05 2018<br>
@@ -55,6 +55,63 @@ Major New Features<br>
 Improvements to Clang's diagnostics<br>
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>
<br>
+- ``-Wextra-semi-stmt`` is a new diagnostic that diagnoses extra semicolons,<br>
+  much like ``-Wextra-semi``. This new diagnostic diagnoses all *unnecessary*<br>
+  null statements (expression statements without an expression), unless: the<br>
+  semicolon directly follows a macro that was expanded to nothing or if the<br>
+  semicolon is within the macro itself. This applies to macros defined in system<br>
+  headers as well as user-defined macros.<br>
+<br>
+  .. code-block:: c++<br>
+<br>
+      #define MACRO(x) int x;<br>
+      #define NULLMACRO(varname)<br>
+<br>
+      void test() {<br>
+        ; // <- warning: ';' with no preceding expression is a null statement<br>
+<br>
+        while (true)<br>
+          ; // OK, it is needed.<br>
+<br>
+        switch (my_enum) {<br>
+        case E1:<br>
+          // stuff<br>
+          break;<br>
+        case E2:<br>
+          ; // OK, it is needed.<br>
+        }<br>
+<br>
+        MACRO(v0;) // Extra semicolon, but within macro, so ignored.<br>
+<br>
+        MACRO(v1); // <- warning: ';' with no preceding expression is a null statement<br>
+<br>
+        NULLMACRO(v2); // ignored, NULLMACRO expanded to nothing.<br>
+      }<br>
+<br>
+- ``-Wempty-init-stmt`` is a new diagnostic that diagnoses empty init-statements<br>
+  of ``if``, ``switch``, ``range-based for``, unless: the semicolon directly<br>
+  follows a macro that was expanded to nothing or if the semicolon is within the<br>
+  macro itself (both macros from system headers, and normal macros). This<br>
+  diagnostic is in the ``-Wextra-semi-stmt`` group and is enabled in<br>
+  ``-Wextra``.<br>
+<br>
+  .. code-block:: c++<br>
+<br>
+      void test() {<br>
+        if(; // <- warning: init-statement of 'if' is a null statement<br>
+           true)<br>
+          ;<br>
+<br>
+        switch (; // <- warning: init-statement of 'switch' is a null statement<br>
+                x) {<br>
+          ...<br>
+        }<br>
+<br>
+        for (; // <- warning: init-statement of 'range-based for' is a null statement<br>
+             int y : S())<br>
+          ;<br>
+      }<br>
+<br>
<br>
 Non-comprehensive list of changes in this release<br>
 -------------------------------------------------<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Nov 20 10:59:05 2018<br>
@@ -162,6 +162,8 @@ def GNUEmptyStruct : DiagGroup<"gnu-empt<br>
 def ExtraTokens : DiagGroup<"extra-tokens">;<br>
 def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">;<br>
 def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;<br>
+def EmptyInitStatement : DiagGroup<"empty-init-stmt">;<br>
+def ExtraSemiStmt : DiagGroup<"extra-semi-stmt", [EmptyInitStatement]>;<br>
 def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi,<br>
                                          CXX11ExtraSemi]>;<br>
<br>
@@ -768,7 +770,8 @@ def Extra : DiagGroup<"extra", [<br>
     MissingMethodReturnType,<br>
     SignCompare,<br>
     UnusedParameter,<br>
-    NullPointerArithmetic<br>
+    NullPointerArithmetic,<br>
+    EmptyInitStatement<br>
   ]>;<br>
<br>
 def Most : DiagGroup<"most", [<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Nov 20 10:59:05 2018<br>
@@ -53,6 +53,10 @@ def ext_extra_semi_cxx11 : Extension<<br>
 def warn_extra_semi_after_mem_fn_def : Warning<<br>
   "extra ';' after member function definition">,<br>
   InGroup<ExtraSemi>, DefaultIgnore;<br>
+def warn_null_statement : Warning<<br>
+  "empty expression statement has no effect; "<br>
+  "remove unnecessary ';' to silence this warning">,<br>
+  InGroup<ExtraSemiStmt>, DefaultIgnore;<br>
<br>
 def ext_thread_before : Extension<"'__thread' before '%0'">;<br>
 def ext_keyword_as_ident : ExtWarn<<br>
@@ -554,6 +558,9 @@ def ext_for_range_init_stmt : ExtWarn<<br>
 def warn_cxx17_compat_for_range_init_stmt : Warning<<br>
   "range-based for loop initialization statements are incompatible with "<br>
   "C++ standards before C++2a">, DefaultIgnore, InGroup<CXXPre2aCompat>;<br>
+def warn_empty_init_statement : Warning<<br>
+  "empty initialization statement of '%select{if|switch|range-based for}0' "<br>
+  "has no effect">, InGroup<EmptyInitStatement>, DefaultIgnore;<br>
<br>
 // C++ derived classes<br>
 def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Parser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Parser.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Nov 20 10:59:05 2018<br>
@@ -1888,6 +1888,7 @@ private:<br>
   StmtResult ParseCompoundStatement(bool isStmtExpr,<br>
                                     unsigned ScopeFlags);<br>
   void ParseCompoundStatementLeadingPragmas();<br>
+  bool ConsumeNullStmt(StmtVector &Stmts);<br>
   StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);<br>
   bool ParseParenExprOrCondition(StmtResult *InitStmt,<br>
                                  Sema::ConditionResult &CondResult,<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Nov 20 10:59:05 2018<br>
@@ -1773,7 +1773,13 @@ Sema::ConditionResult Parser::ParseCXXCo<br>
     //   if (; true);<br>
     if (InitStmt && Tok.is(tok::semi)) {<br>
       WarnOnInit();<br>
-      SourceLocation SemiLoc = ConsumeToken();<br>
+      SourceLocation SemiLoc = Tok.getLocation();<br>
+      if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID()) {<br>
+        Diag(SemiLoc, diag::warn_empty_init_statement)<br>
+            << (CK == Sema::ConditionKind::Switch)<br>
+            << FixItHint::CreateRemoval(SemiLoc);<br>
+      }<br>
+      ConsumeToken();<br>
       *InitStmt = Actions.ActOnNullStmt(SemiLoc);<br>
       return ParseCXXCondition(nullptr, Loc, CK);<br>
     }<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=347339&r1=347338&r2=347339&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=347339&r1=347338&r2=347339&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Nov 20 10:59:05 2018<br>
@@ -930,6 +930,34 @@ void Parser::ParseCompoundStatementLeadi<br>
<br>
 }<br>
<br>
+/// Consume any extra semi-colons resulting in null statements,<br>
+/// returning true if any tok::semi were consumed.<br>
+bool Parser::ConsumeNullStmt(StmtVector &Stmts) {<br>
+  if (!Tok.is(tok::semi))<br>
+    return false;<br>
+<br>
+  SourceLocation StartLoc = Tok.getLocation();<br>
+  SourceLocation EndLoc;<br>
+<br>
+  while (Tok.is(tok::semi) && !Tok.hasLeadingEmptyMacro() &&<br>
+         Tok.getLocation().isValid() && !Tok.getLocation().isMacroID()) {<br>
+    EndLoc = Tok.getLocation();<br>
+<br>
+    // Don't just ConsumeToken() this tok::semi, do store it in AST.<br>
+    StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any);<br>
+    if (R.isUsable())<br>
+      Stmts.push_back(R.get());<br>
+  }<br>
+<br>
+  // Did not consume any extra semi.<br>
+  if (EndLoc.isInvalid())<br>
+    return false;<br>
+<br>
+  Diag(StartLoc, diag::warn_null_statement)<br>
+      << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));<br>
+  return true;<br>
+}<br>
+<br>
 /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the<br>
 /// ActOnCompoundStmt action.  This expects the '{' to be the current token, and<br>
 /// consume the '}' at the end of the block.  It does not manipulate the scope<br>
@@ -992,6 +1020,9 @@ StmtResult Parser::ParseCompoundStatemen<br>
       continue;<br>
     }<br>
<br>
+    if (ConsumeNullStmt(Stmts))<br>
+      continue;<br>
+<br>
     StmtResult R;<br>
     if (Tok.isNot(tok::kw___extension__)) {<br>
       R = ParseStatementOrDeclaration(Stmts, ACK_Any);<br>
@@ -1588,10 +1619,15 @@ StmtResult Parser::ParseForStatement(Sou<br>
   ParsedAttributesWithRange attrs(AttrFactory);<br>
   MaybeParseCXX11Attributes(attrs);<br>
<br>
+  SourceLocation EmptyInitStmtSemiLoc;<br>
+<br>
   // Parse the first part of the for specifier.<br>
   if (Tok.is(tok::semi)) {  // for (;<br>
     ProhibitAttributes(attrs);<br>
     // no first part, eat the ';'.<br>
+    SourceLocation SemiLoc = Tok.getLocation();<br>
+    if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID())<br>
+      EmptyInitStmtSemiLoc = SemiLoc;<br>
     ConsumeToken();<br>
   } else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) &&<br>
              isForRangeIdentifier()) {<br>
@@ -1723,6 +1759,11 @@ StmtResult Parser::ParseForStatement(Sou<br>
                    : diag::ext_for_range_init_stmt)<br>
               << (FirstPart.get() ? FirstPart.get()->getSourceRange()<br>
                                   : SourceRange());<br>
+          if (EmptyInitStmtSemiLoc.isValid()) {<br>
+            Diag(EmptyInitStmtSemiLoc, diag::warn_empty_init_statement)<br>
+                << /*for-loop*/ 2<br>
+                << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc);<br>
+          }<br>
         }<br>
       } else {<br>
         ExprResult SecondExpr = ParseExpression();<br>
<br>
Added: cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp?rev=347339&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp?rev=347339&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp (added)<br>
+++ cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt-in-init-statement.cpp Tue Nov 20 10:59:05 2018<br>
@@ -0,0 +1,64 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -Wextra -std=c++2a -verify %s<br>
+// RUN: %clang_cc1 -fsyntax-only -Wextra-semi-stmt -std=c++2a -verify %s<br>
+// RUN: %clang_cc1 -fsyntax-only -Wempty-init-stmt -std=c++2a -verify %s<br>
+// RUN: cp %s %t<br>
+// RUN: %clang_cc1 -x c++ -Wempty-init-stmt -std=c++2a -fixit %t<br>
+// RUN: %clang_cc1 -x c++ -Wempty-init-stmt -std=c++2a -Werror %t<br>
+<br>
+struct S {<br>
+  int *begin();<br>
+  int *end();<br>
+};<br>
+<br>
+void naive(int x) {<br>
+  if (; true) // expected-warning {{empty initialization statement of 'if' has no effect}}<br>
+    ;<br>
+<br>
+  switch (; x) { // expected-warning {{empty initialization statement of 'switch' has no effect}}<br>
+  }<br>
+<br>
+  for (; int y : S()) // expected-warning {{empty initialization statement of 'range-based for' has no effect}}<br>
+    ;<br>
+<br>
+  for (;;) // OK<br>
+    ;<br>
+}<br>
+<br>
+#define NULLMACRO<br>
+<br>
+void with_null_macro(int x) {<br>
+  if (NULLMACRO; true)<br>
+    ;<br>
+<br>
+  switch (NULLMACRO; x) {<br>
+  }<br>
+<br>
+  for (NULLMACRO; int y : S())<br>
+    ;<br>
+}<br>
+<br>
+#define SEMIMACRO ;<br>
+<br>
+void with_semi_macro(int x) {<br>
+  if (SEMIMACRO true)<br>
+    ;<br>
+<br>
+  switch (SEMIMACRO x) {<br>
+  }<br>
+<br>
+  for (SEMIMACRO int y : S())<br>
+    ;<br>
+}<br>
+<br>
+#define PASSTHROUGHMACRO(x) x<br>
+<br>
+void with_passthrough_macro(int x) {<br>
+  if (PASSTHROUGHMACRO(;) true)<br>
+    ;<br>
+<br>
+  switch (PASSTHROUGHMACRO(;) x) {<br>
+  }<br>
+<br>
+  for (PASSTHROUGHMACRO(;) int y : S())<br>
+    ;<br>
+}<br>
<br>
Added: cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp?rev=347339&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp?rev=347339&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp (added)<br>
+++ cfe/trunk/test/Parser/extra-semi-resulting-in-nullstmt.cpp Tue Nov 20 10:59:05 2018<br>
@@ -0,0 +1,96 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -Wextra-semi-stmt -verify %s<br>
+// RUN: cp %s %t<br>
+// RUN: %clang_cc1 -x c++ -Wextra-semi-stmt -fixit %t<br>
+// RUN: %clang_cc1 -x c++ -Wextra-semi-stmt -Werror %t<br>
+<br>
+#define GOODMACRO(varname) int varname<br>
+#define BETTERMACRO(varname) GOODMACRO(varname);<br>
+#define NULLMACRO(varname)<br>
+<br>
+enum MyEnum {<br>
+  E1,<br>
+  E2<br>
+};<br>
+<br>
+void test() {<br>
+  ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+  ;<br>
+<br>
+  // This removal of extra semi also consumes all the comments.<br>
+  // clang-format: off<br>
+  ;;;<br>
+  // clang-format: on<br>
+<br>
+  // clang-format: off<br>
+  ;NULLMACRO(ZZ);<br>
+  // clang-format: on<br>
+<br>
+  {}; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+<br>
+  {<br>
+    ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+  }<br>
+<br>
+  if (true) {<br>
+    ; // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+  }<br>
+<br>
+  GOODMACRO(v0); // OK<br>
+<br>
+  GOODMACRO(v1;) // OK<br>
+<br>
+  BETTERMACRO(v2) // OK<br>
+<br>
+  BETTERMACRO(v3;) // Extra ';', but within macro expansion, so ignored.<br>
+<br>
+  BETTERMACRO(v4); // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+<br>
+  BETTERMACRO(v5;); // expected-warning {{empty expression statement has no effect; remove unnecessary ';' to silence this warning}}<br>
+<br>
+  NULLMACRO(v6) // OK<br>
+<br>
+  NULLMACRO(v7); // OK. This could be either GOODMACRO() or BETTERMACRO() situation, so we can't know we can drop it.<br>
+<br>
+  if (true)<br>
+    ; // OK<br>
+<br>
+  while (true)<br>
+    ; // OK<br>
+<br>
+  do<br>
+    ; // OK<br>
+  while (true);<br>
+<br>
+  for (;;) // OK<br>
+    ;      // OK<br>
+<br>
+  MyEnum my_enum;<br>
+  switch (my_enum) {<br>
+  case E1:<br>
+    // stuff<br>
+    break;<br>
+  case E2:; // OK<br>
+  }<br>
+<br>
+  for (;;) {<br>
+    for (;;) {<br>
+      goto contin_outer;<br>
+    }<br>
+  contin_outer:; // OK<br>
+  }<br>
+}<br>
+<br>
+;<br>
+<br>
+namespace NS {};<br>
+<br>
+void foo(int x) {<br>
+  switch (x) {<br>
+  case 0:<br>
+    [[fallthrough]];<br>
+  case 1:<br>
+    return;<br>
+  }<br>
+}<br>
+<br>
+[[]];<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>