]> granicus.if.org Git - clang/commitdiff
Add #pragma clang attribute support to the external_source_symbol attribute
authorAlex Lorenz <arphaman@gmail.com>
Wed, 19 Apr 2017 15:52:11 +0000 (15:52 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Wed, 19 Apr 2017 15:52:11 +0000 (15:52 +0000)
Prior to this commit the external_source_symbol attribute wasn't supported by
#pragma clang attribute for the following two reasons:

- The Named attribute subject hasn't been supported by TableGen.
- There was no way to specify a subject match rule for #pragma clang attribute
 that could operate on a set of attribute subjects (e.g. the ones that derive
 from NamedDecl).

This commit fixes the two issues and thus adds external_source_symbol support to
#pragma clang attribute.

rdar://31169028

Differential Revision: https://reviews.llvm.org/D32176

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@300712 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
lib/Sema/SemaDeclAttr.cpp
test/Misc/pragma-attribute-supported-attributes-list.test
test/Sema/alloc-align-attr.c
utils/TableGen/ClangAttrEmitter.cpp

index 69dbdba3ec177d33892c7e64cd83f8d9ab464149..b6cb0f4607cf0cab6b1e573e30ef91c2e3e63489 100644 (file)
@@ -368,6 +368,16 @@ def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
   let LangOpts = [BlocksSupported];
 }
 
+// Aggregate attribute subject match rules are abstract match rules that can't
+// be used directly in #pragma clang attribute. Instead, users have to use
+// subject match rules that correspond to attribute subjects that derive from
+// the specified subject.
+class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
+  AttrSubject Subject = subject;
+}
+
+def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
+
 class Attr {
   // The various ways in which an attribute can be spelled in source
   list<Spelling> Spellings;
@@ -656,7 +666,7 @@ def ExternalSourceSymbol : InheritableAttr {
               StringArgument<"definedIn", 1>,
               BoolArgument<"generatedDeclaration", 1>];
   let HasCustomParsing = 1;
-//  let Subjects = SubjectList<[Named]>;
+  let Subjects = SubjectList<[Named]>;
   let Documentation = [ExternalSourceSymbolDocs];
 }
 
index ae941c88ca3eec813cf0deca707557ce15c4f49c..b87c8bfdd8b620d8053a3b10bbc863fbab8712f7 100644 (file)
@@ -2511,12 +2511,6 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
   assert(checkAttributeAtMostNumArgs(S, Attr, 3) &&
          "Invalid number of arguments in an external_source_symbol attribute");
 
-  if (!isa<NamedDecl>(D)) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << Attr.getName() << ExpectedNamedDecl;
-    return;
-  }
-
   StringRef Language;
   if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0)))
     Language = SE->getString();
@@ -5765,18 +5759,21 @@ static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) {
 static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
                                           const AttributeList &Attr) {
   // Several attributes carry different semantics than the parsing requires, so
-  // those are opted out of the common handling.
+  // those are opted out of the common argument checks.
   //
   // We also bail on unknown and ignored attributes because those are handled
   // as part of the target-specific handling logic.
-  if (Attr.hasCustomParsing() ||
-      Attr.getKind() == AttributeList::UnknownAttribute)
+  if (Attr.getKind() == AttributeList::UnknownAttribute)
     return false;
-
   // Check whether the attribute requires specific language extensions to be
   // enabled.
   if (!Attr.diagnoseLangOpts(S))
     return true;
+  // Check whether the attribute appertains to the given subject.
+  if (!Attr.diagnoseAppertainsTo(S, D))
+    return true;
+  if (Attr.hasCustomParsing())
+    return false;
 
   if (Attr.getMinArgs() == Attr.getMaxArgs()) {
     // If there are no optional arguments, then checking for the argument count
@@ -5793,10 +5790,6 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
       return true;
   }
 
-  // Check whether the attribute appertains to the given subject.
-  if (!Attr.diagnoseAppertainsTo(S, D))
-    return true;
-
   return false;
 }
 
index b1f2e66ab3397bc1e27054039f163a6f23b7fa0f..5b58ba51b989b72b3c240dc5071501a0f0663ceb 100644 (file)
@@ -2,7 +2,7 @@
 
 // The number of supported attributes should never go down!
 
-// CHECK: #pragma clang attribute supports 57 attributes:
+// CHECK: #pragma clang attribute supports 58 attributes:
 // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
 // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
@@ -23,6 +23,7 @@
 // CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: EnableIf (SubjectMatchRule_function)
 // CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum)
+// CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
 // CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
 // CHECK-NEXT: Flatten (SubjectMatchRule_function)
 // CHECK-NEXT: IFunc (SubjectMatchRule_function)
index bf8591625dab290a604156b21d6214985d73814f..ae514343aff4edee0269f69aa1ebf843be3b0056 100644 (file)
@@ -13,7 +13,7 @@ void *test_incorrect_param_type(float a) __attribute__((alloc_align(1))); // exp
 void *test_bad_param_type(void) __attribute((alloc_align(1.1))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
 
 // argument count
-void *test_no_fn_proto() __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}}
-void *test_no_fn_proto() __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}}
-void *test_no_fn_proto() __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto(int x, int y) __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto(int x, int y) __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto(int x, int y) __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}}
 
index 97b3c405900bab5af97ac045d3ae1bc9d539850b..98144567534350129c6392594ca0fbcb9d6539b7 100644 (file)
@@ -1611,7 +1611,36 @@ const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule";
 
 struct PragmaClangAttributeSupport {
   std::vector<AttributeSubjectMatchRule> Rules;
-  llvm::DenseMap<const Record *, AttributeSubjectMatchRule> SubjectsToRules;
+
+  class RuleOrAggregateRuleSet {
+    std::vector<AttributeSubjectMatchRule> Rules;
+    bool IsRule;
+    RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules,
+                           bool IsRule)
+        : Rules(Rules), IsRule(IsRule) {}
+
+  public:
+    bool isRule() const { return IsRule; }
+
+    const AttributeSubjectMatchRule &getRule() const {
+      assert(IsRule && "not a rule!");
+      return Rules[0];
+    }
+
+    ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const {
+      return Rules;
+    }
+
+    static RuleOrAggregateRuleSet
+    getRule(const AttributeSubjectMatchRule &Rule) {
+      return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true);
+    }
+    static RuleOrAggregateRuleSet
+    getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) {
+      return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false);
+    }
+  };
+  llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules;
 
   PragmaClangAttributeSupport(RecordKeeper &Records);
 
@@ -1626,6 +1655,15 @@ struct PragmaClangAttributeSupport {
 
 } // end anonymous namespace
 
+static bool doesDeclDeriveFrom(const Record *D, const Record *Base) {
+  const Record *CurrentBase = D->getValueAsDef("Base");
+  if (!CurrentBase)
+    return false;
+  if (CurrentBase == Base)
+    return true;
+  return doesDeclDeriveFrom(CurrentBase, Base);
+}
+
 PragmaClangAttributeSupport::PragmaClangAttributeSupport(
     RecordKeeper &Records) {
   std::vector<Record *> MetaSubjects =
@@ -1638,7 +1676,11 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport(
         SubjectContainer->getValueAsListOfDefs("Subjects");
     for (const auto *Subject : ApplicableSubjects) {
       bool Inserted =
-          SubjectsToRules.try_emplace(Subject, MetaSubject, Constraint).second;
+          SubjectsToRules
+              .try_emplace(Subject, RuleOrAggregateRuleSet::getRule(
+                                        AttributeSubjectMatchRule(MetaSubject,
+                                                                  Constraint)))
+              .second;
       if (!Inserted) {
         PrintFatalError("Attribute subject match rules should not represent"
                         "same attribute subjects.");
@@ -1652,6 +1694,37 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport(
     for (const auto *Constraint : Constraints)
       MapFromSubjectsToRules(Constraint, MetaSubject, Constraint);
   }
+
+  std::vector<Record *> Aggregates =
+      Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule");
+  std::vector<Record *> DeclNodes = Records.getAllDerivedDefinitions("DDecl");
+  for (const auto *Aggregate : Aggregates) {
+    Record *SubjectDecl = Aggregate->getValueAsDef("Subject");
+
+    // Gather sub-classes of the aggregate subject that act as attribute
+    // subject rules.
+    std::vector<AttributeSubjectMatchRule> Rules;
+    for (const auto *D : DeclNodes) {
+      if (doesDeclDeriveFrom(D, SubjectDecl)) {
+        auto It = SubjectsToRules.find(D);
+        if (It == SubjectsToRules.end())
+          continue;
+        if (!It->second.isRule() || It->second.getRule().isSubRule())
+          continue; // Assume that the rule will be included as well.
+        Rules.push_back(It->second.getRule());
+      }
+    }
+
+    bool Inserted =
+        SubjectsToRules
+            .try_emplace(SubjectDecl,
+                         RuleOrAggregateRuleSet::getAggregateRuleSet(Rules))
+            .second;
+    if (!Inserted) {
+      PrintFatalError("Attribute subject match rules should not represent"
+                      "same attribute subjects.");
+    }
+  }
 }
 
 static PragmaClangAttributeSupport &
@@ -1738,24 +1811,25 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
     auto It = SubjectsToRules.find(Subject);
     assert(It != SubjectsToRules.end() &&
            "This attribute is unsupported by #pragma clang attribute");
-    AttributeSubjectMatchRule Rule = It->getSecond();
-    // The rule might be language specific, so only subtract it from the given
-    // rules if the specific language options are specified.
-    std::vector<Record *> LangOpts = Rule.getLangOpts();
-    SS << "  MatchRules.push_back(std::make_pair(" << Rule.getEnumValue()
-       << ", /*IsSupported=*/";
-    if (!LangOpts.empty()) {
-      for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
-        std::string Part = (*I)->getValueAsString("Name");
-        if ((*I)->getValueAsBit("Negated"))
-          SS << "!";
-        SS << "LangOpts." + Part;
-        if (I + 1 != E)
-          SS << " || ";
-      }
-    } else
-      SS << "true";
-    SS << "));\n";
+    for (const auto &Rule : It->getSecond().getAggregateRuleSet()) {
+      // The rule might be language specific, so only subtract it from the given
+      // rules if the specific language options are specified.
+      std::vector<Record *> LangOpts = Rule.getLangOpts();
+      SS << "  MatchRules.push_back(std::make_pair(" << Rule.getEnumValue()
+         << ", /*IsSupported=*/";
+      if (!LangOpts.empty()) {
+        for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
+          std::string Part = (*I)->getValueAsString("Name");
+          if ((*I)->getValueAsBit("Negated"))
+            SS << "!";
+          SS << "LangOpts." + Part;
+          if (I + 1 != E)
+            SS << " || ";
+        }
+      } else
+        SS << "true";
+      SS << "));\n";
+    }
   }
   SS << "}\n\n";
   OS << SS.str();
@@ -2937,7 +3011,8 @@ static std::string CalculateDiagnostic(const Record &S) {
     Field = 1U << 12,
     CXXMethod = 1U << 13,
     ObjCProtocol = 1U << 14,
-    Enum = 1U << 15
+    Enum = 1U << 15,
+    Named = 1U << 16,
   };
   uint32_t SubMask = 0;
 
@@ -2972,6 +3047,7 @@ static std::string CalculateDiagnostic(const Record &S) {
                    .Case("Field", Field)
                    .Case("CXXMethod", CXXMethod)
                    .Case("Enum", Enum)
+                   .Case("Named", Named)
                    .Default(0);
     if (!V) {
       // Something wasn't in our mapping, so be helpful and let the developer
@@ -3030,6 +3106,9 @@ static std::string CalculateDiagnostic(const Record &S) {
     case ObjCProtocol | ObjCInterface:
       return "ExpectedObjectiveCInterfaceOrProtocol";
     case Field | Var: return "ExpectedFieldOrGlobalVar";
+
+    case Named:
+      return "ExpectedNamedDecl";
   }
 
   PrintFatalError(S.getLoc(),
@@ -3754,9 +3833,19 @@ void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
     for (const auto &Subject : llvm::enumerate(Subjects)) {
       if (Subject.index())
         OS << ", ";
-      OS << Support.SubjectsToRules.find(Subject.value())
-                ->getSecond()
-                .getEnumValueName();
+      PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet =
+          Support.SubjectsToRules.find(Subject.value())->getSecond();
+      if (RuleSet.isRule()) {
+        OS << RuleSet.getRule().getEnumValueName();
+        continue;
+      }
+      OS << "(";
+      for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) {
+        if (Rule.index())
+          OS << ", ";
+        OS << Rule.value().getEnumValueName();
+      }
+      OS << ")";
     }
     OS << ")\n";
   }