arphaman created this revision.
Right now the `external_source_symbol` attribute isn't supported by `#pragma
clang attribute` for the following two reasons:
- The `Named` attribute subject isn't 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 patch fixes the two issues and thus adds `external_source_symbol` support
to `#pragma clang attribute`,
Repository:
rL LLVM
https://reviews.llvm.org/D32176
Files:
include/clang/Basic/Attr.td
lib/Sema/SemaDeclAttr.cpp
test/Misc/pragma-attribute-supported-attributes-list.test
utils/TableGen/ClangAttrEmitter.cpp
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -1611,7 +1611,36 @@
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.begin(), Rules.end()), IsRule(IsRule) {}
+
+ public:
+ bool isRule() const { return IsRule; }
+
+ AttributeSubjectMatchRule &getRule() {
+ 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 @@
} // 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 @@
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 @@
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 Record *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 @@
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 @@
Field = 1U << 12,
CXXMethod = 1U << 13,
ObjCProtocol = 1U << 14,
- Enum = 1U << 15
+ Enum = 1U << 15,
+ Named = 1U << 16,
};
uint32_t SubMask = 0;
@@ -2956,23 +3031,24 @@
Name = R.getName();
uint32_t V = StringSwitch<uint32_t>(Name)
- .Case("Function", Func)
- .Case("Var", Var)
- .Case("ObjCMethod", ObjCMethod)
- .Case("ParmVar", Param)
- .Case("TypedefName", Type)
- .Case("ObjCIvar", ObjCIVar)
- .Case("ObjCProperty", ObjCProp)
- .Case("Record", GenericRecord)
- .Case("ObjCInterface", ObjCInterface)
- .Case("ObjCProtocol", ObjCProtocol)
- .Case("Block", Block)
- .Case("CXXRecord", Class)
- .Case("Namespace", Namespace)
- .Case("Field", Field)
- .Case("CXXMethod", CXXMethod)
- .Case("Enum", Enum)
- .Default(0);
+ .Case("Function", Func)
+ .Case("Var", Var)
+ .Case("ObjCMethod", ObjCMethod)
+ .Case("ParmVar", Param)
+ .Case("TypedefName", Type)
+ .Case("ObjCIvar", ObjCIVar)
+ .Case("ObjCProperty", ObjCProp)
+ .Case("Record", GenericRecord)
+ .Case("ObjCInterface", ObjCInterface)
+ .Case("ObjCProtocol", ObjCProtocol)
+ .Case("Block", Block)
+ .Case("CXXRecord", Class)
+ .Case("Namespace", Namespace)
+ .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
// know about it.
@@ -2998,7 +3074,7 @@
case Type: return "ExpectedType";
case ObjCInterface: return "ExpectedObjectiveCInterface";
case ObjCProtocol: return "ExpectedObjectiveCProtocol";
-
+
// "GenericRecord" means struct, union or class; check the language options
// and if not compiling for C++, strip off the class part. Note that this
// relies on the fact that the context for this declares "Sema &S".
@@ -3030,6 +3106,9 @@
case ObjCProtocol | ObjCInterface:
return "ExpectedObjectiveCInterfaceOrProtocol";
case Field | Var: return "ExpectedFieldOrGlobalVar";
+
+ case Named:
+ return "ExpectedNamedDecl";
}
PrintFatalError(S.getLoc(),
@@ -3754,9 +3833,18 @@
for (const auto &Subject : llvm::enumerate(Subjects)) {
if (Subject.index())
OS << ", ";
- OS << Support.SubjectsToRules.find(Subject.value())
- ->getSecond()
- .getEnumValueName();
+ auto 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";
}
Index: test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- test/Misc/pragma-attribute-supported-attributes-list.test
+++ test/Misc/pragma-attribute-supported-attributes-list.test
@@ -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: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2511,12 +2511,6 @@
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,12 +5759,18 @@
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 majority of common handling.
//
// 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.hasCustomParsing()) {
+ // Still check whether the attribute appertains to the given subject as it
+ // might include a subject list even when it has custom parsing.
+ if (!Attr.diagnoseAppertainsTo(S, D))
+ return true;
+ return false;
+ }
+ if (Attr.getKind() == AttributeList::UnknownAttribute)
return false;
// Check whether the attribute requires specific language extensions to be
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -368,6 +368,16 @@
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 @@
StringArgument<"definedIn", 1>,
BoolArgument<"generatedDeclaration", 1>];
let HasCustomParsing = 1;
-// let Subjects = SubjectList<[Named]>;
+ let Subjects = SubjectList<[Named]>;
let Documentation = [ExternalSourceSymbolDocs];
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits