summaryrefslogtreecommitdiff
path: root/clang/utils/TableGen/ClangAttrEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/utils/TableGen/ClangAttrEmitter.cpp')
-rw-r--r--clang/utils/TableGen/ClangAttrEmitter.cpp853
1 files changed, 466 insertions, 387 deletions
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 4c3742c8e339..bd20e447a950 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -48,22 +48,19 @@ namespace {
class FlattenedSpelling {
std::string V, N, NS;
- bool K;
+ bool K = false;
public:
FlattenedSpelling(const std::string &Variety, const std::string &Name,
const std::string &Namespace, bool KnownToGCC) :
V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {}
- explicit FlattenedSpelling(const Record &Spelling) :
- V(Spelling.getValueAsString("Variety")),
- N(Spelling.getValueAsString("Name")) {
-
+ explicit FlattenedSpelling(const Record &Spelling)
+ : V(std::string(Spelling.getValueAsString("Variety"))),
+ N(std::string(Spelling.getValueAsString("Name"))) {
assert(V != "GCC" && V != "Clang" &&
"Given a GCC spelling, which means this hasn't been flattened!");
if (V == "CXX11" || V == "C2x" || V == "Pragma")
- NS = Spelling.getValueAsString("Namespace");
- bool Unset;
- K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
+ NS = std::string(Spelling.getValueAsString("Namespace"));
}
const std::string &variety() const { return V; }
@@ -83,14 +80,15 @@ GetFlattenedSpellings(const Record &Attr) {
StringRef Variety = Spelling->getValueAsString("Variety");
StringRef Name = Spelling->getValueAsString("Name");
if (Variety == "GCC") {
- // Gin up two new spelling objects to add into the list.
- Ret.emplace_back("GNU", Name, "", true);
- Ret.emplace_back("CXX11", Name, "gnu", true);
+ Ret.emplace_back("GNU", std::string(Name), "", true);
+ Ret.emplace_back("CXX11", std::string(Name), "gnu", true);
+ if (Spelling->getValueAsBit("AllowInC"))
+ Ret.emplace_back("C2x", std::string(Name), "gnu", true);
} else if (Variety == "Clang") {
- Ret.emplace_back("GNU", Name, "", false);
- Ret.emplace_back("CXX11", Name, "clang", false);
+ Ret.emplace_back("GNU", std::string(Name), "", false);
+ Ret.emplace_back("CXX11", std::string(Name), "clang", false);
if (Spelling->getValueAsBit("AllowInC"))
- Ret.emplace_back("C2x", Name, "clang", false);
+ Ret.emplace_back("C2x", std::string(Name), "clang", false);
} else
Ret.push_back(FlattenedSpelling(*Spelling));
}
@@ -100,14 +98,16 @@ GetFlattenedSpellings(const Record &Attr) {
static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
- .EndsWith("Decl *", "Record.GetLocalDeclAs<"
- + std::string(type, 0, type.size()-1) + ">(Record.readInt())")
- .Case("TypeSourceInfo *", "Record.readTypeSourceInfo()")
- .Case("Expr *", "Record.readExpr()")
- .Case("IdentifierInfo *", "Record.readIdentifier()")
- .Case("StringRef", "Record.readString()")
- .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())")
- .Default("Record.readInt()");
+ .EndsWith("Decl *", "Record.GetLocalDeclAs<" +
+ std::string(type.data(), 0, type.size() - 1) +
+ ">(Record.readInt())")
+ .Case("TypeSourceInfo *", "Record.readTypeSourceInfo()")
+ .Case("Expr *", "Record.readExpr()")
+ .Case("IdentifierInfo *", "Record.readIdentifier()")
+ .Case("StringRef", "Record.readString()")
+ .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())")
+ .Case("OMPTraitInfo *", "Record.readOMPTraitInfo()")
+ .Default("Record.readInt()");
}
// Get a type that is suitable for storing an object of the specified type.
@@ -119,14 +119,20 @@ static StringRef getStorageType(StringRef type) {
// Assumes that the way to get the value is SA->getname()
static std::string WritePCHRecord(StringRef type, StringRef name) {
- return "Record." + StringSwitch<std::string>(type)
- .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ");\n")
- .Case("TypeSourceInfo *", "AddTypeSourceInfo(" + std::string(name) + ");\n")
- .Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
- .Case("IdentifierInfo *", "AddIdentifierRef(" + std::string(name) + ");\n")
- .Case("StringRef", "AddString(" + std::string(name) + ");\n")
- .Case("ParamIdx", "push_back(" + std::string(name) + ".serialize());\n")
- .Default("push_back(" + std::string(name) + ");\n");
+ return "Record." +
+ StringSwitch<std::string>(type)
+ .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ");\n")
+ .Case("TypeSourceInfo *",
+ "AddTypeSourceInfo(" + std::string(name) + ");\n")
+ .Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
+ .Case("IdentifierInfo *",
+ "AddIdentifierRef(" + std::string(name) + ");\n")
+ .Case("StringRef", "AddString(" + std::string(name) + ");\n")
+ .Case("ParamIdx",
+ "push_back(" + std::string(name) + ".serialize());\n")
+ .Case("OMPTraitInfo *",
+ "writeOMPTraitInfo(" + std::string(name) + ");\n")
+ .Default("push_back(" + std::string(name) + ");\n");
}
// Normalize attribute name by removing leading and trailing
@@ -167,7 +173,7 @@ static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records,
std::string AN;
if (Attr->isSubClassOf("TargetSpecificAttr") &&
!Attr->isValueUnset("ParseKind")) {
- AN = Attr->getValueAsString("ParseKind");
+ AN = std::string(Attr->getValueAsString("ParseKind"));
// If this attribute has already been handled, it does not need to be
// handled again.
@@ -196,8 +202,8 @@ namespace {
public:
Argument(const Record &Arg, StringRef Attr)
- : lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
- attrName(Attr), isOpt(false), Fake(false) {
+ : lowerName(std::string(Arg.getValueAsString("Name"))),
+ upperName(lowerName), attrName(Attr), isOpt(false), Fake(false) {
if (!lowerName.empty()) {
lowerName[0] = std::tolower(lowerName[0]);
upperName[0] = std::toupper(upperName[0]);
@@ -299,8 +305,9 @@ namespace {
}
void writePCHWrite(raw_ostream &OS) const override {
- OS << " " << WritePCHRecord(type, "SA->get" +
- std::string(getUpperName()) + "()");
+ OS << " "
+ << WritePCHRecord(type,
+ "SA->get" + std::string(getUpperName()) + "()");
}
std::string getIsOmitted() const override {
@@ -331,9 +338,9 @@ namespace {
}
void writeDump(raw_ostream &OS) const override {
- if (type == "FunctionDecl *" || type == "NamedDecl *") {
+ if (StringRef(type).endswith("Decl *")) {
OS << " OS << \" \";\n";
- OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
+ OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
} else if (type == "IdentifierInfo *") {
// Some non-optional (comma required) identifier arguments can be the
// empty string but are then recorded as a nullptr.
@@ -355,6 +362,8 @@ namespace {
OS << " if (SA->get" << getUpperName() << "().isValid())\n ";
OS << " OS << \" \" << SA->get" << getUpperName()
<< "().getSourceIndex();\n";
+ } else if (type == "OMPTraitInfo *") {
+ OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
} else {
llvm_unreachable("Unknown SimpleArgument type!");
}
@@ -416,8 +425,8 @@ namespace {
}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " if (!" << getUpperName() << ".empty())\n";
- OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
+ OS << " if (!" << getUpperName() << ".empty())\n";
+ OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
<< ".data(), " << getLowerName() << "Length);\n";
}
@@ -471,6 +480,7 @@ namespace {
void writeAccessors(raw_ostream &OS) const override {
OS << " bool is" << getUpperName() << "Dependent() const;\n";
+ OS << " bool is" << getUpperName() << "ErrorDependent() const;\n";
OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n";
@@ -495,12 +505,21 @@ namespace {
OS << " if (is" << getLowerName() << "Expr)\n";
OS << " return " << getLowerName() << "Expr && (" << getLowerName()
<< "Expr->isValueDependent() || " << getLowerName()
- << "Expr->isTypeDependent());\n";
+ << "Expr->isTypeDependent());\n";
OS << " else\n";
OS << " return " << getLowerName()
<< "Type->getType()->isDependentType();\n";
OS << "}\n";
+ OS << "bool " << getAttrName() << "Attr::is" << getUpperName()
+ << "ErrorDependent() const {\n";
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " return " << getLowerName() << "Expr && " << getLowerName()
+ << "Expr->containsErrors();\n";
+ OS << " return " << getLowerName()
+ << "Type->getType()->containsErrors();\n";
+ OS << "}\n";
+
// FIXME: Do not do the calculation here
// FIXME: Handle types correctly
// A null pointer means maximum alignment
@@ -520,11 +539,11 @@ namespace {
void writeASTVisitorTraversal(raw_ostream &OS) const override {
StringRef Name = getUpperName();
OS << " if (A->is" << Name << "Expr()) {\n"
- << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n"
- << " return false;\n"
+ << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n"
+ << " return false;\n"
<< " } else if (auto *TSI = A->get" << Name << "Type()) {\n"
<< " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n"
- << " return false;\n"
+ << " return false;\n"
<< " }\n";
}
@@ -642,7 +661,7 @@ namespace {
VariadicArgument(const Record &Arg, StringRef Attr, std::string T)
: Argument(Arg, Attr), Type(std::move(T)),
ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"),
- RangeName(getLowerName()) {}
+ RangeName(std::string(getLowerName())) {}
const std::string &getType() const { return Type; }
const std::string &getArgName() const { return ArgName; }
@@ -653,7 +672,7 @@ namespace {
std::string IteratorType = getLowerName().str() + "_iterator";
std::string BeginFn = getLowerName().str() + "_begin()";
std::string EndFn = getLowerName().str() + "_end()";
-
+
OS << " typedef " << Type << "* " << IteratorType << ";\n";
OS << " " << IteratorType << " " << BeginFn << " const {"
<< " return " << ArgName << "; }\n";
@@ -681,8 +700,8 @@ namespace {
}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " std::copy(" << getUpperName() << ", " << getUpperName()
- << " + " << ArgSizeName << ", " << ArgName << ");\n";
+ OS << " std::copy(" << getUpperName() << ", " << getUpperName() << " + "
+ << ArgSizeName << ", " << ArgName << ");\n";
}
void writeCtorInitializers(raw_ostream &OS) const override {
@@ -719,8 +738,8 @@ namespace {
// If we can't store the values in the current type (if it's something
// like StringRef), store them in a different type and convert the
// container afterwards.
- std::string StorageType = getStorageType(getType());
- std::string StorageName = getLowerName();
+ std::string StorageType = std::string(getStorageType(getType()));
+ std::string StorageName = std::string(getLowerName());
if (StorageType != getType()) {
StorageName += "Storage";
OS << " SmallVector<" << StorageType << ", 4> "
@@ -805,11 +824,10 @@ namespace {
public:
EnumArgument(const Record &Arg, StringRef Attr)
- : Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
- values(Arg.getValueAsListOfStrings("Values")),
- enums(Arg.getValueAsListOfStrings("Enums")),
- uniques(uniqueEnumsInOrder(enums))
- {
+ : Argument(Arg, Attr), type(std::string(Arg.getValueAsString("Type"))),
+ values(Arg.getValueAsListOfStrings("Values")),
+ enums(Arg.getValueAsListOfStrings("Enums")),
+ uniques(uniqueEnumsInOrder(enums)) {
// FIXME: Emit a proper error
assert(!uniques.empty());
}
@@ -885,40 +903,48 @@ namespace {
OS << " }\n";
}
- void writeConversion(raw_ostream &OS) const {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
- OS << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ void writeConversion(raw_ostream &OS, bool Header) const {
+ if (Header) {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
+ << " &Out);\n";
+ OS << " static const char *Convert" << type << "ToStr(" << type
+ << " Val);\n";
+ return;
+ }
+
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
+ << "(StringRef Val, " << type << " &Out) {\n";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
OS << type << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
- OS << " .Case(\"" << values[I] << "\", ";
+ OS << " .Case(\"" << values[I] << "\", ";
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
- OS << " if (R) {\n";
- OS << " Out = *R;\n return true;\n }\n";
- OS << " return false;\n";
- OS << " }\n\n";
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << "}\n\n";
// Mapping from enumeration values back to enumeration strings isn't
// trivial because some enumeration values have multiple named
// enumerators, such as type_visibility(internal) and
// type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden.
- OS << " static const char *Convert" << type << "ToStr("
- << type << " Val) {\n"
- << " switch(Val) {\n";
+ OS << "const char *" << getAttrName() << "Attr::Convert" << type
+ << "ToStr(" << type << " Val) {\n"
+ << " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
- << ": return \"" << values[I] << "\";\n";
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
+ << ": return \"" << values[I] << "\";\n";
}
- OS << " }\n"
- << " llvm_unreachable(\"No enumerator with that value\");\n"
- << " }\n";
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << "}\n";
}
};
-
+
class VariadicEnumArgument: public VariadicArgument {
std::string type, QualifiedTypeName;
std::vector<StringRef> values, enums, uniques;
@@ -934,20 +960,20 @@ namespace {
public:
VariadicEnumArgument(const Record &Arg, StringRef Attr)
- : VariadicArgument(Arg, Attr, Arg.getValueAsString("Type")),
- type(Arg.getValueAsString("Type")),
- values(Arg.getValueAsListOfStrings("Values")),
- enums(Arg.getValueAsListOfStrings("Enums")),
- uniques(uniqueEnumsInOrder(enums))
- {
+ : VariadicArgument(Arg, Attr,
+ std::string(Arg.getValueAsString("Type"))),
+ type(std::string(Arg.getValueAsString("Type"))),
+ values(Arg.getValueAsListOfStrings("Values")),
+ enums(Arg.getValueAsListOfStrings("Enums")),
+ uniques(uniqueEnumsInOrder(enums)) {
QualifiedTypeName = getAttrName().str() + "Attr::" + type;
-
+
// FIXME: Emit a proper error
assert(!uniques.empty());
}
bool isVariadicEnumArg() const override { return true; }
-
+
void writeDeclarations(raw_ostream &OS) const override {
auto i = uniques.cbegin(), e = uniques.cend();
// The last one needs to not have a comma.
@@ -960,7 +986,7 @@ namespace {
OS << " " << *e << "\n";
OS << " };\n";
OS << "private:\n";
-
+
VariadicArgument::writeDeclarations(OS);
}
@@ -997,33 +1023,42 @@ namespace {
OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)");
}
- void writeConversion(raw_ostream &OS) const {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
+ void writeConversion(raw_ostream &OS, bool Header) const {
+ if (Header) {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
+ << " &Out);\n";
+ OS << " static const char *Convert" << type << "ToStr(" << type
+ << " Val);\n";
+ return;
+ }
+
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
+ << "(StringRef Val, ";
OS << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
OS << type << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
- OS << " .Case(\"" << values[I] << "\", ";
+ OS << " .Case(\"" << values[I] << "\", ";
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
- OS << " if (R) {\n";
- OS << " Out = *R;\n return true;\n }\n";
- OS << " return false;\n";
- OS << " }\n\n";
-
- OS << " static const char *Convert" << type << "ToStr("
- << type << " Val) {\n"
- << " switch(Val) {\n";
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << "}\n\n";
+
+ OS << "const char *" << getAttrName() << "Attr::Convert" << type
+ << "ToStr(" << type << " Val) {\n"
+ << " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
- << ": return \"" << values[I] << "\";\n";
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
+ << ": return \"" << values[I] << "\";\n";
}
- OS << " }\n"
- << " llvm_unreachable(\"No enumerator with that value\");\n"
- << " }\n";
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << "}\n";
}
};
@@ -1037,7 +1072,7 @@ namespace {
OS << " VersionTuple get" << getUpperName() << "() const {\n";
OS << " return " << getLowerName() << ";\n";
OS << " }\n";
- OS << " void set" << getUpperName()
+ OS << " void set" << getUpperName()
<< "(ASTContext &C, VersionTuple V) {\n";
OS << " " << getLowerName() << " = V;\n";
OS << " }";
@@ -1199,15 +1234,15 @@ namespace {
{}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n"
- " ++I) {\n"
- " StringRef Ref = " << getUpperName() << "[I];\n"
- " if (!Ref.empty()) {\n"
- " char *Mem = new (Ctx, 1) char[Ref.size()];\n"
- " std::memcpy(Mem, Ref.data(), Ref.size());\n"
- " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n"
- " }\n"
- " }\n";
+ OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n"
+ " ++I) {\n"
+ " StringRef Ref = " << getUpperName() << "[I];\n"
+ " if (!Ref.empty()) {\n"
+ " char *Mem = new (Ctx, 1) char[Ref.size()];\n"
+ " std::memcpy(Mem, Ref.data(), Ref.size());\n"
+ " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n"
+ " }\n"
+ " }\n";
}
void writeValueImpl(raw_ostream &OS) const override {
@@ -1241,8 +1276,9 @@ namespace {
}
void writePCHWrite(raw_ostream &OS) const override {
- OS << " " << WritePCHRecord(
- getType(), "SA->get" + std::string(getUpperName()) + "Loc()");
+ OS << " "
+ << WritePCHRecord(getType(),
+ "SA->get" + std::string(getUpperName()) + "Loc()");
}
};
@@ -1263,10 +1299,9 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = std::make_unique<EnumArgument>(Arg, Attr);
else if (ArgName == "ExprArgument")
Ptr = std::make_unique<ExprArgument>(Arg, Attr);
- else if (ArgName == "FunctionArgument")
- Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
- else if (ArgName == "NamedArgument")
- Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *");
+ else if (ArgName == "DeclArgument")
+ Ptr = std::make_unique<SimpleArgument>(
+ Arg, Attr, (Arg.getValueAsDef("Kind")->getName() + "Decl *").str());
else if (ArgName == "IdentifierArgument")
Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
else if (ArgName == "DefaultBoolArgument")
@@ -1303,6 +1338,8 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = std::make_unique<VariadicIdentifierArgument>(Arg, Attr);
else if (ArgName == "VersionArgument")
Ptr = std::make_unique<VersionArgument>(Arg, Attr);
+ else if (ArgName == "OMPTraitInfoArgument")
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "OMPTraitInfo *");
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
@@ -1341,7 +1378,7 @@ static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) {
OS << " OS << \"";
}
-static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
+static void writeGetSpellingFunction(const Record &R, raw_ostream &OS) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n";
@@ -1365,7 +1402,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
}
static void
-writePrettyPrintFunction(Record &R,
+writePrettyPrintFunction(const Record &R,
const std::vector<std::unique_ptr<Argument>> &Args,
raw_ostream &OS) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
@@ -1577,11 +1614,12 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) {
static bool
SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) {
assert(!Spellings.empty() && "An empty list of spellings was provided");
- std::string FirstName = NormalizeNameForSpellingComparison(
- Spellings.front().name());
+ std::string FirstName =
+ std::string(NormalizeNameForSpellingComparison(Spellings.front().name()));
for (const auto &Spelling :
llvm::make_range(std::next(Spellings.begin()), Spellings.end())) {
- std::string Name = NormalizeNameForSpellingComparison(Spelling.name());
+ std::string Name =
+ std::string(NormalizeNameForSpellingComparison(Spelling.name()));
if (Name != FirstName)
return false;
}
@@ -1727,7 +1765,7 @@ struct AttributeSubjectMatchRule {
}
std::string getSpelling() const {
- std::string Result = MetaSubject->getValueAsString("Name");
+ std::string Result = std::string(MetaSubject->getValueAsString("Name"));
if (isSubRule()) {
Result += '(';
if (isNegatedSubRule())
@@ -1752,7 +1790,7 @@ struct AttributeSubjectMatchRule {
}
if (isAbstractRule())
Result += "_abstract";
- return Result.str();
+ return std::string(Result.str());
}
std::string getEnumValue() const { return "attr::" + getEnumValueName(); }
@@ -1801,7 +1839,7 @@ struct PragmaClangAttributeSupport {
void emitMatchRuleList(raw_ostream &OS);
- std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS);
+ void generateStrictConformsTo(const Record &Attr, raw_ostream &OS);
void generateParsingHelpers(raw_ostream &OS);
};
@@ -1950,6 +1988,11 @@ static std::string GenerateTestExpression(ArrayRef<Record *> LangOpts) {
Test += "(";
Test += Code;
Test += ")";
+ if (!E->getValueAsString("Name").empty()) {
+ PrintWarning(
+ E->getLoc(),
+ "non-empty 'Name' field ignored because 'CustomCode' was supplied");
+ }
} else {
Test += "LangOpts.";
Test += E->getValueAsString("Name");
@@ -1962,21 +2005,17 @@ static std::string GenerateTestExpression(ArrayRef<Record *> LangOpts) {
return Test;
}
-std::string
+void
PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
raw_ostream &OS) {
- if (!isAttributedSupported(Attr))
- return "nullptr";
+ if (!isAttributedSupported(Attr) || Attr.isValueUnset("Subjects"))
+ return;
// 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();
- OS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<"
+ OS << "void getPragmaAttributeMatchRules("
+ << "llvm::SmallVectorImpl<std::pair<"
<< AttributeSubjectMatchRule::EnumName
- << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n";
- if (Attr.isValueUnset("Subjects")) {
- OS << "}\n\n";
- return FnName;
- }
+ << ", bool>> &MatchRules, const LangOptions &LangOpts) const override {\n";
const Record *SubjectObj = Attr.getValueAsDef("Subjects");
std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
for (const auto *Subject : Subjects) {
@@ -1993,7 +2032,6 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
}
}
OS << "}\n\n";
- return FnName;
}
void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
@@ -2223,13 +2261,8 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
}
-// Emits the class definitions for attributes.
-void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute classes' definitions", OS);
-
- OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
- OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
-
+static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
+ bool Header) {
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
ParsedAttrMap AttrMap = getParsedAttrList(Records);
@@ -2246,10 +2279,10 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// When attribute documentation can be generated as part of the build
// itself, this code can be removed.
(void)R.getValueAsListOfDefs("Documentation");
-
+
if (!R.getValueAsBit("ASTNode"))
continue;
-
+
ArrayRef<std::pair<Record *, SMRange>> Supers = R.getSuperClasses();
assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
std::string SuperName;
@@ -2258,12 +2291,15 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
const Record *R = Super.first;
if (R->getName() != "TargetSpecificAttr" &&
R->getName() != "DeclOrTypeAttr" && SuperName.empty())
- SuperName = R->getName();
+ SuperName = std::string(R->getName());
if (R->getName() == "InheritableAttr")
Inheritable = true;
}
- OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
+ if (Header)
+ OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
+ else
+ OS << "\n// " << R.getName() << "Attr implementation\n\n";
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
std::vector<std::unique_ptr<Argument>> Args;
@@ -2273,8 +2309,10 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
bool HasFakeArg = false;
for (const auto *ArgRecord : ArgRecords) {
Args.emplace_back(createArgument(*ArgRecord, R.getName()));
- Args.back()->writeDeclarations(OS);
- OS << "\n\n";
+ if (Header) {
+ Args.back()->writeDeclarations(OS);
+ OS << "\n\n";
+ }
// For these purposes, fake takes priority over optional.
if (Args.back()->isFake()) {
@@ -2284,7 +2322,8 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
}
- OS << "public:\n";
+ if (Header)
+ OS << "public:\n";
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
@@ -2297,8 +2336,11 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// This maps spelling index values to semantic Spelling enumerants.
SemanticSpellingMap SemanticToSyntacticMap;
- if (!ElideSpelling)
- OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
+ std::string SpellingEnum;
+ if (Spellings.size() > 1)
+ SpellingEnum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
+ if (Header)
+ OS << SpellingEnum;
const auto &ParsedAttrSpellingItr = llvm::find_if(
AttrMap, [R](const std::pair<std::string, const Record *> &P) {
@@ -2307,9 +2349,14 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// Emit CreateImplicit factory methods.
auto emitCreate = [&](bool Implicit, bool emitFake) {
- OS << " static " << R.getName() << "Attr *Create";
- if (Implicit)
- OS << "Implicit";
+ if (Header)
+ OS << " static ";
+ OS << R.getName() << "Attr *";
+ if (!Header)
+ OS << R.getName() << "Attr::";
+ OS << "Create";
+ if (Implicit)
+ OS << "Implicit";
OS << "(";
OS << "ASTContext &Ctx";
for (auto const &ai : Args) {
@@ -2317,8 +2364,17 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
ai->writeCtorParameters(OS);
}
- OS << ", const AttributeCommonInfo &CommonInfo = {SourceRange{}}) {\n";
- OS << " auto *A = new (Ctx) " << R.getName();
+ OS << ", const AttributeCommonInfo &CommonInfo";
+ if (Header)
+ OS << " = {SourceRange{}}";
+ OS << ")";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+
+ OS << " {\n";
+ OS << " auto *A = new (Ctx) " << R.getName();
OS << "Attr(Ctx, CommonInfo";
for (auto const &ai : Args) {
if (ai->isFake() && !emitFake) continue;
@@ -2327,18 +2383,23 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << ");\n";
if (Implicit) {
- OS << " A->setImplicit(true);\n";
+ OS << " A->setImplicit(true);\n";
}
if (Implicit || ElideSpelling) {
- OS << " if (!A->isAttributeSpellingListCalculated() && "
+ OS << " if (!A->isAttributeSpellingListCalculated() && "
"!A->getAttrName())\n";
- OS << " A->setAttributeSpellingListIndex(0);\n";
+ OS << " A->setAttributeSpellingListIndex(0);\n";
}
- OS << " return A;\n }\n\n";
+ OS << " return A;\n}\n\n";
};
auto emitCreateNoCI = [&](bool Implicit, bool emitFake) {
- OS <<" static " << R.getName() << "Attr *Create";
+ if (Header)
+ OS << " static ";
+ OS << R.getName() << "Attr *";
+ if (!Header)
+ OS << R.getName() << "Attr::";
+ OS << "Create";
if (Implicit)
OS << "Implicit";
OS << "(";
@@ -2349,12 +2410,19 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
ai->writeCtorParameters(OS);
}
OS << ", SourceRange Range, AttributeCommonInfo::Syntax Syntax";
- if (!ElideSpelling)
- OS << ", " << R.getName()
- << "Attr::Spelling S = "
- "static_cast<Spelling>(SpellingNotCalculated)";
- OS << ") {\n";
- OS << " AttributeCommonInfo I(Range, ";
+ if (!ElideSpelling) {
+ OS << ", " << R.getName() << "Attr::Spelling S";
+ if (Header)
+ OS << " = static_cast<Spelling>(SpellingNotCalculated)";
+ }
+ OS << ")";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+
+ OS << " {\n";
+ OS << " AttributeCommonInfo I(Range, ";
if (ParsedAttrSpellingItr != std::end(AttrMap))
OS << "AT_" << ParsedAttrSpellingItr->first;
@@ -2365,7 +2433,7 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!ElideSpelling)
OS << ", S";
OS << ");\n";
- OS << " return Create";
+ OS << " return Create";
if (Implicit)
OS << "Implicit";
OS << "(Ctx";
@@ -2375,7 +2443,7 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
ai->writeImplicitCtorArgs(OS);
}
OS << ", I);\n";
- OS << " }\n";
+ OS << "}\n\n";
};
auto emitCreates = [&](bool emitFake) {
@@ -2385,6 +2453,9 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
emitCreateNoCI(false, emitFake);
};
+ if (Header)
+ OS << " // Factory methods\n";
+
// Emit a CreateImplicit that takes all the arguments.
emitCreates(true);
@@ -2399,7 +2470,11 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (arg->isOptional()) return emitOpt;
return true;
};
- OS << " " << R.getName()
+ if (Header)
+ OS << " ";
+ else
+ OS << R.getName() << "Attr::";
+ OS << R.getName()
<< "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo";
OS << '\n';
for (auto const &ai : Args) {
@@ -2409,8 +2484,12 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
- OS << " )\n";
- OS << " : " << SuperName << "(Ctx, CommonInfo, ";
+ OS << " )";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+ OS << "\n : " << SuperName << "(Ctx, CommonInfo, ";
OS << "attr::" << R.getName() << ", "
<< (R.getValueAsBit("LateParsed") ? "true" : "false");
if (Inheritable) {
@@ -2431,14 +2510,17 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " {\n";
-
+
for (auto const &ai : Args) {
if (!shouldEmitArg(ai)) continue;
ai->writeCtorBody(OS);
}
- OS << " }\n\n";
+ OS << "}\n\n";
};
+ if (Header)
+ OS << "\n // Constructors\n";
+
// Emit a constructor that includes all the arguments.
// This is necessary for cloning.
emitCtor(true, true);
@@ -2446,48 +2528,89 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// Emit a constructor that takes all the non-fake arguments.
if (HasFakeArg)
emitCtor(true, false);
-
+
// Emit a constructor that takes all the non-fake, non-optional arguments.
if (HasOptArg)
emitCtor(false, false);
- OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
- OS << " void printPretty(raw_ostream &OS,\n"
- << " const PrintingPolicy &Policy) const;\n";
- OS << " const char *getSpelling() const;\n";
-
+ if (Header) {
+ OS << '\n';
+ OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
+ OS << " void printPretty(raw_ostream &OS,\n"
+ << " const PrintingPolicy &Policy) const;\n";
+ OS << " const char *getSpelling() const;\n";
+ }
+
if (!ElideSpelling) {
assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list");
- OS << " Spelling getSemanticSpelling() const {\n";
- WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()",
- SemanticToSyntacticMap, OS);
- OS << " }\n";
+ if (Header)
+ OS << " Spelling getSemanticSpelling() const;\n";
+ else {
+ OS << R.getName() << "Attr::Spelling " << R.getName()
+ << "Attr::getSemanticSpelling() const {\n";
+ WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()",
+ SemanticToSyntacticMap, OS);
+ OS << "}\n";
+ }
}
- writeAttrAccessorDefinition(R, OS);
+ if (Header)
+ writeAttrAccessorDefinition(R, OS);
for (auto const &ai : Args) {
- ai->writeAccessors(OS);
+ if (Header) {
+ ai->writeAccessors(OS);
+ } else {
+ ai->writeAccessorDefinitions(OS);
+ }
OS << "\n\n";
// Don't write conversion routines for fake arguments.
if (ai->isFake()) continue;
if (ai->isEnumArg())
- static_cast<const EnumArgument *>(ai.get())->writeConversion(OS);
+ static_cast<const EnumArgument *>(ai.get())->writeConversion(OS,
+ Header);
else if (ai->isVariadicEnumArg())
- static_cast<const VariadicEnumArgument *>(ai.get())
- ->writeConversion(OS);
+ static_cast<const VariadicEnumArgument *>(ai.get())->writeConversion(
+ OS, Header);
}
- OS << R.getValueAsString("AdditionalMembers");
- OS << "\n\n";
+ if (Header) {
+ OS << R.getValueAsString("AdditionalMembers");
+ OS << "\n\n";
- OS << " static bool classof(const Attr *A) { return A->getKind() == "
- << "attr::" << R.getName() << "; }\n";
+ OS << " static bool classof(const Attr *A) { return A->getKind() == "
+ << "attr::" << R.getName() << "; }\n";
- OS << "};\n\n";
+ OS << "};\n\n";
+ } else {
+ OS << R.getName() << "Attr *" << R.getName()
+ << "Attr::clone(ASTContext &C) const {\n";
+ OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
+ for (auto const &ai : Args) {
+ OS << ", ";
+ ai->writeCloneArgs(OS);
+ }
+ OS << ");\n";
+ OS << " A->Inherited = Inherited;\n";
+ OS << " A->IsPackExpansion = IsPackExpansion;\n";
+ OS << " A->setImplicit(Implicit);\n";
+ OS << " return A;\n}\n\n";
+
+ writePrettyPrintFunction(R, Args, OS);
+ writeGetSpellingFunction(R, OS);
+ }
}
+}
+// Emits the class definitions for attributes.
+void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Attribute classes' definitions", OS);
+
+ OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
+ OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
+
+ emitAttributes(Records, OS, true);
OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n";
}
@@ -2496,38 +2619,9 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute classes' member function definitions", OS);
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
- for (auto *Attr : Attrs) {
- Record &R = *Attr;
-
- if (!R.getValueAsBit("ASTNode"))
- continue;
-
- std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
- std::vector<std::unique_ptr<Argument>> Args;
- for (const auto *Arg : ArgRecords)
- Args.emplace_back(createArgument(*Arg, R.getName()));
-
- for (auto const &ai : Args)
- ai->writeAccessorDefinitions(OS);
-
- OS << R.getName() << "Attr *" << R.getName()
- << "Attr::clone(ASTContext &C) const {\n";
- OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
- for (auto const &ai : Args) {
- OS << ", ";
- ai->writeCloneArgs(OS);
- }
- OS << ");\n";
- OS << " A->Inherited = Inherited;\n";
- OS << " A->IsPackExpansion = IsPackExpansion;\n";
- OS << " A->setImplicit(Implicit);\n";
- OS << " return A;\n}\n\n";
+ emitAttributes(Records, OS, false);
- writePrettyPrintFunction(R, Args, OS);
- writeGetSpellingFunction(R, OS);
- }
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
// Instead of relying on virtual dispatch we just create a huge dispatch
// switch. This is both smaller and faster than virtual functions.
@@ -2825,6 +2919,7 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
if (R.isSubClassOf(InhClass))
OS << " bool isInherited = Record.readInt();\n";
OS << " bool isImplicit = Record.readInt();\n";
+ OS << " bool isPackExpansion = Record.readInt();\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (const auto *Arg : ArgRecords) {
@@ -2840,6 +2935,7 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
if (R.isSubClassOf(InhClass))
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
OS << " New->setImplicit(isImplicit);\n";
+ OS << " New->setPackExpansion(isPackExpansion);\n";
OS << " break;\n";
OS << " }\n";
}
@@ -2866,6 +2962,7 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
if (R.isSubClassOf(InhClass))
OS << " Record.push_back(SA->isInherited());\n";
OS << " Record.push_back(A->isImplicit());\n";
+ OS << " Record.push_back(A->isPackExpansion());\n";
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writePCHWrite(OS);
@@ -2965,7 +3062,7 @@ static void GenerateHasAttrSpellingStringSwitch(
// them. If the attribute has no scope, the version information must not
// have the default value (1), as that's incorrect. Instead, the unscoped
// attribute version information should be taken from the SD-6 standing
- // document, which can be found at:
+ // document, which can be found at:
// https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
int Version = 1;
@@ -3257,7 +3354,7 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#ifndef PARSED_ATTR\n";
OS << "#define PARSED_ATTR(NAME) NAME\n";
OS << "#endif\n\n";
-
+
ParsedAttrMap Names = getParsedAttrList(Records);
for (const auto &I : Names) {
OS << "PARSED_ATTR(" << I.first << ")\n";
@@ -3287,18 +3384,12 @@ static void emitArgInfo(const Record &R, raw_ostream &OS) {
// If there is a variadic argument, we will set the optional argument count
// to its largest value. Since it's currently a 4-bit number, we set it to 15.
- OS << ArgCount << ", " << (HasVariadic ? 15 : OptCount);
-}
-
-static void GenerateDefaultAppertainsTo(raw_ostream &OS) {
- OS << "static bool defaultAppertainsTo(Sema &, const ParsedAttr &,";
- OS << "const Decl *) {\n";
- OS << " return true;\n";
- OS << "}\n\n";
+ OS << " NumArgs = " << ArgCount << ";\n";
+ OS << " OptArgs = " << (HasVariadic ? 15 : OptCount) << ";\n";
}
static std::string GetDiagnosticSpelling(const Record &R) {
- std::string Ret = R.getValueAsString("DiagSpelling");
+ std::string Ret = std::string(R.getValueAsString("DiagSpelling"));
if (!Ret.empty())
return Ret;
@@ -3334,7 +3425,7 @@ static std::string CalculateDiagnostic(const Record &S) {
SmallVector<StringRef, 2> Frags;
llvm::SplitString(V, Frags, ",");
for (auto Str : Frags) {
- DiagList.push_back(Str.trim());
+ DiagList.push_back(std::string(Str.trim()));
}
}
}
@@ -3365,7 +3456,7 @@ static std::string CalculateDiagnostic(const Record &S) {
}
static std::string GetSubjectWithSuffix(const Record *R) {
- const std::string &B = R->getName();
+ const std::string &B = std::string(R->getName());
if (B == "DeclBase")
return "Decl";
return B + "Decl";
@@ -3375,16 +3466,14 @@ static std::string functionNameForCustomAppertainsTo(const Record &Subject) {
return "is" + Subject.getName().str();
}
-static std::string GenerateCustomAppertainsTo(const Record &Subject,
- raw_ostream &OS) {
+static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) {
std::string FnName = functionNameForCustomAppertainsTo(Subject);
- // If this code has already been generated, simply return the previous
- // instance of it.
+ // If this code has already been generated, we don't need to do anything.
static std::set<std::string> CustomSubjectSet;
auto I = CustomSubjectSet.find(FnName);
if (I != CustomSubjectSet.end())
- return *I;
+ return;
// This only works with non-root Decls.
Record *Base = Subject.getValueAsDef(BaseFieldName);
@@ -3393,7 +3482,7 @@ static std::string GenerateCustomAppertainsTo(const Record &Subject,
if (Base->isSubClassOf("SubsetSubject")) {
PrintFatalError(Subject.getLoc(),
"SubsetSubjects within SubsetSubjects is not supported");
- return "";
+ return;
}
OS << "static bool " << FnName << "(const Decl *D) {\n";
@@ -3405,14 +3494,13 @@ static std::string GenerateCustomAppertainsTo(const Record &Subject,
OS << "}\n\n";
CustomSubjectSet.insert(FnName);
- return FnName;
}
-static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
+static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
// If the attribute does not contain a Subjects definition, then use the
// default appertainsTo logic.
if (Attr.isValueUnset("Subjects"))
- return "defaultAppertainsTo";
+ return;
const Record *SubjectObj = Attr.getValueAsDef("Subjects");
std::vector<Record*> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
@@ -3420,52 +3508,46 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
// If the list of subjects is empty, it is assumed that the attribute
// appertains to everything.
if (Subjects.empty())
- return "defaultAppertainsTo";
+ return;
bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn");
// Otherwise, generate an appertainsTo check specific to this attribute which
- // checks all of the given subjects against the Decl passed in. Return the
- // name of that check to the caller.
+ // checks all of the given subjects against the Decl passed in.
//
// If D is null, that means the attribute was not applied to a declaration
// at all (for instance because it was applied to a type), or that the caller
// has determined that the check should fail (perhaps prior to the creation
// of the declaration).
- std::string FnName = "check" + Attr.getName().str() + "AppertainsTo";
- std::stringstream SS;
- SS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr, ";
- SS << "const Decl *D) {\n";
- SS << " if (!D || (";
+ OS << "bool diagAppertainsToDecl(Sema &S, ";
+ OS << "const ParsedAttr &Attr, const Decl *D) const override {\n";
+ OS << " if (";
for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) {
- // If the subject has custom code associated with it, generate a function
- // for it. The function cannot be inlined into this check (yet) because it
- // requires the subject to be of a specific type, and were that information
- // inlined here, it would not support an attribute with multiple custom
- // subjects.
+ // If the subject has custom code associated with it, use the generated
+ // function for it. The function cannot be inlined into this check (yet)
+ // because it requires the subject to be of a specific type, and were that
+ // information inlined here, it would not support an attribute with multiple
+ // custom subjects.
if ((*I)->isSubClassOf("SubsetSubject")) {
- SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)";
+ OS << "!" << functionNameForCustomAppertainsTo(**I) << "(D)";
} else {
- SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
+ OS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
}
if (I + 1 != E)
- SS << " && ";
+ OS << " && ";
}
- SS << ")) {\n";
- SS << " S.Diag(Attr.getLoc(), diag::";
- SS << (Warn ? "warn_attribute_wrong_decl_type_str" :
+ OS << ") {\n";
+ OS << " S.Diag(Attr.getLoc(), diag::";
+ OS << (Warn ? "warn_attribute_wrong_decl_type_str" :
"err_attribute_wrong_decl_type_str");
- SS << ")\n";
- SS << " << Attr << ";
- SS << CalculateDiagnostic(*SubjectObj) << ";\n";
- SS << " return false;\n";
- SS << " }\n";
- SS << " return true;\n";
- SS << "}\n\n";
-
- OS << SS.str();
- return FnName;
+ OS << ")\n";
+ OS << " << Attr << ";
+ OS << CalculateDiagnostic(*SubjectObj) << ";\n";
+ OS << " return false;\n";
+ OS << " }\n";
+ OS << " return true;\n";
+ OS << "}\n\n";
}
static void
@@ -3504,37 +3586,16 @@ emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport,
OS << "}\n\n";
}
-static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
- OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
- OS << "const ParsedAttr &) {\n";
- OS << " return true;\n";
- OS << "}\n\n";
-}
-
-static std::string GenerateLangOptRequirements(const Record &R,
- raw_ostream &OS) {
+static void GenerateLangOptRequirements(const Record &R,
+ raw_ostream &OS) {
// If the attribute has an empty or unset list of language requirements,
- // return the default handler.
+ // use the default handler.
std::vector<Record *> LangOpts = R.getValueAsListOfDefs("LangOpts");
if (LangOpts.empty())
- return "defaultDiagnoseLangOpts";
-
- // Generate a unique function name for the diagnostic test. The list of
- // options should usually be short (one or two options), and the
- // uniqueness isn't strictly necessary (it is just for codegen efficiency).
- std::string FnName = "check";
- for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I)
- FnName += (*I)->getValueAsString("Name");
- FnName += "LangOpts";
-
- // If this code has already been generated, simply return the previous
- // instance of it.
- static std::set<std::string> CustomLangOptsSet;
- auto I = CustomLangOptsSet.find(FnName);
- if (I != CustomLangOptsSet.end())
- return *I;
-
- OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n";
+ return;
+
+ OS << "bool diagLangOpts(Sema &S, const ParsedAttr &Attr) ";
+ OS << "const override {\n";
OS << " auto &LangOpts = S.LangOpts;\n";
OS << " if (" << GenerateTestExpression(LangOpts) << ")\n";
OS << " return true;\n\n";
@@ -3542,24 +3603,15 @@ static std::string GenerateLangOptRequirements(const Record &R,
OS << "<< Attr;\n";
OS << " return false;\n";
OS << "}\n\n";
-
- CustomLangOptsSet.insert(FnName);
- return FnName;
-}
-
-static void GenerateDefaultTargetRequirements(raw_ostream &OS) {
- OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n";
- OS << " return true;\n";
- OS << "}\n\n";
}
-static std::string GenerateTargetRequirements(const Record &Attr,
- const ParsedAttrMap &Dupes,
- raw_ostream &OS) {
- // If the attribute is not a target specific attribute, return the default
+static void GenerateTargetRequirements(const Record &Attr,
+ const ParsedAttrMap &Dupes,
+ raw_ostream &OS) {
+ // If the attribute is not a target specific attribute, use the default
// target handler.
if (!Attr.isSubClassOf("TargetSpecificAttr"))
- return "defaultTargetRequirements";
+ return;
// Get the list of architectures to be tested for.
const Record *R = Attr.getValueAsDef("Target");
@@ -3587,55 +3639,51 @@ static std::string GenerateTargetRequirements(const Record &Attr,
std::string Test;
bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName);
- // If this code has already been generated, simply return the previous
- // instance of it.
- static std::set<std::string> CustomTargetSet;
- auto I = CustomTargetSet.find(FnName);
- if (I != CustomTargetSet.end())
- return *I;
-
- OS << "static bool " << FnName << "(const TargetInfo &Target) {\n";
+ OS << "bool existsInTarget(const TargetInfo &Target) const override {\n";
if (UsesT)
OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n";
OS << " return " << Test << ";\n";
OS << "}\n\n";
-
- CustomTargetSet.insert(FnName);
- return FnName;
-}
-
-static void GenerateDefaultSpellingIndexToSemanticSpelling(raw_ostream &OS) {
- OS << "static unsigned defaultSpellingIndexToSemanticSpelling("
- << "const ParsedAttr &Attr) {\n";
- OS << " return UINT_MAX;\n";
- OS << "}\n\n";
}
-static std::string GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
- raw_ostream &OS) {
+static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
+ raw_ostream &OS) {
// If the attribute does not have a semantic form, we can bail out early.
if (!Attr.getValueAsBit("ASTNode"))
- return "defaultSpellingIndexToSemanticSpelling";
+ return;
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
// If there are zero or one spellings, or all of the spellings share the same
// name, we can also bail out early.
if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings))
- return "defaultSpellingIndexToSemanticSpelling";
+ return;
// Generate the enumeration we will use for the mapping.
SemanticSpellingMap SemanticToSyntacticMap;
std::string Enum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
std::string Name = Attr.getName().str() + "AttrSpellingMap";
- OS << "static unsigned " << Name << "(const ParsedAttr &Attr) {\n";
+ OS << "unsigned spellingIndexToSemanticSpelling(";
+ OS << "const ParsedAttr &Attr) const override {\n";
OS << Enum;
OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n";
WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS);
OS << "}\n\n";
+}
+
+static void GenerateHandleDeclAttribute(const Record &Attr, raw_ostream &OS) {
+ // Only generate if Attr can be handled simply.
+ if (!Attr.getValueAsBit("SimpleHandler"))
+ return;
- return Name;
+ // Generate a function which just converts from ParsedAttr to the Attr type.
+ OS << "AttrHandling handleDeclAttribute(Sema &S, Decl *D,";
+ OS << "const ParsedAttr &Attr) const override {\n";
+ OS << " D->addAttr(::new (S.Context) " << Attr.getName();
+ OS << "Attr(S.Context, Attr));\n";
+ OS << " return AttributeApplied;\n";
+ OS << "}\n\n";
}
static bool IsKnownToGCC(const Record &Attr) {
@@ -3658,19 +3706,19 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
ParsedAttrMap Dupes;
ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes);
- // Generate the default appertainsTo, target and language option diagnostic,
- // and spelling list index mapping methods.
- GenerateDefaultAppertainsTo(OS);
- GenerateDefaultLangOptRequirements(OS);
- GenerateDefaultTargetRequirements(OS);
- GenerateDefaultSpellingIndexToSemanticSpelling(OS);
-
- // Generate the appertainsTo diagnostic methods and write their names into
- // another mapping. At the same time, generate the AttrInfoMap object
- // contents. Due to the reliance on generated code, use separate streams so
- // that code will not be interleaved.
- std::string Buffer;
- raw_string_ostream SS {Buffer};
+ // Generate all of the custom appertainsTo functions that the attributes
+ // will be using.
+ for (auto I : Attrs) {
+ const Record &Attr = *I.second;
+ if (Attr.isValueUnset("Subjects"))
+ continue;
+ const Record *SubjectObj = Attr.getValueAsDef("Subjects");
+ for (auto Subject : SubjectObj->getValueAsListOfDefs("Subjects"))
+ if (Subject->isSubClassOf("SubsetSubject"))
+ GenerateCustomAppertainsTo(*Subject, OS);
+ }
+
+ // Generate a ParsedAttrInfo struct for each of the attributes.
for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
// TODO: If the attribute's kind appears in the list of duplicates, that is
// because it is a target-specific attribute that appears multiple times.
@@ -3680,33 +3728,63 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// We need to generate struct instances based off ParsedAttrInfo from
// ParsedAttr.cpp.
- SS << " { ";
- emitArgInfo(*I->second, SS);
- SS << ", " << I->second->getValueAsBit("HasCustomParsing");
- SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
- SS << ", "
- << (I->second->isSubClassOf("TypeAttr") ||
- I->second->isSubClassOf("DeclOrTypeAttr"));
- 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)
- SS << ",";
-
- SS << " // AT_" << I->first << "\n";
+ const std::string &AttrName = I->first;
+ const Record &Attr = *I->second;
+ auto Spellings = GetFlattenedSpellings(Attr);
+ if (!Spellings.empty()) {
+ OS << "static constexpr ParsedAttrInfo::Spelling " << I->first
+ << "Spellings[] = {\n";
+ for (const auto &S : Spellings) {
+ const std::string &RawSpelling = S.name();
+ std::string Spelling;
+ if (!S.nameSpace().empty())
+ Spelling += S.nameSpace() + "::";
+ if (S.variety() == "GNU")
+ Spelling += NormalizeGNUAttrSpelling(RawSpelling);
+ else
+ Spelling += RawSpelling;
+ OS << " {AttributeCommonInfo::AS_" << S.variety();
+ OS << ", \"" << Spelling << "\"},\n";
+ }
+ OS << "};\n";
+ }
+ OS << "struct ParsedAttrInfo" << I->first
+ << " final : public ParsedAttrInfo {\n";
+ OS << " ParsedAttrInfo" << I->first << "() {\n";
+ OS << " AttrKind = ParsedAttr::AT_" << AttrName << ";\n";
+ emitArgInfo(Attr, OS);
+ OS << " HasCustomParsing = ";
+ OS << Attr.getValueAsBit("HasCustomParsing") << ";\n";
+ OS << " IsTargetSpecific = ";
+ OS << Attr.isSubClassOf("TargetSpecificAttr") << ";\n";
+ OS << " IsType = ";
+ OS << (Attr.isSubClassOf("TypeAttr") ||
+ Attr.isSubClassOf("DeclOrTypeAttr")) << ";\n";
+ OS << " IsStmt = ";
+ OS << Attr.isSubClassOf("StmtAttr") << ";\n";
+ OS << " IsKnownToGCC = ";
+ OS << IsKnownToGCC(Attr) << ";\n";
+ OS << " IsSupportedByPragmaAttribute = ";
+ OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n";
+ if (!Spellings.empty())
+ OS << " Spellings = " << I->first << "Spellings;\n";
+ OS << " }\n";
+ GenerateAppertainsTo(Attr, OS);
+ GenerateLangOptRequirements(Attr, OS);
+ GenerateTargetRequirements(Attr, Dupes, OS);
+ GenerateSpellingIndexToSemanticSpelling(Attr, OS);
+ PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
+ GenerateHandleDeclAttribute(Attr, OS);
+ OS << "static const ParsedAttrInfo" << I->first << " Instance;\n";
+ OS << "};\n";
+ OS << "const ParsedAttrInfo" << I->first << " ParsedAttrInfo" << I->first
+ << "::Instance;\n";
}
- OS << "static const ParsedAttrInfo AttrInfoMap[ParsedAttr::UnknownAttribute "
- "+ 1] = {\n";
- OS << SS.str();
+ OS << "static const ParsedAttrInfo *AttrInfoMap[] = {\n";
+ for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
+ OS << "&ParsedAttrInfo" << I->first << "::Instance,\n";
+ }
OS << "};\n\n";
// Generate the attribute match rules.
@@ -3740,7 +3818,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
std::string AttrName;
if (Attr.isSubClassOf("TargetSpecificAttr") &&
!Attr.isValueUnset("ParseKind")) {
- AttrName = Attr.getValueAsString("ParseKind");
+ AttrName = std::string(Attr.getValueAsString("ParseKind"));
if (Seen.find(AttrName) != Seen.end())
continue;
Seen.insert(AttrName);
@@ -3755,12 +3833,12 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
const std::string &Variety = S.variety();
if (Variety == "CXX11") {
Matches = &CXX11;
- Spelling += S.nameSpace();
- Spelling += "::";
+ if (!S.nameSpace().empty())
+ Spelling += S.nameSpace() + "::";
} else if (Variety == "C2x") {
Matches = &C2x;
- Spelling += S.nameSpace();
- Spelling += "::";
+ if (!S.nameSpace().empty())
+ Spelling += S.nameSpace() + "::";
} else if (Variety == "GNU")
Matches = &GNU;
else if (Variety == "Declspec")
@@ -3980,7 +4058,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
"documented");
// Determine the heading to be used for this attribute.
- std::string Heading = Documentation.getValueAsString("Heading");
+ std::string Heading = std::string(Documentation.getValueAsString("Heading"));
if (Heading.empty()) {
// If there's only one spelling, we can simply use that.
if (Spellings.size() == 1)
@@ -3989,7 +4067,8 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
std::set<std::string> Uniques;
for (auto I = Spellings.begin(), E = Spellings.end();
I != E && Uniques.size() <= 1; ++I) {
- std::string Spelling = NormalizeNameForSpellingComparison(I->name());
+ std::string Spelling =
+ std::string(NormalizeNameForSpellingComparison(I->name()));
Uniques.insert(Spelling);
}
// If the semantic map has only one spelling, that is sufficient for our