Hi rsmith, hfinkel,

According to the C11 standard, `_Static_assert` should be allowed as clause-1 
in a for loop.

For example:
```
for (_Static_assert(1, "1 is nonzero");;) {}
```

The relevant section of the C11 grammar is:
//for ( declaration expressionopt ; expressionopt ) statement
declaration:
  declaration-specifiers init-declarator-listopt ;
  static_assert-declaration//

It is not allowed in C++11, where the for statement has the form:
//for ( for-init-statement conditionopt; expressionopt) statement//
and for-init-statement can only be an //expression-statement// or a 
//simple-declaration//, not a //static_assert-declaration//

http://reviews.llvm.org/D9113

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseStmt.cpp
  lib/Sema/SemaStmt.cpp
  test/Parser/static-assert.c
  test/Parser/static-assert.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1803,7 +1803,7 @@
   /// isForInitDeclaration - Disambiguates between a declaration or an
   /// expression in the context of the C 'clause-1' or the C++
   // 'for-init-statement' part of a 'for' statement.
-  /// Returns true for declaration, false for expression.
+  /// Returns true for C declaration or C++ simple-declaration, false otherwise
   bool isForInitDeclaration() {
     if (getLangOpts().CPlusPlus)
       return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true);
@@ -2275,7 +2275,8 @@
                               SourceLocation &DeclEnd,
                               AccessSpecifier AS = AS_none,
                               Decl **OwnedType = nullptr);
-  Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd);
+  Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd,
+                                     bool RequireSemi = true);
   Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc,
                             SourceLocation AliasLoc, IdentifierInfo *Alias,
                             SourceLocation &DeclEnd);
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -684,7 +684,8 @@
 /// [C11]   static_assert-declaration:
 ///           _Static_assert ( constant-expression  ,  string-literal  ) ;
 ///
-Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
+Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd,
+                                           bool RequireSemi) {
   assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) &&
          "Not a static_assert declaration");
 
@@ -739,7 +740,8 @@
   T.consumeClose();
 
   DeclEnd = Tok.getLocation();
-  ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
+  if (RequireSemi)
+    ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
 
   return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
                                               AssertExpr.get(),
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -1553,9 +1553,17 @@
     ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
 
     SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-    DeclGroupPtrTy DG = ParseSimpleDeclaration(
-        Declarator::ForContext, DeclEnd, attrs, false,
-        MightBeForRangeStmt ? &ForRangeInit : nullptr);
+    DeclGroupPtrTy DG;
+    // in C11, the declaration may be a static_assert-declaration
+    if (Tok.is(tok::kw__Static_assert)) {
+      ProhibitAttributes(attrs);
+      DG = Actions.ConvertDeclToDeclGroup(
+          ParseStaticAssertDeclaration(DeclEnd, false));
+    } else {
+      DG = ParseSimpleDeclaration(
+          Declarator::ForContext, DeclEnd, attrs, false,
+          MightBeForRangeStmt ? &ForRangeInit : nullptr);
+    }
     FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
     if (ForRangeInit.ParsedForRangeDecl()) {
       Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -1612,6 +1612,9 @@
       // declare identifiers for objects having storage class 'auto' or
       // 'register'.
       for (auto *DI : DS->decls()) {
+        // C11: skip over static assertions
+        if (isa<StaticAssertDecl>(DI))
+          continue;
         VarDecl *VD = dyn_cast<VarDecl>(DI);
         if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage())
           VD = nullptr;
Index: test/Parser/static-assert.c
===================================================================
--- test/Parser/static-assert.c
+++ test/Parser/static-assert.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
+
+void f() {
+  for (_Static_assert(1, "1 is nonzero");;) {}
+  for (_Static_assert(0, "0 is nonzero");;) {} // expected-error {{static_assert failed "0 is nonzero"}}
+}
Index: test/Parser/static-assert.cpp
===================================================================
--- test/Parser/static-assert.cpp
+++ test/Parser/static-assert.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -xc++ -std=c++11 -fsyntax-only -verify %s
+
+void f() {
+  for (static_assert(1, "1 is nonzero");;) {} // expected-error {{expected expression}}
+  for (static_assert(0, "0 is nonzero");;) {} // expected-error {{expected expression}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to