diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -331,6 +331,8 @@ Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed a bug where attribute annotations on type specifiers (enums, classes, structs, unions, and scoped enums) were not properly ignored, resulting in misleading warning messages. Now, such attribute annotations are correctly ignored. +(`#61660 `_) Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2666,7 +2666,7 @@ def err_invalid_constexpr_member : Error<"non-static data member cannot be " "constexpr%select{; did you intend to make it %select{const|static}0?|}1">; def err_constexpr_tag : Error< - "%select{class|struct|interface|union|enum}0 " + "%select{class|struct|interface|union|enum|enum class|enum struct}0 " "cannot be marked %sub{select_constexpr_spec_kind}1">; def err_constexpr_dtor : Error< "destructor cannot be declared %sub{select_constexpr_spec_kind}0">; @@ -3423,7 +3423,7 @@ InGroup; def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after " - "\"%select{class|struct|interface|union|enum}1\" to apply attribute to " + "\"%select{class|struct|interface|union|enum|enum class|enum struct}1\" to apply attribute to " "type declaration">, InGroup; def warn_attribute_precede_definition : Warning< "attribute declaration must precede definition">, @@ -6928,7 +6928,7 @@ def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration " "of a type">, InGroup; def err_standalone_class_nested_name_specifier : Error< - "forward declaration of %select{class|struct|interface|union|enum}0 cannot " + "forward declaration of %select{class|struct|interface|union|enum|enum class|enum struct}0 cannot " "have a nested name specifier">; def err_typecheck_sclass_func : Error<"illegal storage class on function">; def err_static_block_func : Error< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5033,7 +5033,8 @@ TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); } -static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { +static unsigned GetDiagnosticTypeSpecifierID(const DeclSpec &DS) { + DeclSpec::TST T = DS.getTypeSpecType(); switch (T) { case DeclSpec::TST_class: return 0; @@ -5044,12 +5045,17 @@ case DeclSpec::TST_union: return 3; case DeclSpec::TST_enum: + if (const auto *ED = dyn_cast(DS.getRepAsDecl())) { + if (ED->isScopedUsingClassTag()) + return 5; + if (ED->isScoped()) + return 6; + } return 4; default: llvm_unreachable("unexpected type specifier"); } } - /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. @@ -5107,7 +5113,7 @@ // the declaration of a function or function template if (Tag) Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) - << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) + << GetDiagnosticTypeSpecifierID(DS) << static_cast(DS.getConstexprSpecifier()); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind) @@ -5141,7 +5147,7 @@ // // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either. Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) - << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << SS.getRange(); + << GetDiagnosticTypeSpecifierID(DS) << SS.getRange(); return nullptr; } @@ -5306,10 +5312,10 @@ TypeSpecType == DeclSpec::TST_enum) { for (const ParsedAttr &AL : DS.getAttributes()) Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) - << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + << AL << GetDiagnosticTypeSpecifierID(DS); for (const ParsedAttr &AL : DeclAttrs) Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) - << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + << AL << GetDiagnosticTypeSpecifierID(DS); } } diff --git a/clang/test/SemaCXX/attr-declspec-ignored.cpp b/clang/test/SemaCXX/attr-declspec-ignored.cpp --- a/clang/test/SemaCXX/attr-declspec-ignored.cpp +++ b/clang/test/SemaCXX/attr-declspec-ignored.cpp @@ -9,6 +9,10 @@ // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \ // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}} + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum class EC {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum class" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum class" to apply attribute to type declaration}} + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum struct ES {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum struct" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum struct" to apply attribute to type declaration}} // Test that we get the same warnings for type declarations nested in a record. struct X { @@ -20,7 +24,11 @@ // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \ // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}} - + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum class EC {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum class" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum class" to apply attribute to type declaration}} + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum struct ES {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum struct" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum struct" to apply attribute to type declaration}} + // Also test [[]] attribute syntax. (On a non-nested declaration, these // generate a hard "misplaced attributes" error, which we test for // elsewhere.) @@ -32,6 +40,10 @@ // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} [[gnu::visibility("hidden")]] [[gnu::aligned]] enum H {H}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \ // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}} + [[gnu::visibility("hidden")]] [[gnu::aligned]] enum class I {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum class" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum class" to apply attribute to type declaration}} + [[gnu::visibility("hidden")]] [[gnu::aligned]] enum struct J {}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum struct" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "enum struct" to apply attribute to type declaration}} }; } @@ -40,16 +52,22 @@ __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B {} b; __attribute__((visibility("hidden"))) __attribute__((aligned)) union C {} c; __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D} d; + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum class EC {} ec; + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum struct ES {} es; struct X { __attribute__((visibility("hidden"))) __attribute__((aligned)) class A {} a; __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B {} b; __attribute__((visibility("hidden"))) __attribute__((aligned)) union C {} c; __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D} d; + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum class EC {} ec; + __attribute__((visibility("hidden"))) __attribute__((aligned)) enum struct ES {} es; [[gnu::visibility("hidden")]] [[gnu::aligned]] class E {} e; [[gnu::visibility("hidden")]] [[gnu::aligned]] struct F {} f; [[gnu::visibility("hidden")]] [[gnu::aligned]] union G {} g; [[gnu::visibility("hidden")]] [[gnu::aligned]] enum H {H} h; + [[gnu::visibility("hidden")]] [[gnu::aligned]] enum class I {} i; + [[gnu::visibility("hidden")]] [[gnu::aligned]] enum struct J {} j; }; }