summaryrefslogtreecommitdiff
path: root/utils/TableGen/ClangAttrEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/TableGen/ClangAttrEmitter.cpp')
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp275
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