diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -632,6 +632,7 @@ def AddressSpace : TypeAttr { let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; + let PragmaAttributeSupport = 1; let Documentation = [Undocumented]; } 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 @@ -4347,7 +4347,7 @@ void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. - void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); + void ProcessDeclAttributes(Scope *S, Decl *D, Declarator &PD); // Helper for delayed processing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList); @@ -10217,6 +10217,12 @@ /// '\#pragma clang attribute push' directives to the given declaration. void AddPragmaAttributes(Scope *S, Decl *D); + /// Adds the type attributes (e.g. address_space) that have been specified + /// using the '\#pragma clang attribute push' directives to the given + /// declaration's type. + void AddPragmaTypeAttributes(Scope *TheScope, ValueDecl *TheDecl, + Declarator &TheDeclarator); + void DiagnoseUnterminatedPragmaAttribute(); /// Called on well formed \#pragma clang optimize. diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -972,10 +972,12 @@ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1; } -void Sema::AddPragmaAttributes(Scope *S, Decl *D) { - if (PragmaAttributeStack.empty()) +static void +forEachPragmaAttribute(Sema *TheSema, Decl *TheDecl, + llvm::function_ref Block) { + if (TheSema->PragmaAttributeStack.empty()) return; - for (auto &Group : PragmaAttributeStack) { + for (auto &Group : TheSema->PragmaAttributeStack) { for (auto &Entry : Group.Entries) { ParsedAttr *Attribute = Entry.Attribute; assert(Attribute && "Expected an attribute"); @@ -985,23 +987,51 @@ // Ensure that the attribute can be applied to the given declaration. bool Applies = false; for (const auto &Rule : Entry.MatchRules) { - if (Attribute->appliesToDecl(D, Rule)) { + if (Attribute->appliesToDecl(TheDecl, Rule)) { Applies = true; break; } } if (!Applies) continue; - Entry.IsUsed = true; - PragmaAttributeCurrentTargetDecl = D; - ParsedAttributesView Attrs; - Attrs.addAtEnd(Attribute); - ProcessDeclAttributeList(S, D, Attrs); - PragmaAttributeCurrentTargetDecl = nullptr; + TheSema->PragmaAttributeCurrentTargetDecl = TheDecl; + Entry.IsUsed |= Block(Attribute); + TheSema->PragmaAttributeCurrentTargetDecl = nullptr; } } } +void Sema::AddPragmaAttributes(Scope *S, Decl *D) { + forEachPragmaAttribute(this, D, [&](ParsedAttr *Attribute) { + if (Attribute->isTypeAttr()) + return false; + + ParsedAttributesView Attrs; + Attrs.addAtEnd(Attribute); + ProcessDeclAttributeList(S, D, Attrs); + return true; + }); +} + +void Sema::AddPragmaTypeAttributes(Scope *TheScope, ValueDecl *TheDecl, + Declarator &TheDeclarator) { + bool AddedTypeAttrs = false; + forEachPragmaAttribute(this, TheDecl, [&](ParsedAttr *Attribute) { + if (!Attribute->isTypeAttr()) + return false; + + TheDeclarator.getAttributes().addAtEnd(Attribute); + AddedTypeAttrs = true; + return true; + }); + + if (AddedTypeAttrs) { + // Recalculate the type of the declaration after type attributes were added. + TypeSourceInfo *NewType = GetTypeForDeclarator(TheDeclarator, TheScope); + TheDecl->setType(NewType->getType()); + } +} + void Sema::PrintPragmaAttributeInstantiationPoint() { assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration"); Diags.Report(PragmaAttributeCurrentTargetDecl->getBeginLoc(), diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -9017,7 +9017,7 @@ /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in /// it, apply them to D. This is a bit tricky because PD can have attributes /// specified in many different places, and we need to find and apply them all. -void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { +void Sema::ProcessDeclAttributes(Scope *S, Decl *D, Declarator &PD) { // Apply decl attributes from the DeclSpec if present. if (!PD.getDeclSpec().getAttributes().empty()) ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes()); @@ -9035,6 +9035,8 @@ // Apply additional attributes specified by '#pragma clang attribute'. AddPragmaAttributes(S, D); + if (auto *VD = dyn_cast(D)) + AddPragmaTypeAttributes(S, VD, PD); } /// Is the given declaration allowed to use a forbidden type? diff --git a/clang/test/AST/address_space_attribute.cpp b/clang/test/AST/address_space_attribute.cpp --- a/clang/test/AST/address_space_attribute.cpp +++ b/clang/test/AST/address_space_attribute.cpp @@ -28,3 +28,19 @@ void func2() { func<2>(); } + +#pragma clang attribute push (__attribute__((address_space(4))), apply_to=variable(is_global)) +volatile int f; +// CHECK: VarDecl {{.*}} 'volatile __attribute__((address_space(4))) int' +#pragma clang attribute pop + +#pragma clang attribute push (__attribute__((address_space(5))), apply_to=variable(is_parameter)) +void func3(volatile int g) {} +// CHECK: ParmVarDecl {{.*}} 'volatile __attribute__((address_space(5))) int' +#pragma clang attribute pop + +#pragma clang attribute push (__attribute__((address_space(6))), apply_to=field) +volatile int g; +// Verify that the attribute is not applied to a declaration that does not match the filter. +// CHECK: VarDecl {{.*}} 'volatile int' +#pragma clang attribute pop diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -10,6 +10,7 @@ // CHECK-NEXT: AVRSignal (SubjectMatchRule_function) // CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace) // CHECK-NEXT: AcquireHandle (SubjectMatchRule_function, SubjectMatchRule_type_alias, SubjectMatchRule_variable_is_parameter) +// CHECK-NEXT: AddressSpace () // CHECK-NEXT: Alias (SubjectMatchRule_function, SubjectMatchRule_variable_is_global) // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias) // CHECK-NEXT: AlwaysDestroy (SubjectMatchRule_variable) diff --git a/clang/test/Parser/pragma-attribute.cpp b/clang/test/Parser/pragma-attribute.cpp --- a/clang/test/Parser/pragma-attribute.cpp +++ b/clang/test/Parser/pragma-attribute.cpp @@ -142,8 +142,6 @@ _Pragma("clang attribute pop"); -#pragma clang attribute push (__attribute__((address_space(0))), apply_to=variable) // expected-error {{attribute 'address_space' is not supported by '#pragma clang attribute'}} - // Check support for CXX11 style attributes #pragma clang attribute push ([[noreturn]], apply_to = any(function)) #pragma clang attribute pop