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 an in-class 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 @@ -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/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/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,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/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/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}}