PR14922: when printing an attribute, use the real syntax of the attribute (GNU, C++11, MS Declspec) instead of hardcoded GNU syntax.
Introduce a spelling index to Attr class, which is an index into the attribute spelling list of an attribute defined in Attr.td.
This index will determine the actual spelling used by an attribute, as it incorporates both the syntax and naming of the attribute.
When constructing an attribute AST node, the spelling index is computed based on attribute kind, scope (if it's a C++11 attribute), and
name, then passed to Attr that will use the index to print itself.
Thanks to Richard Smith for the idea and review.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173358 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index ef618ce..b873636 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -735,6 +735,82 @@
<< " OS << \"";
}
+static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
+ raw_ostream &OS) {
+ std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
+
+ OS << "void " << R.getName() << "Attr::printPretty("
+ << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
+
+ if (Spellings.size() == 0) {
+ OS << "}\n\n";
+ return;
+ }
+
+ OS <<
+ " switch (SpellingListIndex) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute spelling!\");\n"
+ " break;\n";
+
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ llvm::SmallString<16> Prefix;
+ llvm::SmallString<8> Suffix;
+ // The actual spelling of the name and namespace (if applicable)
+ // of an attribute without considering prefix and suffix.
+ llvm::SmallString<64> Spelling;
+ std::string Name = Spellings[I]->getValueAsString("Name");
+ std::string Variety = Spellings[I]->getValueAsString("Variety");
+
+ if (Variety == "GNU") {
+ Prefix = " __attribute__((";
+ Suffix = "))";
+ } else if (Variety == "CXX11") {
+ Prefix = " [[";
+ Suffix = "]]";
+ std::string Namespace = Spellings[I]->getValueAsString("Namespace");
+ if (Namespace != "") {
+ Spelling += Namespace;
+ Spelling += "::";
+ }
+ } else if (Variety == "Declspec") {
+ Prefix = " __declspec(";
+ Suffix = ")";
+ } else {
+ llvm_unreachable("Unkown attribute syntax variety!");
+ }
+
+ Spelling += Name;
+
+ OS <<
+ " case " << I << " : {\n"
+ " OS << \"" + Prefix.str() + Spelling.str();
+
+ if (Args.size()) OS << "(";
+ if (Spelling == "availability") {
+ writeAvailabilityValue(OS);
+ } else {
+ for (std::vector<Argument*>::const_iterator I = Args.begin(),
+ E = Args.end(); I != E; ++ I) {
+ if (I != Args.begin()) OS << ", ";
+ (*I)->writeValue(OS);
+ }
+ }
+
+ if (Args.size()) OS << ")";
+ OS << Suffix.str() + "\";\n";
+
+ OS <<
+ " break;\n"
+ " }\n";
+ }
+
+ // End of the switch statement.
+ OS << "}\n";
+ // End of the print function.
+ OS << "}\n\n";
+}
+
namespace clang {
// Emits the class definitions for attributes.
@@ -783,9 +859,12 @@
(*ai)->writeCtorParameters(OS);
OS << "\n";
}
-
+
+ OS << " , ";
+ OS << "unsigned SI = 0\n";
+
OS << " )\n";
- OS << " : " << SuperName << "(attr::" << R.getName() << ", R)\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
for (ai = Args.begin(); ai != ae; ++ai) {
OS << " , ";
@@ -841,7 +920,6 @@
continue;
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
- std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<Argument*> Args;
for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
Args.push_back(createArgument(**ri, R.getName()));
@@ -858,24 +936,7 @@
}
OS << ");\n}\n\n";
- OS << "void " << R.getName() << "Attr::printPretty("
- << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
- if (Spellings.begin() != Spellings.end()) {
- std::string Spelling = (*Spellings.begin())->getValueAsString("Name");
- OS << " OS << \" __attribute__((" << Spelling;
- if (Args.size()) OS << "(";
- if (Spelling == "availability") {
- writeAvailabilityValue(OS);
- } else {
- for (ai = Args.begin(); ai != ae; ++ai) {
- if (ai!=Args.begin()) OS <<", ";
- (*ai)->writeValue(OS);
- }
- }
- if (Args.size()) OS << ")";
- OS << "))\";\n";
- }
- OS << "}\n\n";
+ writePrettyPrintFunction(R, Args, OS);
}
}
@@ -1044,6 +1105,64 @@
}
+void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit it. \n\n";
+
+ OS <<
+ " unsigned Index = 0;\n"
+ " switch (AttrKind) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute kind!\");\n"
+ " break;\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (std::vector<Record*>::const_iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ // We only care about attributes that participate in Sema checking, so
+ // skip those attributes that are not able to make their way to Sema.
+ if (!R.getValueAsBit("SemaHandler"))
+ continue;
+
+ std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
+ // Each distinct spelling yields an attribute kind.
+ if (R.getValueAsBit("DistinctSpellings")) {
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ OS <<
+ " case AT_" << Spellings[I]->getValueAsString("Name") << ": \n"
+ " Index = " << I << ";\n"
+ " break;\n";
+ }
+ } else {
+ OS << " case AT_" << R.getName() << " : {\n";
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ SmallString<16> Namespace;
+ if (Spellings[I]->getValueAsString("Variety") == "CXX11")
+ Namespace = Spellings[I]->getValueAsString("Namespace");
+ else
+ Namespace = "";
+
+ OS << " if (Name == \""
+ << Spellings[I]->getValueAsString("Name") << "\" && "
+ << "SyntaxUsed == "
+ << StringSwitch<unsigned>(Spellings[I]->getValueAsString("Variety"))
+ .Case("GNU", 0)
+ .Case("CXX11", 1)
+ .Case("Declspec", 2)
+ .Default(0)
+ << " && Scope == \"" << Namespace << "\")\n"
+ << " return " << I << ";\n";
+ }
+
+ OS << " break;\n";
+ OS << " }\n";
+ }
+ }
+
+ OS << " }\n";
+ OS << " return Index;\n";
+}
+
// Emits the LateParsed property for attributes.
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
OS << "// This file is generated by TableGen. Do not edit.\n\n";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 7e9076f..8af6598 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -29,6 +29,7 @@
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrSpellingList,
+ GenClangAttrSpellingListIndex,
GenClangAttrLateParsedList,
GenClangAttrTemplateInstantiate,
GenClangAttrParsedAttrList,
@@ -70,6 +71,9 @@
clEnumValN(GenClangAttrSpellingList,
"gen-clang-attr-spelling-list",
"Generate a clang attribute spelling list"),
+ clEnumValN(GenClangAttrSpellingListIndex,
+ "gen-clang-attr-spelling-index",
+ "Generate a clang attribute spelling index"),
clEnumValN(GenClangAttrLateParsedList,
"gen-clang-attr-late-parsed-list",
"Generate a clang attribute LateParsed list"),
@@ -144,6 +148,9 @@
case GenClangAttrSpellingList:
EmitClangAttrSpellingList(Records, OS);
break;
+ case GenClangAttrSpellingListIndex:
+ EmitClangAttrSpellingListIndex(Records, OS);
+ break;
case GenClangAttrLateParsedList:
EmitClangAttrLateParsedList(Records, OS);
break;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 54e76fd..637e54c 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -35,6 +35,7 @@
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS);