diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-20 21:20:51 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-20 21:20:51 +0000 |
commit | 583e75cce441388bc562fa225d23499261a0091e (patch) | |
tree | 5944a7c248d4a8c858db45abc3444eb69270a3c8 /utils | |
parent | 7442d6faa2719e4e7d33a7021c406c5a4facd74d (diff) | |
download | src-583e75cce441388bc562fa225d23499261a0091e.tar.gz src-583e75cce441388bc562fa225d23499261a0091e.zip |
Vendor import of clang trunk r300890:vendor/clang/clang-trunk-r300890
Notes
Notes:
svn path=/vendor/clang/dist/; revision=317220
svn path=/vendor/clang/clang-trunk-r300890/; revision=317221; tag=vendor/clang/clang-trunk-r300890
Diffstat (limited to 'utils')
-rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 536 | ||||
-rw-r--r-- | utils/TableGen/TableGen.cpp | 31 | ||||
-rw-r--r-- | utils/TableGen/TableGenBackends.h | 6 |
3 files changed, 560 insertions, 13 deletions
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 8aaa28beaac2..981445675343 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -12,13 +12,15 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -1522,6 +1524,408 @@ static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; } +static bool hasGNUorCXX11Spelling(const Record &Attribute) { + std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); + for (const auto &I : Spellings) { + if (I.variety() == "GNU" || I.variety() == "CXX11") + return true; + } + return false; +} + +namespace { + +struct AttributeSubjectMatchRule { + const Record *MetaSubject; + const Record *Constraint; + + AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint) + : MetaSubject(MetaSubject), Constraint(Constraint) { + assert(MetaSubject && "Missing subject"); + } + + bool isSubRule() const { return Constraint != nullptr; } + + std::vector<Record *> getSubjects() const { + return (Constraint ? Constraint : MetaSubject) + ->getValueAsListOfDefs("Subjects"); + } + + std::vector<Record *> getLangOpts() const { + if (Constraint) { + // Lookup the options in the sub-rule first, in case the sub-rule + // overrides the rules options. + std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts"); + if (!Opts.empty()) + return Opts; + } + return MetaSubject->getValueAsListOfDefs("LangOpts"); + } + + // Abstract rules are used only for sub-rules + bool isAbstractRule() const { return getSubjects().empty(); } + + std::string getName() const { + return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name"); + } + + bool isNegatedSubRule() const { + assert(isSubRule() && "Not a sub-rule"); + return Constraint->getValueAsBit("Negated"); + } + + std::string getSpelling() const { + std::string Result = MetaSubject->getValueAsString("Name"); + if (isSubRule()) { + Result += '('; + if (isNegatedSubRule()) + Result += "unless("; + Result += getName(); + if (isNegatedSubRule()) + Result += ')'; + Result += ')'; + } + return Result; + } + + std::string getEnumValueName() const { + std::string Result = + "SubjectMatchRule_" + MetaSubject->getValueAsString("Name"); + if (isSubRule()) { + Result += "_"; + if (isNegatedSubRule()) + Result += "not_"; + Result += Constraint->getValueAsString("Name"); + } + if (isAbstractRule()) + Result += "_abstract"; + return Result; + } + + std::string getEnumValue() const { return "attr::" + getEnumValueName(); } + + static const char *EnumName; +}; + +const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule"; + +struct PragmaClangAttributeSupport { + std::vector<AttributeSubjectMatchRule> Rules; + + 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); + + bool isAttributedSupported(const Record &Attribute); + + void emitMatchRuleList(raw_ostream &OS); + + std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS); + + void generateParsingHelpers(raw_ostream &OS); +}; + +} // 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 = + Records.getAllDerivedDefinitions("AttrSubjectMatcherRule"); + auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, + const Record *MetaSubject, + const Record *Constraint = nullptr) { + Rules.emplace_back(MetaSubject, Constraint); + std::vector<Record *> ApplicableSubjects = + SubjectContainer->getValueAsListOfDefs("Subjects"); + for (const auto *Subject : ApplicableSubjects) { + bool Inserted = + SubjectsToRules + .try_emplace(Subject, RuleOrAggregateRuleSet::getRule( + AttributeSubjectMatchRule(MetaSubject, + Constraint))) + .second; + if (!Inserted) { + PrintFatalError("Attribute subject match rules should not represent" + "same attribute subjects."); + } + } + }; + for (const auto *MetaSubject : MetaSubjects) { + MapFromSubjectsToRules(MetaSubject, MetaSubject); + std::vector<Record *> Constraints = + MetaSubject->getValueAsListOfDefs("Constraints"); + 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 & +getPragmaAttributeSupport(RecordKeeper &Records) { + static PragmaClangAttributeSupport Instance(Records); + return Instance; +} + +void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) { + OS << "#ifndef ATTR_MATCH_SUB_RULE\n"; + OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, " + "IsNegated) " + << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n"; + OS << "#endif\n"; + for (const auto &Rule : Rules) { + OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '('; + OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", " + << Rule.isAbstractRule(); + if (Rule.isSubRule()) + OS << ", " + << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue() + << ", " << Rule.isNegatedSubRule(); + OS << ")\n"; + } + OS << "#undef ATTR_MATCH_SUB_RULE\n"; +} + +bool PragmaClangAttributeSupport::isAttributedSupported( + const Record &Attribute) { + if (Attribute.getValueAsBit("ForcePragmaAttributeSupport")) + return true; + // Opt-out rules: + // FIXME: The documentation check should be moved before + // the ForcePragmaAttributeSupport check after annotate is documented. + // No documentation present. + if (Attribute.isValueUnset("Documentation")) + return false; + std::vector<Record *> Docs = Attribute.getValueAsListOfDefs("Documentation"); + if (Docs.empty()) + return false; + if (Docs.size() == 1 && Docs[0]->getName() == "Undocumented") + return false; + // An attribute requires delayed parsing (LateParsed is on) + if (Attribute.getValueAsBit("LateParsed")) + return false; + // An attribute has no GNU/CXX11 spelling + if (!hasGNUorCXX11Spelling(Attribute)) + return false; + // An attribute subject list has a subject that isn't covered by one of the + // subject match rules or has no subjects at all. + if (Attribute.isValueUnset("Subjects")) + return false; + const Record *SubjectObj = Attribute.getValueAsDef("Subjects"); + std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); + if (Subjects.empty()) + return false; + for (const auto *Subject : Subjects) { + if (SubjectsToRules.find(Subject) == SubjectsToRules.end()) + return false; + } + return true; +} + +std::string +PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, + raw_ostream &OS) { + if (!isAttributedSupported(Attr)) + return "nullptr"; + // Generate a function that constructs a set of matching rules that describe + // to which declarations the attribute should apply to. + std::string FnName = "matchRulesFor" + Attr.getName().str(); + std::stringstream SS; + SS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<" + << AttributeSubjectMatchRule::EnumName + << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n"; + if (Attr.isValueUnset("Subjects")) { + SS << "}\n\n"; + OS << SS.str(); + return FnName; + } + const Record *SubjectObj = Attr.getValueAsDef("Subjects"); + std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); + for (const auto *Subject : Subjects) { + auto It = SubjectsToRules.find(Subject); + assert(It != SubjectsToRules.end() && + "This attribute is unsupported by #pragma clang attribute"); + 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(); + return FnName; +} + +void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { + // Generate routines that check the names of sub-rules. + OS << "Optional<attr::SubjectMatchRule> " + "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n"; + OS << " return None;\n"; + OS << "}\n\n"; + + std::map<const Record *, std::vector<AttributeSubjectMatchRule>> + SubMatchRules; + for (const auto &Rule : Rules) { + if (!Rule.isSubRule()) + continue; + SubMatchRules[Rule.MetaSubject].push_back(Rule); + } + + for (const auto &SubMatchRule : SubMatchRules) { + OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_" + << SubMatchRule.first->getValueAsString("Name") + << "(StringRef Name, bool IsUnless) {\n"; + OS << " if (IsUnless)\n"; + OS << " return " + "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; + for (const auto &Rule : SubMatchRule.second) { + if (Rule.isNegatedSubRule()) + OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() + << ").\n"; + } + OS << " Default(None);\n"; + OS << " return " + "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; + for (const auto &Rule : SubMatchRule.second) { + if (!Rule.isNegatedSubRule()) + OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() + << ").\n"; + } + OS << " Default(None);\n"; + OS << "}\n\n"; + } + + // Generate the function that checks for the top-level rules. + OS << "std::pair<Optional<attr::SubjectMatchRule>, " + "Optional<attr::SubjectMatchRule> (*)(StringRef, " + "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n"; + OS << " return " + "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, " + "Optional<attr::SubjectMatchRule> (*) (StringRef, " + "bool)>>(Name).\n"; + for (const auto &Rule : Rules) { + if (Rule.isSubRule()) + continue; + std::string SubRuleFunction; + if (SubMatchRules.count(Rule.MetaSubject)) + SubRuleFunction = "isAttributeSubjectMatchSubRuleFor_" + Rule.getName(); + else + SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor"; + OS << " Case(\"" << Rule.getName() << "\", std::make_pair(" + << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n"; + } + OS << " Default(std::make_pair(None, " + "defaultIsAttributeSubjectMatchSubRuleFor));\n"; + OS << "}\n\n"; + + // Generate the function that checks for the submatch rules. + OS << "const char *validAttributeSubjectMatchSubRules(" + << AttributeSubjectMatchRule::EnumName << " Rule) {\n"; + OS << " switch (Rule) {\n"; + for (const auto &SubMatchRule : SubMatchRules) { + OS << " case " + << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue() + << ":\n"; + OS << " return \"'"; + bool IsFirst = true; + for (const auto &Rule : SubMatchRule.second) { + if (!IsFirst) + OS << ", '"; + IsFirst = false; + if (Rule.isNegatedSubRule()) + OS << "unless("; + OS << Rule.getName(); + if (Rule.isNegatedSubRule()) + OS << ')'; + OS << "'"; + } + OS << "\";\n"; + } + OS << " default: return nullptr;\n"; + OS << " }\n"; + OS << "}\n\n"; +} + template <typename Fn> static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); @@ -2109,6 +2513,17 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { OS << "#undef PRAGMA_SPELLING_ATTR\n"; } +// Emits the enumeration list for attributes. +void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader( + "List of all attribute subject matching rules that Clang recognizes", OS); + PragmaClangAttributeSupport &PragmaAttributeSupport = + getPragmaAttributeSupport(Records); + emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr); + PragmaAttributeSupport.emitMatchRuleList(OS); + OS << "#undef ATTR_MATCH_RULE\n"; +} + // Emits the code to read an attribute from a precompiled header. void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Attribute deserialization code", OS); @@ -2596,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; @@ -2631,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 @@ -2689,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(), @@ -2704,9 +3124,13 @@ static std::string GetSubjectWithSuffix(const Record *R) { return B + "Decl"; } +static std::string functionNameForCustomAppertainsTo(const Record &Subject) { + return "is" + Subject.getName().str(); +} + static std::string GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) { - std::string FnName = "is" + Subject.getName().str(); + std::string FnName = functionNameForCustomAppertainsTo(Subject); // If this code has already been generated, simply return the previous // instance of it. @@ -2791,6 +3215,42 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { return FnName; } +static void +emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport, + raw_ostream &OS) { + OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, " + << AttributeSubjectMatchRule::EnumName << " rule) {\n"; + OS << " switch (rule) {\n"; + for (const auto &Rule : PragmaAttributeSupport.Rules) { + if (Rule.isAbstractRule()) { + OS << " case " << Rule.getEnumValue() << ":\n"; + OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n"; + OS << " return false;\n"; + continue; + } + std::vector<Record *> Subjects = Rule.getSubjects(); + assert(!Subjects.empty() && "Missing subjects"); + OS << " case " << Rule.getEnumValue() << ":\n"; + OS << " return "; + for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { + // If the subject has custom code associated with it, use the function + // that was generated for GenerateAppertainsTo to check if the declaration + // is valid. + if ((*I)->isSubClassOf("SubsetSubject")) + OS << functionNameForCustomAppertainsTo(**I) << "(D)"; + else + OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)"; + + if (I + 1 != E) + OS << " || "; + } + OS << ";\n"; + } + OS << " }\n"; + OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n"; + OS << "}\n\n"; +} + static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { OS << "static bool defaultDiagnoseLangOpts(Sema &, "; OS << "const AttributeList &) {\n"; @@ -2949,6 +3409,9 @@ static bool IsKnownToGCC(const Record &Attr) { void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Parsed attribute helpers", OS); + PragmaClangAttributeSupport &PragmaAttributeSupport = + getPragmaAttributeSupport(Records); + // Get the list of parsed attributes, and accept the optional list of // duplicates due to the ParseKind. ParsedAttrMap Dupes; @@ -2982,10 +3445,13 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { SS << ", " << I->second->isSubClassOf("TypeAttr"); SS << ", " << I->second->isSubClassOf("StmtAttr"); SS << ", " << IsKnownToGCC(*I->second); + SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second); SS << ", " << GenerateAppertainsTo(*I->second, OS); SS << ", " << GenerateLangOptRequirements(*I->second, OS); SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS); SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS); + SS << ", " + << PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS); SS << " }"; if (I + 1 != E) @@ -2997,6 +3463,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n"; OS << SS.str(); OS << "};\n\n"; + + // Generate the attribute match rules. + emitAttributeMatchRules(PragmaAttributeSupport, OS); } // Emits the kind list of parsed attributes @@ -3136,6 +3605,11 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records, emitClangAttrLateParsedList(Records, OS); } +void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, + raw_ostream &OS) { + getPragmaAttributeSupport(Records).generateParsingHelpers(OS); +} + class DocumentationData { public: const Record *Documentation; @@ -3167,8 +3641,8 @@ enum SpellingKind { Pragma = 1 << 5 }; -static void WriteDocumentation(const DocumentationData &Doc, - raw_ostream &OS) { +static void WriteDocumentation(RecordKeeper &Records, + const DocumentationData &Doc, raw_ostream &OS) { // FIXME: there is no way to have a per-spelling category for the attribute // documentation. This may not be a limiting factor since the spellings // should generally be consistently applied across the category. @@ -3250,7 +3724,7 @@ static void WriteDocumentation(const DocumentationData &Doc, // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\","; - OS << " \"Pragma\"\n\n"; + OS << " \"Pragma\", \"Pragma clang attribute\"\n\n"; OS << " \""; if (SupportedSpellings & GNU) OS << "X"; OS << "\",\""; @@ -3261,6 +3735,9 @@ static void WriteDocumentation(const DocumentationData &Doc, if (SupportedSpellings & Keyword) OS << "X"; OS << "\", \""; if (SupportedSpellings & Pragma) OS << "X"; + OS << "\", \""; + if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute)) + OS << "X"; OS << "\"\n\n"; // If the attribute is deprecated, print a message about it, and possibly @@ -3327,7 +3804,50 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { // Walk over each of the attributes in the category and write out their // documentation. for (const auto &Doc : I.second) - WriteDocumentation(Doc, OS); + WriteDocumentation(Records, Doc, OS); + } +} + +void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records, + raw_ostream &OS) { + PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records); + ParsedAttrMap Attrs = getParsedAttrList(Records); + unsigned NumAttrs = 0; + for (const auto &I : Attrs) { + if (Support.isAttributedSupported(*I.second)) + ++NumAttrs; + } + OS << "#pragma clang attribute supports " << NumAttrs << " attributes:\n"; + for (const auto &I : Attrs) { + if (!Support.isAttributedSupported(*I.second)) + continue; + OS << I.first; + if (I.second->isValueUnset("Subjects")) { + OS << " ()\n"; + continue; + } + const Record *SubjectObj = I.second->getValueAsDef("Subjects"); + std::vector<Record *> Subjects = + SubjectObj->getValueAsListOfDefs("Subjects"); + OS << " ("; + for (const auto &Subject : llvm::enumerate(Subjects)) { + if (Subject.index()) + OS << ", "; + 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"; } } diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index fd7999be3877..781518ddbc31 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -25,8 +25,10 @@ using namespace clang; enum ActionType { GenClangAttrClasses, GenClangAttrParserStringSwitches, + GenClangAttrSubjectMatchRulesParserStringSwitches, GenClangAttrImpl, GenClangAttrList, + GenClangAttrSubjectMatchRuleList, GenClangAttrPCHRead, GenClangAttrPCHWrite, GenClangAttrHasAttributeImpl, @@ -54,7 +56,8 @@ enum ActionType { GenArmNeonTest, GenAttrDocs, GenDiagDocs, - GenOptDocs + GenOptDocs, + GenTestPragmaAttributeSupportedAttributes }; namespace { @@ -66,10 +69,17 @@ cl::opt<ActionType> Action( clEnumValN(GenClangAttrParserStringSwitches, "gen-clang-attr-parser-string-switches", "Generate all parser-related attribute string switches"), + clEnumValN(GenClangAttrSubjectMatchRulesParserStringSwitches, + "gen-clang-attr-subject-match-rules-parser-string-switches", + "Generate all parser-related attribute subject match rule" + "string switches"), clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl", "Generate clang attribute implementations"), clEnumValN(GenClangAttrList, "gen-clang-attr-list", "Generate a clang attribute list"), + clEnumValN(GenClangAttrSubjectMatchRuleList, + "gen-clang-attr-subject-match-rule-list", + "Generate a clang attribute subject match rule list"), clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read", "Generate clang PCH attribute reader"), clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", @@ -80,8 +90,7 @@ cl::opt<ActionType> Action( clEnumValN(GenClangAttrSpellingListIndex, "gen-clang-attr-spelling-index", "Generate a clang attribute spelling index"), - clEnumValN(GenClangAttrASTVisitor, - "gen-clang-attr-ast-visitor", + clEnumValN(GenClangAttrASTVisitor, "gen-clang-attr-ast-visitor", "Generate a recursive AST visitor for clang attributes"), clEnumValN(GenClangAttrTemplateInstantiate, "gen-clang-attr-template-instantiate", @@ -137,8 +146,11 @@ cl::opt<ActionType> Action( "Generate attribute documentation"), clEnumValN(GenDiagDocs, "gen-diag-docs", "Generate diagnostic documentation"), - clEnumValN(GenOptDocs, "gen-opt-docs", - "Generate option documentation"))); + clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"), + clEnumValN(GenTestPragmaAttributeSupportedAttributes, + "gen-clang-test-pragma-attribute-supported-attributes", + "Generate a list of attributes supported by #pragma clang " + "attribute for testing purposes"))); cl::opt<std::string> ClangComponent("clang-component", @@ -153,12 +165,18 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangAttrParserStringSwitches: EmitClangAttrParserStringSwitches(Records, OS); break; + case GenClangAttrSubjectMatchRulesParserStringSwitches: + EmitClangAttrSubjectMatchRulesParserStringSwitches(Records, OS); + break; case GenClangAttrImpl: EmitClangAttrImpl(Records, OS); break; case GenClangAttrList: EmitClangAttrList(Records, OS); break; + case GenClangAttrSubjectMatchRuleList: + EmitClangAttrSubjectMatchRuleList(Records, OS); + break; case GenClangAttrPCHRead: EmitClangAttrPCHRead(Records, OS); break; @@ -244,6 +262,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenOptDocs: EmitClangOptDocs(Records, OS); break; + case GenTestPragmaAttributeSupportedAttributes: + EmitTestPragmaAttributeSupportedAttributes(Records, OS); + break; } return false; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 033cb78f36f3..e1b7d0ec63be 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -33,9 +33,12 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, const std::string &N, const std::string &S); void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, + raw_ostream &OS); void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS); @@ -72,6 +75,9 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS); void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS); void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS); +void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records, + raw_ostream &OS); + } // end namespace clang #endif |