diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3110,8 +3110,10 @@ void ActOnTranslationUnitScope(Scope *S); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, RecordDecl *&AnonRecord); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1863,8 +1863,8 @@ DeclEnd = Tok.getLocation(); if (RequireSemi) ConsumeToken(); RecordDecl *AnonRecord = nullptr; - Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS, AnonRecord); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); DS.complete(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; @@ -4358,8 +4358,8 @@ // declarator list is omitted." ProhibitAttributes(Attrs); RecordDecl *AnonRecord = nullptr; - Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS, AnonRecord); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); assert(!AnonRecord && "Did not expect anonymous struct or union here"); DS.complete(TheDecl); return; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2766,7 +2766,7 @@ RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( - getCurScope(), AS, DS, TemplateParams, false, AnonRecord); + getCurScope(), AS, DS, DeclAttrs, TemplateParams, false, AnonRecord); DS.complete(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -231,7 +231,7 @@ DeclEnd = ConsumeToken(); RecordDecl *AnonRecord = nullptr; Decl *Decl = Actions.ParsedFreeStandingDeclSpec( - getCurScope(), AS, DS, + getCurScope(), AS, DS, ParsedAttributesView::none(), TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams : MultiTemplateParamsArg(), TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1113,8 +1113,8 @@ ProhibitAttributes(Attrs, CorrectLocationForAttributes); ConsumeToken(); RecordDecl *AnonRecord = nullptr; - Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS, AnonRecord); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); DS.complete(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; 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 @@ -4629,11 +4629,12 @@ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Decl * -Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, - RecordDecl *&AnonRecord) { - return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false, - AnonRecord); +Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, + RecordDecl *&AnonRecord) { + return ParsedFreeStandingDeclSpec( + S, AS, DS, DeclAttrs, MultiTemplateParamsArg(), false, AnonRecord); } // The MS ABI changed between VS2013 and VS2015 with regard to numbers used to @@ -4846,11 +4847,12 @@ /// 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. -Decl * -Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, - MultiTemplateParamsArg TemplateParams, - bool IsExplicitInstantiation, - RecordDecl *&AnonRecord) { +Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, + MultiTemplateParamsArg TemplateParams, + bool IsExplicitInstantiation, + RecordDecl *&AnonRecord) { Decl *TagD = nullptr; TagDecl *Tag = nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -5089,7 +5091,7 @@ // Warn about ignored type attributes, for example: // __attribute__((aligned)) struct A; // Attributes should be placed after tag to apply to type declaration. - if (!DS.getAttributes().empty()) { + if (!DS.getAttributes().empty() || !DeclAttrs.empty()) { DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || @@ -5099,6 +5101,9 @@ for (const ParsedAttr &AL : DS.getAttributes()) Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + for (const ParsedAttr &AL : DeclAttrs) + Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) + << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); } } 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 @@ -6,9 +6,33 @@ __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \ // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}} __attribute__((visibility("hidden"))) __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \ - // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} + // 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}} + + // Test that we get the same warnings for type declarations nested in a record. + struct X { + __attribute__((visibility("hidden"))) __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}} + __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}} + __attribute__((visibility("hidden"))) __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \ + // 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}} + + // Also test [[]] attribute syntax. (On a non-nested declaration, these + // generate a hard "misplaced attributes" error, which we test for + // elsewhere.) + [[gnu::visibility("hidden")]] [[gnu::aligned]] class E; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}} + [[gnu::visibility("hidden")]] [[gnu::aligned]] struct F; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \ + // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}} + [[gnu::visibility("hidden")]] [[gnu::aligned]] union G; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \ + // 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}} + }; } namespace test2 { @@ -16,4 +40,16 @@ __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; + + 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; + + [[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; + }; }