summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp')
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp136
1 files changed, 84 insertions, 52 deletions
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
index 5dd3f7e..11a766c 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -28,6 +28,7 @@
using namespace llvm;
+namespace {
class FlattenedSpelling {
std::string V, N, NS;
bool K;
@@ -53,18 +54,19 @@ public:
const std::string &nameSpace() const { return NS; }
bool knownToGCC() const { return K; }
};
+} // namespace
-std::vector<FlattenedSpelling> GetFlattenedSpellings(const Record &Attr) {
+static std::vector<FlattenedSpelling>
+GetFlattenedSpellings(const Record &Attr) {
std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Ret;
for (const auto &Spelling : Spellings) {
if (Spelling->getValueAsString("Variety") == "GCC") {
// Gin up two new spelling objects to add into the list.
- Ret.push_back(FlattenedSpelling("GNU", Spelling->getValueAsString("Name"),
- "", true));
- Ret.push_back(FlattenedSpelling(
- "CXX11", Spelling->getValueAsString("Name"), "gnu", true));
+ Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true);
+ Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu",
+ true);
} else
Ret.push_back(FlattenedSpelling(*Spelling));
}
@@ -79,6 +81,7 @@ static std::string ReadPCHRecord(StringRef type) {
.Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
.Case("Expr *", "ReadExpr(F)")
.Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
+ .Case("std::string", "ReadString(Record, Idx)")
.Default("Record[Idx++]");
}
@@ -92,6 +95,7 @@ static std::string WritePCHRecord(StringRef type, StringRef name) {
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
.Case("IdentifierInfo *",
"AddIdentifierRef(" + std::string(name) + ", Record);\n")
+ .Case("std::string", "AddString(" + std::string(name) + ", Record);\n")
.Default("Record.push_back(" + std::string(name) + ");\n");
}
@@ -112,11 +116,7 @@ static StringRef NormalizeAttrName(StringRef AttrName) {
// This is different from NormalizeAttrName in that it also handles names like
// _pascal and __pascal.
static StringRef NormalizeNameForSpellingComparison(StringRef Name) {
- while (Name.startswith("_"))
- Name = Name.substr(1, Name.size());
- while (Name.endswith("_"))
- Name = Name.substr(0, Name.size() - 1);
- return Name;
+ return Name.trim("_");
}
// Normalize attribute spelling only if the spelling has both leading
@@ -414,15 +414,14 @@ namespace {
// FIXME: Do not do the calculation here
// FIXME: Handle types correctly
// A null pointer means maximum alignment
- // FIXME: Load the platform-specific maximum alignment, rather than
- // 16, the x86 max.
OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName()
<< "(ASTContext &Ctx) const {\n";
OS << " assert(!is" << getUpperName() << "Dependent());\n";
OS << " if (is" << getLowerName() << "Expr)\n";
- OS << " return (" << getLowerName() << "Expr ? " << getLowerName()
- << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue() : 16)"
- << "* Ctx.getCharWidth();\n";
+ OS << " return " << getLowerName() << "Expr ? " << getLowerName()
+ << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue()"
+ << " * Ctx.getCharWidth() : "
+ << "Ctx.getTargetDefaultAlignForAttributeAligned();\n";
OS << " else\n";
OS << " return 0; // FIXME\n";
OS << "}\n";
@@ -985,6 +984,16 @@ namespace {
}
};
+ class VariadicStringArgument : public VariadicArgument {
+ public:
+ VariadicStringArgument(const Record &Arg, StringRef Attr)
+ : VariadicArgument(Arg, Attr, "std::string")
+ {}
+ void writeValueImpl(raw_ostream &OS) const override {
+ OS << " OS << \"\\\"\" << Val << \"\\\"\";\n";
+ }
+ };
+
class TypeArgument : public SimpleArgument {
public:
TypeArgument(const Record &Arg, StringRef Attr)
@@ -1046,6 +1055,8 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
else if (ArgName == "VariadicUnsignedArgument")
Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
+ else if (ArgName == "VariadicStringArgument")
+ Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr);
else if (ArgName == "VariadicEnumArgument")
Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
else if (ArgName == "VariadicExprArgument")
@@ -1162,7 +1173,7 @@ writePrettyPrintFunction(Record &R,
OS <<
" case " << I << " : {\n"
- " OS << \"" + Prefix.str() + Spelling.str();
+ " OS << \"" << Prefix << Spelling;
if (Variety == "Pragma") {
OS << " \";\n";
@@ -1190,7 +1201,7 @@ writePrettyPrintFunction(Record &R,
if (!Args.empty())
OS << ")";
- OS << Suffix.str() + "\";\n";
+ OS << Suffix + "\";\n";
OS <<
" break;\n"
@@ -1207,7 +1218,7 @@ writePrettyPrintFunction(Record &R,
static unsigned
getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList,
const FlattenedSpelling &Spelling) {
- assert(SpellingList.size() && "Spelling list is empty!");
+ assert(!SpellingList.empty() && "Spelling list is empty!");
for (unsigned Index = 0; Index < SpellingList.size(); ++Index) {
const FlattenedSpelling &S = SpellingList[Index];
@@ -1231,7 +1242,7 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) {
std::vector<FlattenedSpelling> Spellings =
GetFlattenedSpellings(*Accessor);
std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(R);
- assert(SpellingList.size() &&
+ assert(!SpellingList.empty() &&
"Attribute with empty spelling list can't have accessors!");
OS << " bool " << Name << "() const { return SpellingListIndex == ";
@@ -1297,7 +1308,11 @@ CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings,
Uniques.insert(EnumName);
if (I != Spellings.begin())
Ret += ",\n";
- Ret += " " + EnumName;
+ // Duplicate spellings are not considered part of the semantic spelling
+ // enumeration, but the spelling index and semantic spelling values are
+ // meant to be equivalent, so we must specify a concrete value for each
+ // enumerator.
+ Ret += " " + EnumName + " = " + llvm::utostr(Idx);
}
Ret += "\n };\n\n";
return Ret;
@@ -1513,7 +1528,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "unsigned SI\n";
OS << " )\n";
- OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, "
+ << R.getValueAsBit("LateParsed") << ", "
+ << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n";
for (auto const &ai : Args) {
OS << " , ";
@@ -1545,7 +1562,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "unsigned SI\n";
OS << " )\n";
- OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, "
+ << R.getValueAsBit("LateParsed") << ", "
+ << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n";
for (auto const &ai : Args) {
OS << " , ";
@@ -1564,10 +1583,10 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << " }\n\n";
}
- OS << " " << R.getName() << "Attr *clone(ASTContext &C) const override;\n";
+ OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
OS << " void printPretty(raw_ostream &OS,\n"
- << " const PrintingPolicy &Policy) const override;\n";
- OS << " const char *getSpelling() const override;\n";
+ << " const PrintingPolicy &Policy) const;\n";
+ OS << " const char *getSpelling() const;\n";
if (!ElideSpelling) {
assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list");
@@ -1596,13 +1615,6 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << " static bool classof(const Attr *A) { return A->getKind() == "
<< "attr::" << R.getName() << "; }\n";
- bool LateParsed = R.getValueAsBit("LateParsed");
- OS << " bool isLateParsed() const override { return "
- << LateParsed << "; }\n";
-
- if (R.getValueAsBit("DuplicatesAllowedWhileMerging"))
- OS << " bool duplicatesAllowed() const override { return true; }\n\n";
-
OS << "};\n\n";
}
@@ -1645,6 +1657,36 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
writePrettyPrintFunction(R, Args, OS);
writeGetSpellingFunction(R, OS);
}
+
+ // Instead of relying on virtual dispatch we just create a huge dispatch
+ // switch. This is both smaller and faster than virtual functions.
+ auto EmitFunc = [&](const char *Method) {
+ OS << " switch (getKind()) {\n";
+ for (const auto *Attr : Attrs) {
+ const Record &R = *Attr;
+ if (!R.getValueAsBit("ASTNode"))
+ continue;
+
+ OS << " case attr::" << R.getName() << ":\n";
+ OS << " return cast<" << R.getName() << "Attr>(this)->" << Method
+ << ";\n";
+ }
+ OS << " case attr::NUM_ATTRS:\n";
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n";
+ OS << "}\n\n";
+ };
+
+ OS << "const char *Attr::getSpelling() const {\n";
+ EmitFunc("getSpelling()");
+
+ OS << "Attr *Attr::clone(ASTContext &C) const {\n";
+ EmitFunc("clone(C)");
+
+ OS << "void Attr::printPretty(raw_ostream &OS, "
+ "const PrintingPolicy &Policy) const {\n";
+ EmitFunc("printPretty(OS, Policy)");
}
} // end namespace clang
@@ -2185,7 +2227,8 @@ static std::string CalculateDiagnostic(const Record &S) {
Namespace = 1U << 11,
Field = 1U << 12,
CXXMethod = 1U << 13,
- ObjCProtocol = 1U << 14
+ ObjCProtocol = 1U << 14,
+ Enum = 1U << 15
};
uint32_t SubMask = 0;
@@ -2219,6 +2262,7 @@ static std::string CalculateDiagnostic(const Record &S) {
.Case("Namespace", Namespace)
.Case("Field", Field)
.Case("CXXMethod", CXXMethod)
+ .Case("Enum", Enum)
.Default(0);
if (!V) {
// Something wasn't in our mapping, so be helpful and let the developer
@@ -2237,6 +2281,7 @@ static std::string CalculateDiagnostic(const Record &S) {
case Var: return "ExpectedVariable";
case Param: return "ExpectedParameter";
case Class: return "ExpectedClass";
+ case Enum: return "ExpectedEnum";
case CXXMethod:
// FIXME: Currently, this maps to ExpectedMethod based on existing code,
// but should map to something a bit more accurate at some point.
@@ -2390,6 +2435,8 @@ static std::string GenerateLangOptRequirements(const Record &R,
std::string FnName = "check", Test;
for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
std::string Part = (*I)->getValueAsString("Name");
+ if ((*I)->getValueAsBit("Negated"))
+ Test += "!";
Test += "S.LangOpts." + Part;
if (I + 1 != E)
Test += " || ";
@@ -2748,17 +2795,9 @@ static void WriteCategoryHeader(const Record *DocCategory,
// If there is content, print that as well.
std::string ContentStr = DocCategory->getValueAsString("Content");
- if (!ContentStr.empty()) {
- // Trim leading and trailing newlines and spaces.
- StringRef Content(ContentStr);
- while (Content.startswith("\r") || Content.startswith("\n") ||
- Content.startswith(" ") || Content.startswith("\t"))
- Content = Content.substr(1);
- while (Content.endswith("\r") || Content.endswith("\n") ||
- Content.endswith(" ") || Content.endswith("\t"))
- Content = Content.substr(0, Content.size() - 1);
- OS << Content;
- }
+ // Trim leading and trailing newlines and spaces.
+ OS << StringRef(ContentStr).trim();
+
OS << "\n\n";
}
@@ -2880,14 +2919,7 @@ static void WriteDocumentation(const DocumentationData &Doc,
std::string ContentStr = Doc.Documentation->getValueAsString("Content");
// Trim leading and trailing newlines and spaces.
- StringRef Content(ContentStr);
- while (Content.startswith("\r") || Content.startswith("\n") ||
- Content.startswith(" ") || Content.startswith("\t"))
- Content = Content.substr(1);
- while (Content.endswith("\r") || Content.endswith("\n") ||
- Content.endswith(" ") || Content.endswith("\t"))
- Content = Content.substr(0, Content.size() - 1);
- OS << Content;
+ OS << StringRef(ContentStr).trim();
OS << "\n\n\n";
}
OpenPOWER on IntegriCloud