forked from OSchip/llvm-project
Add #pragma clang attribute support to the external_source_symbol attribute
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 llvm-svn: 300712
This commit is contained in:
parent
2be153b240
commit
24952fbc6f
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue