diff options
Diffstat (limited to 'utils/TableGen/ClangAttrEmitter.cpp')
| -rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 275 |
1 files changed, 153 insertions, 122 deletions
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 6b3df825808f..874ad2df0031 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -603,14 +603,15 @@ namespace { OS << " OS << \""; } - void writeDump(raw_ostream &OS) const override {} + void writeDump(raw_ostream &OS) const override { + OS << " if (!SA->is" << getUpperName() << "Expr())\n"; + OS << " dumpType(SA->get" << getUpperName() + << "Type()->getType());\n"; + } void writeDumpChildren(raw_ostream &OS) const override { OS << " if (SA->is" << getUpperName() << "Expr())\n"; OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n"; - OS << " else\n"; - OS << " dumpType(SA->get" << getUpperName() - << "Type()->getType());\n"; } void writeHasChildren(raw_ostream &OS) const override { @@ -1885,19 +1886,15 @@ void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) { bool PragmaClangAttributeSupport::isAttributedSupported( const Record &Attribute) { - if (Attribute.getValueAsBit("ForcePragmaAttributeSupport")) - return true; + // If the attribute explicitly specified whether to support #pragma clang + // attribute, use that setting. + bool Unset; + bool SpecifiedResult = + Attribute.getValueAsBitOrUnset("PragmaAttributeSupport", Unset); + if (!Unset) + return SpecifiedResult; + // 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; @@ -2470,8 +2467,10 @@ namespace { static const AttrClassDescriptor AttrClassDescriptors[] = { { "ATTR", "Attr" }, + { "TYPE_ATTR", "TypeAttr" }, { "STMT_ATTR", "StmtAttr" }, { "INHERITABLE_ATTR", "InheritableAttr" }, + { "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" }, { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }, { "PARAMETER_ABI_ATTR", "ParameterABIAttr" } }; @@ -2937,9 +2936,9 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { if (I != List.cbegin()) OS << " else "; if (I->first.empty()) - OS << "if (!Scope || Scope->getName() == \"\") {\n"; + OS << "if (ScopeName == \"\") {\n"; else - OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; + OS << "if (ScopeName == \"" << I->first << "\") {\n"; OS << " return llvm::StringSwitch<int>(Name)\n"; GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); OS << "}"; @@ -3335,7 +3334,7 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { SS << (Warn ? "warn_attribute_wrong_decl_type_str" : "err_attribute_wrong_decl_type_str"); SS << ")\n"; - SS << " << Attr.getName() << "; + SS << " << Attr << "; SS << CalculateDiagnostic(*SubjectObj) << ";\n"; SS << " return false;\n"; SS << " }\n"; @@ -3699,39 +3698,67 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { } // Emits the code to dump an attribute. -void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) { - emitSourceFileHeader("Attribute dumper", OS); +void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute text node dumper", OS); - OS << " switch (A->getKind()) {\n"; std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; for (const auto *Attr : Attrs) { const Record &R = *Attr; if (!R.getValueAsBit("ASTNode")) continue; - OS << " case attr::" << R.getName() << ": {\n"; // If the attribute has a semantically-meaningful name (which is determined // by whether there is a Spelling enumeration for it), then write out the // spelling used for the attribute. + + std::string FunctionContent; + llvm::raw_string_ostream SS(FunctionContent); + std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings)) - OS << " OS << \" \" << A->getSpelling();\n"; + SS << " OS << \" \" << A->getSpelling();\n"; Args = R.getValueAsListOfDefs("Args"); - if (!Args.empty()) { - OS << " const auto *SA = cast<" << R.getName() - << "Attr>(A);\n"; - for (const auto *Arg : Args) - createArgument(*Arg, R.getName())->writeDump(OS); + for (const auto *Arg : Args) + createArgument(*Arg, R.getName())->writeDump(SS); - for (const auto *AI : Args) - createArgument(*AI, R.getName())->writeDumpChildren(OS); + if (SS.tell()) { + OS << " void Visit" << R.getName() << "Attr(const " << R.getName() + << "Attr *A) {\n"; + if (!Args.empty()) + OS << " const auto *SA = cast<" << R.getName() + << "Attr>(A); (void)SA;\n"; + OS << SS.str(); + OS << " }\n"; + } + } +} + +void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Attribute text node traverser", OS); + + std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; + for (const auto *Attr : Attrs) { + const Record &R = *Attr; + if (!R.getValueAsBit("ASTNode")) + continue; + + std::string FunctionContent; + llvm::raw_string_ostream SS(FunctionContent); + + Args = R.getValueAsListOfDefs("Args"); + for (const auto *Arg : Args) + createArgument(*Arg, R.getName())->writeDumpChildren(SS); + if (SS.tell()) { + OS << " void Visit" << R.getName() << "Attr(const " << R.getName() + << "Attr *A) {\n"; + if (!Args.empty()) + OS << " const auto *SA = cast<" << R.getName() + << "Attr>(A); (void)SA;\n"; + OS << SS.str(); + OS << " }\n"; } - OS << - " break;\n" - " }\n"; } - OS << " }\n"; } void EmitClangAttrParserStringSwitches(RecordKeeper &Records, @@ -3749,18 +3776,66 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, getPragmaAttributeSupport(Records).generateParsingHelpers(OS); } +enum class SpellingKind { + GNU, + CXX11, + C2x, + Declspec, + Microsoft, + Keyword, + Pragma, +}; +static const size_t NumSpellingKinds = (size_t)SpellingKind::Pragma + 1; + +class SpellingList { + std::vector<std::string> Spellings[NumSpellingKinds]; + +public: + ArrayRef<std::string> operator[](SpellingKind K) const { + return Spellings[(size_t)K]; + } + + void add(const Record &Attr, FlattenedSpelling Spelling) { + SpellingKind Kind = StringSwitch<SpellingKind>(Spelling.variety()) + .Case("GNU", SpellingKind::GNU) + .Case("CXX11", SpellingKind::CXX11) + .Case("C2x", SpellingKind::C2x) + .Case("Declspec", SpellingKind::Declspec) + .Case("Microsoft", SpellingKind::Microsoft) + .Case("Keyword", SpellingKind::Keyword) + .Case("Pragma", SpellingKind::Pragma); + std::string Name; + if (!Spelling.nameSpace().empty()) { + switch (Kind) { + case SpellingKind::CXX11: + case SpellingKind::C2x: + Name = Spelling.nameSpace() + "::"; + break; + case SpellingKind::Pragma: + Name = Spelling.nameSpace() + " "; + break; + default: + PrintFatalError(Attr.getLoc(), "Unexpected namespace in spelling"); + } + } + Name += Spelling.name(); + + Spellings[(size_t)Kind].push_back(Name); + } +}; + class DocumentationData { public: const Record *Documentation; const Record *Attribute; std::string Heading; - unsigned SupportedSpellings; + SpellingList SupportedSpellings; DocumentationData(const Record &Documentation, const Record &Attribute, - const std::pair<std::string, unsigned> HeadingAndKinds) + std::pair<std::string, SpellingList> HeadingAndSpellings) : Documentation(&Documentation), Attribute(&Attribute), - Heading(std::move(HeadingAndKinds.first)), - SupportedSpellings(HeadingAndKinds.second) {} + Heading(std::move(HeadingAndSpellings.first)), + SupportedSpellings(std::move(HeadingAndSpellings.second)) {} }; static void WriteCategoryHeader(const Record *DocCategory, @@ -3776,28 +3851,21 @@ static void WriteCategoryHeader(const Record *DocCategory, OS << "\n\n"; } -enum SpellingKind { - GNU = 1 << 0, - CXX11 = 1 << 1, - C2x = 1 << 2, - Declspec = 1 << 3, - Microsoft = 1 << 4, - Keyword = 1 << 5, - Pragma = 1 << 6 -}; - -static std::pair<std::string, unsigned> -GetAttributeHeadingAndSpellingKinds(const Record &Documentation, - const Record &Attribute) { +static std::pair<std::string, SpellingList> +GetAttributeHeadingAndSpellings(const Record &Documentation, + const Record &Attribute) { // 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. std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); + if (Spellings.empty()) + PrintFatalError(Attribute.getLoc(), + "Attribute has no supported spellings; cannot be " + "documented"); // Determine the heading to be used for this attribute. std::string Heading = Documentation.getValueAsString("Heading"); - bool CustomHeading = !Heading.empty(); if (Heading.empty()) { // If there's only one spelling, we can simply use that. if (Spellings.size() == 1) @@ -3821,51 +3889,11 @@ GetAttributeHeadingAndSpellingKinds(const Record &Documentation, PrintFatalError(Attribute.getLoc(), "This attribute requires a heading to be specified"); - // Gather a list of unique spellings; this is not the same as the semantic - // spelling for the attribute. Variations in underscores and other non- - // semantic characters are still acceptable. - std::vector<std::string> Names; + SpellingList SupportedSpellings; + for (const auto &I : Spellings) + SupportedSpellings.add(Attribute, I); - unsigned SupportedSpellings = 0; - for (const auto &I : Spellings) { - SpellingKind Kind = StringSwitch<SpellingKind>(I.variety()) - .Case("GNU", GNU) - .Case("CXX11", CXX11) - .Case("C2x", C2x) - .Case("Declspec", Declspec) - .Case("Microsoft", Microsoft) - .Case("Keyword", Keyword) - .Case("Pragma", Pragma); - - // Mask in the supported spelling. - SupportedSpellings |= Kind; - - std::string Name; - if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty()) - Name = I.nameSpace() + "::"; - Name += I.name(); - - // If this name is the same as the heading, do not add it. - if (Name != Heading) - Names.push_back(Name); - } - - // Print out the heading for the attribute. If there are alternate spellings, - // then display those after the heading. - if (!CustomHeading && !Names.empty()) { - Heading += " ("; - for (auto I = Names.begin(), E = Names.end(); I != E; ++I) { - if (I != Names.begin()) - Heading += ", "; - Heading += *I; - } - Heading += ")"; - } - if (!SupportedSpellings) - PrintFatalError(Attribute.getLoc(), - "Attribute has no supported spellings; cannot be " - "documented"); - return std::make_pair(std::move(Heading), SupportedSpellings); + return std::make_pair(std::move(Heading), std::move(SupportedSpellings)); } static void WriteDocumentation(RecordKeeper &Records, @@ -3874,23 +3902,30 @@ static void WriteDocumentation(RecordKeeper &Records, // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; - OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\","; - OS << " \"Pragma\", \"Pragma clang attribute\"\n\n"; + OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"``__declspec``\","; + OS << " \"Keyword\", \"``#pragma``\", \"``#pragma clang attribute``\"\n\n"; OS << " \""; - if (Doc.SupportedSpellings & GNU) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & CXX11) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & C2x) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & Declspec) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & Keyword) OS << "X"; - OS << "\", \""; - if (Doc.SupportedSpellings & Pragma) OS << "X"; - OS << "\", \""; - if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute)) - OS << "X"; + for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) { + SpellingKind K = (SpellingKind)Kind; + // TODO: List Microsoft (IDL-style attribute) spellings once we fully + // support them. + if (K == SpellingKind::Microsoft) + continue; + + bool PrintedAny = false; + for (StringRef Spelling : Doc.SupportedSpellings[K]) { + if (PrintedAny) + OS << " |br| "; + OS << "``" << Spelling << "``"; + PrintedAny = true; + } + + OS << "\",\""; + } + + if (getPragmaAttributeSupport(Records).isAttributedSupported( + *Doc.Attribute)) + OS << "Yes"; OS << "\"\n\n"; // If the attribute is deprecated, print a message about it, and possibly @@ -3946,7 +3981,7 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { if (!Undocumented) SplitDocs[Category].push_back(DocumentationData( - Doc, Attr, GetAttributeHeadingAndSpellingKinds(Doc, Attr))); + Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr))); } } @@ -3955,10 +3990,10 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { for (auto &I : SplitDocs) { WriteCategoryHeader(I.first, OS); - llvm::sort(I.second.begin(), I.second.end(), + llvm::sort(I.second, [](const DocumentationData &D1, const DocumentationData &D2) { return D1.Heading < D2.Heading; - }); + }); // Walk over each of the attributes in the category and write out their // documentation. @@ -3971,12 +4006,7 @@ 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"; + OS << "#pragma clang attribute supports the following attributes:\n"; for (const auto &I : Attrs) { if (!Support.isAttributedSupported(*I.second)) continue; @@ -4008,6 +4038,7 @@ void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records, } OS << ")\n"; } + OS << "End of supported attributes.\n"; } } // end namespace clang |
