egorzhdan created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a subscriber: jdoerfert.
egorzhdan requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This change adds support for type attributes (for example, `address_space`) in 
pragmas, so that the following code now compiles correctly:

  #pragma clang attribute push (__attribute__ ((address_space(1))), 
apply_to=variable(is_global))
  
  int var;
  
  #pragma clang attribute pop

Since the attribute matching logic (`attr::SubjectMatchRule`) applies to an 
already constructed `Decl`, we first determine the declaration's type ignoring 
pragma attributes, then construct the `Decl`, and then recalculate its type if 
any type attribute was applied.

rdar://78269223


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D117931

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/address_space_attribute.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/Parser/pragma-attribute.cpp

Index: clang/test/Parser/pragma-attribute.cpp
===================================================================
--- clang/test/Parser/pragma-attribute.cpp
+++ 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
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ 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)
Index: clang/test/AST/address_space_attribute.cpp
===================================================================
--- clang/test/AST/address_space_attribute.cpp
+++ 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
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ 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<ValueDecl>(D))
+    AddPragmaTypeAttributes(S, VD, PD);
 }
 
 /// Is the given declaration allowed to use a forbidden type?
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ 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<bool(ParsedAttr *)> 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(),
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ 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.
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ 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];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to