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, DefaultIgnore; +def err_anon_bitfield_member_init : Error< + "anonymous bit-field cannot have a default member initializer">; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; 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/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -4113,12 +4113,17 @@ DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. - if (!FirstDeclarator) + if (!FirstDeclarator) { + // However, this does not apply for [[]] attributes (which could show up + // before or after the __attribute__ attributes). + DiagnoseAndSkipCXX11Attributes(); MaybeParseGNUAttributes(DeclaratorInfo.D); + DiagnoseAndSkipCXX11Attributes(); + } /// 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); Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -2305,11 +2305,16 @@ 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 + // + // NOTE: the latter two productions are a proposed bugfix rather than the + // current grammar rules as of C++20. + if (Tok.isNot(tok::colon) && !isCXX11AttributeSpecifier()) ParseDeclarator(DeclaratorInfo); else DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation()); @@ -2342,7 +2347,11 @@ } // If attributes exist after the declarator, but before an '{', parse them. + // However, this does not apply for [[]] attributes (which could show up + // before or after the __attribute__ attributes). + DiagnoseAndSkipCXX11Attributes(); MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + DiagnoseAndSkipCXX11Attributes(); // For compatibility with code written to older Clang, also accept a // virt-specifier *after* the GNU attributes. @@ -2784,7 +2793,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. @@ -2933,7 +2947,11 @@ DeclaratorInfo.setCommaLoc(CommaLoc); // GNU attributes are allowed before the second and subsequent declarator. + // However, this does not apply for [[]] attributes (which could show up + // before or after the __attribute__ attributes). + DiagnoseAndSkipCXX11Attributes(); MaybeParseGNUAttributes(DeclaratorInfo); + DiagnoseAndSkipCXX11Attributes(); if (ParseCXXMemberDeclaratorBeforeInitializer( DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) 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/test/CXX/class/class.bit/p1.cpp =================================================================== --- /dev/null +++ clang/test/CXX/class/class.bit/p1.cpp @@ -0,0 +1,19 @@ +// 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 a default member initializer}} + int : 0 { 1 }; // expected-error {{anonymous bit-field cannot have a default member initializer}} + int : 0, d : 1 = 1; + int : 1 = 12, e : 1; // expected-error {{anonymous bit-field cannot have a default member initializer}} + int : 0, f : 1 = 1; + int g [[]] : 1 = 1; + int h [[]] : 1 {1}; + int i : foo() = foo(); + int j, [[]] k; // expected-error {{an attribute list cannot appear here}} +}; 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 a default member initializer}} }; } Index: clang/test/Parser/c2x-attributes.c =================================================================== --- clang/test/Parser/c2x-attributes.c +++ clang/test/Parser/c2x-attributes.c @@ -23,6 +23,9 @@ 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}} + int q, [[]] r; // expected-error {{an attribute list cannot appear here}} }; [[]] struct S2 { int a; }; // expected-error {{misplaced attributes}}