aaron.ballman updated this revision to Diff 294554.
aaron.ballman retitled this revision from "Correctly parse attributes on the 
declaration of an anonymous bit-field" to "Better diagnostics for anonymous 
bit-fields with attributes or an initializer".
aaron.ballman added a comment.
Herald added a reviewer: jdoerfert.

I've updated the patch to continue to reject attributes on anonymous 
bit-fields, but with a better diagnostic. In addition, I changed how we handle 
anonymous bit-fields with an initializer (based on discussion on the Core 
reflector) -- instead of rejecting the construct as a semantic issue, I reject 
it at the parser level with a similar diagnostic (I went with "in-class 
initializer" because that's used by other parser diagnostics, but I'm fine with 
either formulation).


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88333/new/

https://reviews.llvm.org/D88333

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CXX/class/class.bit/p1.cpp
  clang/test/Parser/MicrosoftExtensions.cpp
  clang/test/Parser/c2x-attributes.c

Index: clang/test/Parser/c2x-attributes.c
===================================================================
--- clang/test/Parser/c2x-attributes.c
+++ clang/test/Parser/c2x-attributes.c
@@ -23,6 +23,8 @@
   int l[[]][10];
   [[]] int m, n;
   int o [[]] : 12;
+  int [[]] : 0; // OK, attribute applies to the type.
+  int p, [[]] : 0; // expected-error {{an attribute list cannot appear here}}
 };
 
 [[]] struct S2 { int a; }; // expected-error {{misplaced attributes}}
Index: clang/test/Parser/MicrosoftExtensions.cpp
===================================================================
--- clang/test/Parser/MicrosoftExtensions.cpp
+++ clang/test/Parser/MicrosoftExtensions.cpp
@@ -466,6 +466,6 @@
     // MSVC produces a "C4353 constant 0 as function expression" for this,
     // considering the final {} to be part of the bit-width. We follow P0683R1
     // and treat it as a default member initializer.
-    enum E : int : int{}{}; // expected-error {{anonymous bit-field cannot have a default member initializer}} expected-warning {{C++20 extension}}
+    enum E : int : int{}{}; // expected-error {{anonymous bit-field cannot have an in-class initializer}}
   };
 }
Index: clang/test/CXX/class/class.bit/p1.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/class/class.bit/p1.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+// Test various bit-field member declarations.
+constexpr int foo() { return 1; }
+struct A {
+  int a [[]] : 1;
+  int b, [[]] : 0; // expected-error {{an attribute list cannot appear here}}
+  int [[]] : 0; // OK, attribute applies to the type.
+  int [[]] c : 1; // OK, attribute applies to the type.
+  int : 2 = 1; // expected-error {{anonymous bit-field cannot have an in-class initializer}}
+  int : 0 { 1 }; // expected-error {{anonymous bit-field cannot have an in-class initializer}}
+  int : 0, d : 1 = 1;
+  int : 1 = 12, e : 1; // expected-error {{anonymous bit-field cannot have an in-class initializer}}
+  int : 0, f : 1 = 1;
+  int g [[]] : 1 = 1;
+  int h [[]] : 1 {1};
+  int i : foo() = foo();
+};
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -16707,14 +16707,6 @@
       BitWidth = nullptr;
       ZeroWidth = false;
     }
-
-    // Only data members can have in-class initializers.
-    if (BitWidth && !II && InitStyle) {
-      Diag(Loc, diag::err_anon_bitfield_init);
-      InvalidDecl = true;
-      BitWidth = nullptr;
-      ZeroWidth = false;
-    }
   }
 
   // Check that 'mutable' is consistent with the type of the declaration.
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -2305,14 +2305,21 @@
     Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize,
     LateParsedAttrList &LateParsedAttrs) {
   // member-declarator:
-  //   declarator pure-specifier[opt]
+  //   declarator virt-specifier-seq[opt] pure-specifier[opt]
   //   declarator requires-clause
   //   declarator brace-or-equal-initializer[opt]
-  //   identifier[opt] ':' constant-expression
-  if (Tok.isNot(tok::colon))
+  //   identifier attribute-specifier-seq[opt] ':' constant-expression
+  //       brace-or-equal-initializer[opt]
+  //   ':' constant-expression
+  if (Tok.isNot(tok::colon) && !isCXX11AttributeSpecifier())
     ParseDeclarator(DeclaratorInfo);
-  else
+  else {
     DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
+    // Anonymous bit-fields cannot specify attributes; the attributes appertain
+    // to the type specifier for the bit-field instead. Provide a kinder
+    // parsing error than if we just let parsing happen organically.
+    DiagnoseAndSkipCXX11Attributes();
+  }
 
   if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
     assert(DeclaratorInfo.isPastIdentifier() &&
@@ -2784,7 +2791,12 @@
     InClassInitStyle HasInClassInit = ICIS_NoInit;
     bool HasStaticInitializer = false;
     if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) {
-      if (DeclaratorInfo.isDeclarationOfFunction()) {
+      // DRXXXX: Anonymous bit-fields cannot have a brace-or-equal-initializer.
+      if (BitfieldSize.isUsable() && !DeclaratorInfo.hasName()) {
+        // Diagnose the error and pretend there is no in-class initializer.
+        Diag(Tok, diag::err_anon_bitfield_member_init);
+        SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+      } else if (DeclaratorInfo.isDeclarationOfFunction()) {
         // It's a pure-specifier.
         if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false))
           // Parse it as an expression so that Sema can diagnose it.
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4118,12 +4118,17 @@
 
     /// struct-declarator: declarator
     /// struct-declarator: declarator[opt] ':' constant-expression
-    if (Tok.isNot(tok::colon)) {
+    if (Tok.isNot(tok::colon) && !isCXX11AttributeSpecifier()) {
       // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
       ColonProtectionRAIIObject X(*this);
       ParseDeclarator(DeclaratorInfo.D);
-    } else
+    } else {
       DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation());
+      // Anonymous bit-fields cannot specify attributes; the attributes
+      // appertain to the type specifier for the bit-field instead. Provide a
+      // kinder parsing error than if we just let parsing happen organically.
+      DiagnoseAndSkipCXX11Attributes();
+    }
 
     if (TryConsumeToken(tok::colon)) {
       ExprResult Res(ParseConstantExpression());
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5619,8 +5619,6 @@
 def err_anon_bitfield_width_exceeds_type_width : Error<
   "width of anonymous bit-field (%0 bits) exceeds %select{width|size}1 "
   "of its type (%2 bit%s2)">;
-def err_anon_bitfield_init : Error<
-  "anonymous bit-field cannot have a default member initializer">;
 def err_incorrect_number_of_vector_initializers : Error<
   "number of elements must be either one or match the size of the vector">;
 
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -872,6 +872,8 @@
 def warn_cxx17_compat_bitfield_member_init: Warning<
   "default member initializer for bit-field is incompatible with "
   "C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
+def err_anon_bitfield_member_init : Error<
+  "anonymous bit-field cannot have an in-class initializer">;
 def err_incomplete_array_member_init: Error<
   "array bound cannot be deduced from an in-class initializer">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D88333: B... Aaron Ballman via Phabricator via cfe-commits

Reply via email to