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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits