|  | //===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // These tablegen backends emit Clang attribute processing code | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ADT/ArrayRef.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/ADT/StringSet.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/ADT/iterator_range.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/TableGen/Error.h" | 
|  | #include "llvm/TableGen/Record.h" | 
|  | #include "llvm/TableGen/StringMatcher.h" | 
|  | #include "llvm/TableGen/TableGenBackend.h" | 
|  | #include <algorithm> | 
|  | #include <cassert> | 
|  | #include <cctype> | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <sstream> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class FlattenedSpelling { | 
|  | std::string V, N, NS; | 
|  | bool K; | 
|  |  | 
|  | 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")) { | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | const std::string &variety() const { return V; } | 
|  | const std::string &name() const { return N; } | 
|  | const std::string &nameSpace() const { return NS; } | 
|  | bool knownToGCC() const { return K; } | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static std::vector<FlattenedSpelling> | 
|  | GetFlattenedSpellings(const Record &Attr) { | 
|  | std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings"); | 
|  | std::vector<FlattenedSpelling> Ret; | 
|  |  | 
|  | for (const auto &Spelling : Spellings) { | 
|  | 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); | 
|  | } else if (Variety == "Clang") { | 
|  | Ret.emplace_back("GNU", Name, "", false); | 
|  | Ret.emplace_back("CXX11", Name, "clang", false); | 
|  | if (Spelling->getValueAsBit("AllowInC")) | 
|  | Ret.emplace_back("C2x", Name, "clang", false); | 
|  | } else | 
|  | Ret.push_back(FlattenedSpelling(*Spelling)); | 
|  | } | 
|  |  | 
|  | return Ret; | 
|  | } | 
|  |  | 
|  | 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.getTypeSourceInfo()") | 
|  | .Case("Expr *", "Record.readExpr()") | 
|  | .Case("IdentifierInfo *", "Record.getIdentifierInfo()") | 
|  | .Case("StringRef", "Record.readString()") | 
|  | .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())") | 
|  | .Default("Record.readInt()"); | 
|  | } | 
|  |  | 
|  | // Get a type that is suitable for storing an object of the specified type. | 
|  | static StringRef getStorageType(StringRef type) { | 
|  | return StringSwitch<StringRef>(type) | 
|  | .Case("StringRef", "std::string") | 
|  | .Default(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"); | 
|  | } | 
|  |  | 
|  | // Normalize attribute name by removing leading and trailing | 
|  | // underscores. For example, __foo, foo__, __foo__ would | 
|  | // become foo. | 
|  | static StringRef NormalizeAttrName(StringRef AttrName) { | 
|  | AttrName.consume_front("__"); | 
|  | AttrName.consume_back("__"); | 
|  | return AttrName; | 
|  | } | 
|  |  | 
|  | // Normalize the name by removing any and all leading and trailing underscores. | 
|  | // This is different from NormalizeAttrName in that it also handles names like | 
|  | // _pascal and __pascal. | 
|  | static StringRef NormalizeNameForSpellingComparison(StringRef Name) { | 
|  | return Name.trim("_"); | 
|  | } | 
|  |  | 
|  | // Normalize the spelling of a GNU attribute (i.e. "x" in "__attribute__((x))"), | 
|  | // removing "__" if it appears at the beginning and end of the attribute's name. | 
|  | static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) { | 
|  | if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) { | 
|  | AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4); | 
|  | } | 
|  |  | 
|  | return AttrSpelling; | 
|  | } | 
|  |  | 
|  | typedef std::vector<std::pair<std::string, const Record *>> ParsedAttrMap; | 
|  |  | 
|  | static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, | 
|  | ParsedAttrMap *Dupes = nullptr) { | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  | std::set<std::string> Seen; | 
|  | ParsedAttrMap R; | 
|  | for (const auto *Attr : Attrs) { | 
|  | if (Attr->getValueAsBit("SemaHandler")) { | 
|  | std::string AN; | 
|  | if (Attr->isSubClassOf("TargetSpecificAttr") && | 
|  | !Attr->isValueUnset("ParseKind")) { | 
|  | AN = Attr->getValueAsString("ParseKind"); | 
|  |  | 
|  | // If this attribute has already been handled, it does not need to be | 
|  | // handled again. | 
|  | if (Seen.find(AN) != Seen.end()) { | 
|  | if (Dupes) | 
|  | Dupes->push_back(std::make_pair(AN, Attr)); | 
|  | continue; | 
|  | } | 
|  | Seen.insert(AN); | 
|  | } else | 
|  | AN = NormalizeAttrName(Attr->getName()).str(); | 
|  |  | 
|  | R.push_back(std::make_pair(AN, Attr)); | 
|  | } | 
|  | } | 
|  | return R; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class Argument { | 
|  | std::string lowerName, upperName; | 
|  | StringRef attrName; | 
|  | bool isOpt; | 
|  | bool Fake; | 
|  |  | 
|  | public: | 
|  | Argument(const Record &Arg, StringRef Attr) | 
|  | : lowerName(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]); | 
|  | } | 
|  | // Work around MinGW's macro definition of 'interface' to 'struct'. We | 
|  | // have an attribute argument called 'Interface', so only the lower case | 
|  | // name conflicts with the macro definition. | 
|  | if (lowerName == "interface") | 
|  | lowerName = "interface_"; | 
|  | } | 
|  | virtual ~Argument() = default; | 
|  |  | 
|  | StringRef getLowerName() const { return lowerName; } | 
|  | StringRef getUpperName() const { return upperName; } | 
|  | StringRef getAttrName() const { return attrName; } | 
|  |  | 
|  | bool isOptional() const { return isOpt; } | 
|  | void setOptional(bool set) { isOpt = set; } | 
|  |  | 
|  | bool isFake() const { return Fake; } | 
|  | void setFake(bool fake) { Fake = fake; } | 
|  |  | 
|  | // These functions print the argument contents formatted in different ways. | 
|  | virtual void writeAccessors(raw_ostream &OS) const = 0; | 
|  | virtual void writeAccessorDefinitions(raw_ostream &OS) const {} | 
|  | virtual void writeASTVisitorTraversal(raw_ostream &OS) const {} | 
|  | virtual void writeCloneArgs(raw_ostream &OS) const = 0; | 
|  | virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; | 
|  | virtual void writeTemplateInstantiation(raw_ostream &OS) const {} | 
|  | virtual void writeCtorBody(raw_ostream &OS) const {} | 
|  | virtual void writeCtorInitializers(raw_ostream &OS) const = 0; | 
|  | virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0; | 
|  | virtual void writeCtorParameters(raw_ostream &OS) const = 0; | 
|  | virtual void writeDeclarations(raw_ostream &OS) const = 0; | 
|  | virtual void writePCHReadArgs(raw_ostream &OS) const = 0; | 
|  | virtual void writePCHReadDecls(raw_ostream &OS) const = 0; | 
|  | virtual void writePCHWrite(raw_ostream &OS) const = 0; | 
|  | virtual std::string getIsOmitted() const { return "false"; } | 
|  | virtual void writeValue(raw_ostream &OS) const = 0; | 
|  | virtual void writeDump(raw_ostream &OS) const = 0; | 
|  | virtual void writeDumpChildren(raw_ostream &OS) const {} | 
|  | virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; } | 
|  |  | 
|  | virtual bool isEnumArg() const { return false; } | 
|  | virtual bool isVariadicEnumArg() const { return false; } | 
|  | virtual bool isVariadic() const { return false; } | 
|  |  | 
|  | virtual void writeImplicitCtorArgs(raw_ostream &OS) const { | 
|  | OS << getUpperName(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class SimpleArgument : public Argument { | 
|  | std::string type; | 
|  |  | 
|  | public: | 
|  | SimpleArgument(const Record &Arg, StringRef Attr, std::string T) | 
|  | : Argument(Arg, Attr), type(std::move(T)) {} | 
|  |  | 
|  | std::string getType() const { return type; } | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  " << type << " get" << getUpperName() << "() const {\n"; | 
|  | OS << "    return " << getLowerName() << ";\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "A->get" << getUpperName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "(" << getUpperName() << ")"; | 
|  | } | 
|  |  | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << type << " " << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | OS << type << " " << getLowerName() << ";"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | std::string read = ReadPCHRecord(type); | 
|  | OS << "    " << type << " " << getLowerName() << " = " << read << ";\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    " << WritePCHRecord(type, "SA->get" + | 
|  | std::string(getUpperName()) + "()"); | 
|  | } | 
|  |  | 
|  | std::string getIsOmitted() const override { | 
|  | if (type == "IdentifierInfo *") | 
|  | return "!get" + getUpperName().str() + "()"; | 
|  | if (type == "ParamIdx") | 
|  | return "!get" + getUpperName().str() + "().isValid()"; | 
|  | return "false"; | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | if (type == "FunctionDecl *") | 
|  | OS << "\" << get" << getUpperName() | 
|  | << "()->getNameInfo().getAsString() << \""; | 
|  | else if (type == "IdentifierInfo *") | 
|  | // Some non-optional (comma required) identifier arguments can be the | 
|  | // empty string but are then recorded as a nullptr. | 
|  | OS << "\" << (get" << getUpperName() << "() ? get" << getUpperName() | 
|  | << "()->getName() : \"\") << \""; | 
|  | else if (type == "TypeSourceInfo *") | 
|  | OS << "\" << get" << getUpperName() << "().getAsString() << \""; | 
|  | else if (type == "ParamIdx") | 
|  | OS << "\" << get" << getUpperName() << "().getSourceIndex() << \""; | 
|  | else | 
|  | OS << "\" << get" << getUpperName() << "() << \""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | if (type == "FunctionDecl *" || type == "NamedDecl *") { | 
|  | OS << "    OS << \" \";\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. | 
|  | OS << "    if (SA->get" << getUpperName() << "())\n" | 
|  | << "      OS << \" \" << SA->get" << getUpperName() | 
|  | << "()->getName();\n"; | 
|  | } else if (type == "TypeSourceInfo *") { | 
|  | OS << "    OS << \" \" << SA->get" << getUpperName() | 
|  | << "().getAsString();\n"; | 
|  | } else if (type == "bool") { | 
|  | OS << "    if (SA->get" << getUpperName() << "()) OS << \" " | 
|  | << getUpperName() << "\";\n"; | 
|  | } else if (type == "int" || type == "unsigned") { | 
|  | OS << "    OS << \" \" << SA->get" << getUpperName() << "();\n"; | 
|  | } else if (type == "ParamIdx") { | 
|  | if (isOptional()) | 
|  | OS << "    if (SA->get" << getUpperName() << "().isValid())\n  "; | 
|  | OS << "    OS << \" \" << SA->get" << getUpperName() | 
|  | << "().getSourceIndex();\n"; | 
|  | } else { | 
|  | llvm_unreachable("Unknown SimpleArgument type!"); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | class DefaultSimpleArgument : public SimpleArgument { | 
|  | int64_t Default; | 
|  |  | 
|  | public: | 
|  | DefaultSimpleArgument(const Record &Arg, StringRef Attr, | 
|  | std::string T, int64_t Default) | 
|  | : SimpleArgument(Arg, Attr, T), Default(Default) {} | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | SimpleArgument::writeAccessors(OS); | 
|  |  | 
|  | OS << "\n\n  static const " << getType() << " Default" << getUpperName() | 
|  | << " = "; | 
|  | if (getType() == "bool") | 
|  | OS << (Default != 0 ? "true" : "false"); | 
|  | else | 
|  | OS << Default; | 
|  | OS << ";"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class StringArgument : public Argument { | 
|  | public: | 
|  | StringArgument(const Record &Arg, StringRef Attr) | 
|  | : Argument(Arg, Attr) | 
|  | {} | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  llvm::StringRef get" << getUpperName() << "() const {\n"; | 
|  | OS << "    return llvm::StringRef(" << getLowerName() << ", " | 
|  | << getLowerName() << "Length);\n"; | 
|  | OS << "  }\n"; | 
|  | OS << "  unsigned get" << getUpperName() << "Length() const {\n"; | 
|  | OS << "    return " << getLowerName() << "Length;\n"; | 
|  | OS << "  }\n"; | 
|  | OS << "  void set" << getUpperName() | 
|  | << "(ASTContext &C, llvm::StringRef S) {\n"; | 
|  | OS << "    " << getLowerName() << "Length = S.size();\n"; | 
|  | OS << "    this->" << getLowerName() << " = new (C, 1) char [" | 
|  | << getLowerName() << "Length];\n"; | 
|  | OS << "    if (!S.empty())\n"; | 
|  | OS << "      std::memcpy(this->" << getLowerName() << ", S.data(), " | 
|  | << getLowerName() << "Length);\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << "get" << getUpperName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "A->get" << getUpperName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeCtorBody(raw_ostream &OS) const override { | 
|  | OS << "      if (!" << getUpperName() << ".empty())\n"; | 
|  | OS << "        std::memcpy(" << getLowerName() << ", " << getUpperName() | 
|  | << ".data(), " << getLowerName() << "Length);\n"; | 
|  | } | 
|  |  | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "Length(" << getUpperName() << ".size())," | 
|  | << getLowerName() << "(new (Ctx, 1) char[" << getLowerName() | 
|  | << "Length])"; | 
|  | } | 
|  |  | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "Length(0)," << getLowerName() << "(nullptr)"; | 
|  | } | 
|  |  | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << "llvm::StringRef " << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | OS << "unsigned " << getLowerName() << "Length;\n"; | 
|  | OS << "char *" << getLowerName() << ";"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    std::string " << getLowerName() | 
|  | << "= Record.readString();\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    Record.AddString(SA->get" << getUpperName() << "());\n"; | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | OS << "    OS << \" \\\"\" << SA->get" << getUpperName() | 
|  | << "() << \"\\\"\";\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class AlignedArgument : public Argument { | 
|  | public: | 
|  | AlignedArgument(const Record &Arg, StringRef Attr) | 
|  | : Argument(Arg, Attr) | 
|  | {} | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  bool is" << getUpperName() << "Dependent() const;\n"; | 
|  |  | 
|  | OS << "  unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n"; | 
|  |  | 
|  | OS << "  bool is" << getUpperName() << "Expr() const {\n"; | 
|  | OS << "    return is" << getLowerName() << "Expr;\n"; | 
|  | OS << "  }\n"; | 
|  |  | 
|  | OS << "  Expr *get" << getUpperName() << "Expr() const {\n"; | 
|  | OS << "    assert(is" << getLowerName() << "Expr);\n"; | 
|  | OS << "    return " << getLowerName() << "Expr;\n"; | 
|  | OS << "  }\n"; | 
|  |  | 
|  | OS << "  TypeSourceInfo *get" << getUpperName() << "Type() const {\n"; | 
|  | OS << "    assert(!is" << getLowerName() << "Expr);\n"; | 
|  | OS << "    return " << getLowerName() << "Type;\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeAccessorDefinitions(raw_ostream &OS) const override { | 
|  | OS << "bool " << getAttrName() << "Attr::is" << getUpperName() | 
|  | << "Dependent() const {\n"; | 
|  | OS << "  if (is" << getLowerName() << "Expr)\n"; | 
|  | OS << "    return " << getLowerName() << "Expr && (" << getLowerName() | 
|  | << "Expr->isValueDependent() || " << getLowerName() | 
|  | << "Expr->isTypeDependent());\n"; | 
|  | OS << "  else\n"; | 
|  | OS << "    return " << getLowerName() | 
|  | << "Type->getType()->isDependentType();\n"; | 
|  | OS << "}\n"; | 
|  |  | 
|  | // FIXME: Do not do the calculation here | 
|  | // FIXME: Handle types correctly | 
|  | // A null pointer means maximum alignment | 
|  | 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()" | 
|  | << " * Ctx.getCharWidth() : " | 
|  | << "Ctx.getTargetDefaultAlignForAttributeAligned();\n"; | 
|  | OS << "  else\n"; | 
|  | OS << "    return 0; // FIXME\n"; | 
|  | OS << "}\n"; | 
|  | } | 
|  |  | 
|  | 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" | 
|  | << "  } else if (auto *TSI = A->get" << Name << "Type()) {\n" | 
|  | << "    if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" | 
|  | << "      return false;\n" | 
|  | << "  }\n"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << "is" << getLowerName() << "Expr, is" << getLowerName() | 
|  | << "Expr ? static_cast<void*>(" << getLowerName() | 
|  | << "Expr) : " << getLowerName() | 
|  | << "Type"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | // FIXME: move the definition in Sema::InstantiateAttrs to here. | 
|  | // In the meantime, aligned attributes are cloned. | 
|  | } | 
|  |  | 
|  | void writeCtorBody(raw_ostream &OS) const override { | 
|  | OS << "    if (is" << getLowerName() << "Expr)\n"; | 
|  | OS << "       " << getLowerName() << "Expr = reinterpret_cast<Expr *>(" | 
|  | << getUpperName() << ");\n"; | 
|  | OS << "    else\n"; | 
|  | OS << "       " << getLowerName() | 
|  | << "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName() | 
|  | << ");\n"; | 
|  | } | 
|  |  | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)"; | 
|  | } | 
|  |  | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << "is" << getLowerName() << "Expr(false)"; | 
|  | } | 
|  |  | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeImplicitCtorArgs(raw_ostream &OS) const override { | 
|  | OS << "Is" << getUpperName() << "Expr, " << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | OS << "bool is" << getLowerName() << "Expr;\n"; | 
|  | OS << "union {\n"; | 
|  | OS << "Expr *" << getLowerName() << "Expr;\n"; | 
|  | OS << "TypeSourceInfo *" << getLowerName() << "Type;\n"; | 
|  | OS << "};"; | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    bool is" << getLowerName() << "Expr = Record.readInt();\n"; | 
|  | OS << "    void *" << getLowerName() << "Ptr;\n"; | 
|  | OS << "    if (is" << getLowerName() << "Expr)\n"; | 
|  | OS << "      " << getLowerName() << "Ptr = Record.readExpr();\n"; | 
|  | OS << "    else\n"; | 
|  | OS << "      " << getLowerName() | 
|  | << "Ptr = Record.getTypeSourceInfo();\n"; | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    Record.push_back(SA->is" << getUpperName() << "Expr());\n"; | 
|  | OS << "    if (SA->is" << getUpperName() << "Expr())\n"; | 
|  | OS << "      Record.AddStmt(SA->get" << getUpperName() << "Expr());\n"; | 
|  | OS << "    else\n"; | 
|  | OS << "      Record.AddTypeSourceInfo(SA->get" << getUpperName() | 
|  | << "Type());\n"; | 
|  | } | 
|  |  | 
|  | std::string getIsOmitted() const override { | 
|  | return "!is" + getLowerName().str() + "Expr || !" + getLowerName().str() | 
|  | + "Expr"; | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | OS << "\";\n"; | 
|  | OS << "    " << getLowerName() | 
|  | << "Expr->printPretty(OS, nullptr, Policy);\n"; | 
|  | OS << "    OS << \""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override {} | 
|  |  | 
|  | 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 { | 
|  | OS << "SA->is" << getUpperName() << "Expr()"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class VariadicArgument : public Argument { | 
|  | std::string Type, ArgName, ArgSizeName, RangeName; | 
|  |  | 
|  | protected: | 
|  | // Assumed to receive a parameter: raw_ostream OS. | 
|  | virtual void writeValueImpl(raw_ostream &OS) const { | 
|  | OS << "    OS << Val;\n"; | 
|  | } | 
|  | // Assumed to receive a parameter: raw_ostream OS. | 
|  | virtual void writeDumpImpl(raw_ostream &OS) const { | 
|  | OS << "      OS << \" \" << Val;\n"; | 
|  | } | 
|  |  | 
|  | public: | 
|  | VariadicArgument(const Record &Arg, StringRef Attr, std::string T) | 
|  | : Argument(Arg, Attr), Type(std::move(T)), | 
|  | ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"), | 
|  | RangeName(getLowerName()) {} | 
|  |  | 
|  | const std::string &getType() const { return Type; } | 
|  | const std::string &getArgName() const { return ArgName; } | 
|  | const std::string &getArgSizeName() const { return ArgSizeName; } | 
|  | bool isVariadic() const override { return true; } | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | 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"; | 
|  | OS << "  " << IteratorType << " " << EndFn << " const {" | 
|  | << " return " << ArgName << " + " << ArgSizeName << "; }\n"; | 
|  | OS << "  unsigned " << getLowerName() << "_size() const {" | 
|  | << " return " << ArgSizeName << "; }\n"; | 
|  | OS << "  llvm::iterator_range<" << IteratorType << "> " << RangeName | 
|  | << "() const { return llvm::make_range(" << BeginFn << ", " << EndFn | 
|  | << "); }\n"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << ArgName << ", " << ArgSizeName; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | // This isn't elegant, but we have to go through public methods... | 
|  | OS << "A->" << getLowerName() << "_begin(), " | 
|  | << "A->" << getLowerName() << "_size()"; | 
|  | } | 
|  |  | 
|  | void writeASTVisitorTraversal(raw_ostream &OS) const override { | 
|  | // FIXME: Traverse the elements. | 
|  | } | 
|  |  | 
|  | void writeCtorBody(raw_ostream &OS) const override { | 
|  | OS << "    std::copy(" << getUpperName() << ", " << getUpperName() | 
|  | << " + " << ArgSizeName << ", " << ArgName << ");\n"; | 
|  | } | 
|  |  | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << ArgSizeName << "(" << getUpperName() << "Size), " | 
|  | << ArgName << "(new (Ctx, 16) " << getType() << "[" | 
|  | << ArgSizeName << "])"; | 
|  | } | 
|  |  | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << ArgSizeName << "(0), " << ArgName << "(nullptr)"; | 
|  | } | 
|  |  | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << getType() << " *" << getUpperName() << ", unsigned " | 
|  | << getUpperName() << "Size"; | 
|  | } | 
|  |  | 
|  | void writeImplicitCtorArgs(raw_ostream &OS) const override { | 
|  | OS << getUpperName() << ", " << getUpperName() << "Size"; | 
|  | } | 
|  |  | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | OS << "  unsigned " << ArgSizeName << ";\n"; | 
|  | OS << "  " << getType() << " *" << ArgName << ";"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    unsigned " << getLowerName() << "Size = Record.readInt();\n"; | 
|  | OS << "    SmallVector<" << getType() << ", 4> " | 
|  | << getLowerName() << ";\n"; | 
|  | OS << "    " << getLowerName() << ".reserve(" << getLowerName() | 
|  | << "Size);\n"; | 
|  |  | 
|  | // 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(); | 
|  | if (StorageType != getType()) { | 
|  | StorageName += "Storage"; | 
|  | OS << "    SmallVector<" << StorageType << ", 4> " | 
|  | << StorageName << ";\n"; | 
|  | OS << "    " << StorageName << ".reserve(" << getLowerName() | 
|  | << "Size);\n"; | 
|  | } | 
|  |  | 
|  | OS << "    for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n"; | 
|  | std::string read = ReadPCHRecord(Type); | 
|  | OS << "      " << StorageName << ".push_back(" << read << ");\n"; | 
|  |  | 
|  | if (StorageType != getType()) { | 
|  | OS << "    for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n"; | 
|  | OS << "      " << getLowerName() << ".push_back(" | 
|  | << StorageName << "[i]);\n"; | 
|  | } | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << ".data(), " << getLowerName() << "Size"; | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    Record.push_back(SA->" << getLowerName() << "_size());\n"; | 
|  | OS << "    for (auto &Val : SA->" << RangeName << "())\n"; | 
|  | OS << "      " << WritePCHRecord(Type, "Val"); | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | OS << "\";\n"; | 
|  | OS << "  bool isFirst = true;\n" | 
|  | << "  for (const auto &Val : " << RangeName << "()) {\n" | 
|  | << "    if (isFirst) isFirst = false;\n" | 
|  | << "    else OS << \", \";\n"; | 
|  | writeValueImpl(OS); | 
|  | OS << "  }\n"; | 
|  | OS << "  OS << \""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | OS << "    for (const auto &Val : SA->" << RangeName << "())\n"; | 
|  | writeDumpImpl(OS); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class VariadicParamIdxArgument : public VariadicArgument { | 
|  | public: | 
|  | VariadicParamIdxArgument(const Record &Arg, StringRef Attr) | 
|  | : VariadicArgument(Arg, Attr, "ParamIdx") {} | 
|  |  | 
|  | public: | 
|  | void writeValueImpl(raw_ostream &OS) const override { | 
|  | OS << "    OS << Val.getSourceIndex();\n"; | 
|  | } | 
|  |  | 
|  | void writeDumpImpl(raw_ostream &OS) const override { | 
|  | OS << "      OS << \" \" << Val.getSourceIndex();\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Unique the enums, but maintain the original declaration ordering. | 
|  | std::vector<StringRef> | 
|  | uniqueEnumsInOrder(const std::vector<StringRef> &enums) { | 
|  | std::vector<StringRef> uniques; | 
|  | SmallDenseSet<StringRef, 8> unique_set; | 
|  | for (const auto &i : enums) { | 
|  | if (unique_set.insert(i).second) | 
|  | uniques.push_back(i); | 
|  | } | 
|  | return uniques; | 
|  | } | 
|  |  | 
|  | class EnumArgument : public Argument { | 
|  | std::string type; | 
|  | std::vector<StringRef> values, enums, uniques; | 
|  |  | 
|  | 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)) | 
|  | { | 
|  | // FIXME: Emit a proper error | 
|  | assert(!uniques.empty()); | 
|  | } | 
|  |  | 
|  | bool isEnumArg() const override { return true; } | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  " << type << " get" << getUpperName() << "() const {\n"; | 
|  | OS << "    return " << getLowerName() << ";\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "A->get" << getUpperName() << "()"; | 
|  | } | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "(" << getUpperName() << ")"; | 
|  | } | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "(" << type << "(0))"; | 
|  | } | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << type << " " << getUpperName(); | 
|  | } | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | auto i = uniques.cbegin(), e = uniques.cend(); | 
|  | // The last one needs to not have a comma. | 
|  | --e; | 
|  |  | 
|  | OS << "public:\n"; | 
|  | OS << "  enum " << type << " {\n"; | 
|  | for (; i != e; ++i) | 
|  | OS << "    " << *i << ",\n"; | 
|  | OS << "    " << *e << "\n"; | 
|  | OS << "  };\n"; | 
|  | OS << "private:\n"; | 
|  | OS << "  " << type << " " << getLowerName() << ";"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    " << getAttrName() << "Attr::" << type << " " << getLowerName() | 
|  | << "(static_cast<" << getAttrName() << "Attr::" << type | 
|  | << ">(Record.readInt()));\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "Record.push_back(SA->get" << getUpperName() << "());\n"; | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | // FIXME: this isn't 100% correct -- some enum arguments require printing | 
|  | // as a string literal, while others require printing as an identifier. | 
|  | // Tablegen currently does not distinguish between the two forms. | 
|  | OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << type << "ToStr(get" | 
|  | << getUpperName() << "()) << \"\\\""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | OS << "    switch(SA->get" << getUpperName() << "()) {\n"; | 
|  | for (const auto &I : uniques) { | 
|  | OS << "    case " << getAttrName() << "Attr::" << I << ":\n"; | 
|  | OS << "      OS << \" " << I << "\";\n"; | 
|  | OS << "      break;\n"; | 
|  | } | 
|  | 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<"; | 
|  | OS << type << ">>(Val)\n"; | 
|  | for (size_t I = 0; I < enums.size(); ++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"; | 
|  |  | 
|  | // 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"; | 
|  | 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 << "    }\n" | 
|  | << "    llvm_unreachable(\"No enumerator with that value\");\n" | 
|  | << "  }\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class VariadicEnumArgument: public VariadicArgument { | 
|  | std::string type, QualifiedTypeName; | 
|  | std::vector<StringRef> values, enums, uniques; | 
|  |  | 
|  | protected: | 
|  | void writeValueImpl(raw_ostream &OS) const override { | 
|  | // FIXME: this isn't 100% correct -- some enum arguments require printing | 
|  | // as a string literal, while others require printing as an identifier. | 
|  | // Tablegen currently does not distinguish between the two forms. | 
|  | OS << "    OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" << type | 
|  | << "ToStr(Val)" << "<< \"\\\"\";\n"; | 
|  | } | 
|  |  | 
|  | 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)) | 
|  | { | 
|  | 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. | 
|  | --e; | 
|  |  | 
|  | OS << "public:\n"; | 
|  | OS << "  enum " << type << " {\n"; | 
|  | for (; i != e; ++i) | 
|  | OS << "    " << *i << ",\n"; | 
|  | OS << "    " << *e << "\n"; | 
|  | OS << "  };\n"; | 
|  | OS << "private:\n"; | 
|  |  | 
|  | VariadicArgument::writeDeclarations(OS); | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | OS << "    for (" << getAttrName() << "Attr::" << getLowerName() | 
|  | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" | 
|  | << getLowerName() << "_end(); I != E; ++I) {\n"; | 
|  | OS << "      switch(*I) {\n"; | 
|  | for (const auto &UI : uniques) { | 
|  | OS << "    case " << getAttrName() << "Attr::" << UI << ":\n"; | 
|  | OS << "      OS << \" " << UI << "\";\n"; | 
|  | OS << "      break;\n"; | 
|  | } | 
|  | OS << "      }\n"; | 
|  | OS << "    }\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    unsigned " << getLowerName() << "Size = Record.readInt();\n"; | 
|  | OS << "    SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName() | 
|  | << ";\n"; | 
|  | OS << "    " << getLowerName() << ".reserve(" << getLowerName() | 
|  | << "Size);\n"; | 
|  | OS << "    for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; | 
|  | OS << "      " << getLowerName() << ".push_back(" << "static_cast<" | 
|  | << QualifiedTypeName << ">(Record.readInt()));\n"; | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    Record.push_back(SA->" << getLowerName() << "_size());\n"; | 
|  | OS << "    for (" << getAttrName() << "Attr::" << getLowerName() | 
|  | << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" | 
|  | << getLowerName() << "_end(); i != e; ++i)\n"; | 
|  | OS << "      " << WritePCHRecord(QualifiedTypeName, "(*i)"); | 
|  | } | 
|  |  | 
|  | void writeConversion(raw_ostream &OS) const { | 
|  | OS << "  static bool ConvertStrTo" << type << "(StringRef Val, "; | 
|  | OS << 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 << 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"; | 
|  | 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 << "    }\n" | 
|  | << "    llvm_unreachable(\"No enumerator with that value\");\n" | 
|  | << "  }\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class VersionArgument : public Argument { | 
|  | public: | 
|  | VersionArgument(const Record &Arg, StringRef Attr) | 
|  | : Argument(Arg, Attr) | 
|  | {} | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  VersionTuple get" << getUpperName() << "() const {\n"; | 
|  | OS << "    return " << getLowerName() << ";\n"; | 
|  | OS << "  }\n"; | 
|  | OS << "  void set" << getUpperName() | 
|  | << "(ASTContext &C, VersionTuple V) {\n"; | 
|  | OS << "    " << getLowerName() << " = V;\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeCloneArgs(raw_ostream &OS) const override { | 
|  | OS << "get" << getUpperName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "A->get" << getUpperName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeCtorInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "(" << getUpperName() << ")"; | 
|  | } | 
|  |  | 
|  | void writeCtorDefaultInitializers(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "()"; | 
|  | } | 
|  |  | 
|  | void writeCtorParameters(raw_ostream &OS) const override { | 
|  | OS << "VersionTuple " << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeDeclarations(raw_ostream &OS) const override { | 
|  | OS << "VersionTuple " << getLowerName() << ";\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadDecls(raw_ostream &OS) const override { | 
|  | OS << "    VersionTuple " << getLowerName() | 
|  | << "= Record.readVersionTuple();\n"; | 
|  | } | 
|  |  | 
|  | void writePCHReadArgs(raw_ostream &OS) const override { | 
|  | OS << getLowerName(); | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    Record.AddVersionTuple(SA->get" << getUpperName() << "());\n"; | 
|  | } | 
|  |  | 
|  | void writeValue(raw_ostream &OS) const override { | 
|  | OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override { | 
|  | OS << "    OS << \" \" << SA->get" << getUpperName() << "();\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class ExprArgument : public SimpleArgument { | 
|  | public: | 
|  | ExprArgument(const Record &Arg, StringRef Attr) | 
|  | : SimpleArgument(Arg, Attr, "Expr *") | 
|  | {} | 
|  |  | 
|  | void writeASTVisitorTraversal(raw_ostream &OS) const override { | 
|  | OS << "  if (!" | 
|  | << "getDerived().TraverseStmt(A->get" << getUpperName() << "()))\n"; | 
|  | OS << "    return false;\n"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "tempInst" << getUpperName(); | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiation(raw_ostream &OS) const override { | 
|  | OS << "      " << getType() << " tempInst" << getUpperName() << ";\n"; | 
|  | OS << "      {\n"; | 
|  | OS << "        EnterExpressionEvaluationContext " | 
|  | << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n"; | 
|  | OS << "        ExprResult " << "Result = S.SubstExpr(" | 
|  | << "A->get" << getUpperName() << "(), TemplateArgs);\n"; | 
|  | OS << "        tempInst" << getUpperName() << " = " | 
|  | << "Result.getAs<Expr>();\n"; | 
|  | OS << "      }\n"; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override {} | 
|  |  | 
|  | void writeDumpChildren(raw_ostream &OS) const override { | 
|  | OS << "    dumpStmt(SA->get" << getUpperName() << "());\n"; | 
|  | } | 
|  |  | 
|  | void writeHasChildren(raw_ostream &OS) const override { OS << "true"; } | 
|  | }; | 
|  |  | 
|  | class VariadicExprArgument : public VariadicArgument { | 
|  | public: | 
|  | VariadicExprArgument(const Record &Arg, StringRef Attr) | 
|  | : VariadicArgument(Arg, Attr, "Expr *") | 
|  | {} | 
|  |  | 
|  | void writeASTVisitorTraversal(raw_ostream &OS) const override { | 
|  | OS << "  {\n"; | 
|  | OS << "    " << getType() << " *I = A->" << getLowerName() | 
|  | << "_begin();\n"; | 
|  | OS << "    " << getType() << " *E = A->" << getLowerName() | 
|  | << "_end();\n"; | 
|  | OS << "    for (; I != E; ++I) {\n"; | 
|  | OS << "      if (!getDerived().TraverseStmt(*I))\n"; | 
|  | OS << "        return false;\n"; | 
|  | OS << "    }\n"; | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "tempInst" << getUpperName() << ", " | 
|  | << "A->" << getLowerName() << "_size()"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiation(raw_ostream &OS) const override { | 
|  | OS << "      auto *tempInst" << getUpperName() | 
|  | << " = new (C, 16) " << getType() | 
|  | << "[A->" << getLowerName() << "_size()];\n"; | 
|  | OS << "      {\n"; | 
|  | OS << "        EnterExpressionEvaluationContext " | 
|  | << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n"; | 
|  | OS << "        " << getType() << " *TI = tempInst" << getUpperName() | 
|  | << ";\n"; | 
|  | OS << "        " << getType() << " *I = A->" << getLowerName() | 
|  | << "_begin();\n"; | 
|  | OS << "        " << getType() << " *E = A->" << getLowerName() | 
|  | << "_end();\n"; | 
|  | OS << "        for (; I != E; ++I, ++TI) {\n"; | 
|  | OS << "          ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n"; | 
|  | OS << "          *TI = Result.getAs<Expr>();\n"; | 
|  | OS << "        }\n"; | 
|  | OS << "      }\n"; | 
|  | } | 
|  |  | 
|  | void writeDump(raw_ostream &OS) const override {} | 
|  |  | 
|  | void writeDumpChildren(raw_ostream &OS) const override { | 
|  | OS << "    for (" << getAttrName() << "Attr::" << getLowerName() | 
|  | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" | 
|  | << getLowerName() << "_end(); I != E; ++I)\n"; | 
|  | OS << "      dumpStmt(*I);\n"; | 
|  | } | 
|  |  | 
|  | void writeHasChildren(raw_ostream &OS) const override { | 
|  | OS << "SA->" << getLowerName() << "_begin() != " | 
|  | << "SA->" << getLowerName() << "_end()"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class VariadicStringArgument : public VariadicArgument { | 
|  | public: | 
|  | VariadicStringArgument(const Record &Arg, StringRef Attr) | 
|  | : VariadicArgument(Arg, Attr, "StringRef") | 
|  | {} | 
|  |  | 
|  | 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"; | 
|  | } | 
|  |  | 
|  | void writeValueImpl(raw_ostream &OS) const override { | 
|  | OS << "    OS << \"\\\"\" << Val << \"\\\"\";\n"; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class TypeArgument : public SimpleArgument { | 
|  | public: | 
|  | TypeArgument(const Record &Arg, StringRef Attr) | 
|  | : SimpleArgument(Arg, Attr, "TypeSourceInfo *") | 
|  | {} | 
|  |  | 
|  | void writeAccessors(raw_ostream &OS) const override { | 
|  | OS << "  QualType get" << getUpperName() << "() const {\n"; | 
|  | OS << "    return " << getLowerName() << "->getType();\n"; | 
|  | OS << "  }"; | 
|  | OS << "  " << getType() << " get" << getUpperName() << "Loc() const {\n"; | 
|  | OS << "    return " << getLowerName() << ";\n"; | 
|  | OS << "  }"; | 
|  | } | 
|  |  | 
|  | void writeASTVisitorTraversal(raw_ostream &OS) const override { | 
|  | OS << "  if (auto *TSI = A->get" << getUpperName() << "Loc())\n"; | 
|  | OS << "    if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n"; | 
|  | OS << "      return false;\n"; | 
|  | } | 
|  |  | 
|  | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { | 
|  | OS << "A->get" << getUpperName() << "Loc()"; | 
|  | } | 
|  |  | 
|  | void writePCHWrite(raw_ostream &OS) const override { | 
|  | OS << "    " << WritePCHRecord( | 
|  | getType(), "SA->get" + std::string(getUpperName()) + "Loc()"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static std::unique_ptr<Argument> | 
|  | createArgument(const Record &Arg, StringRef Attr, | 
|  | const Record *Search = nullptr) { | 
|  | if (!Search) | 
|  | Search = &Arg; | 
|  |  | 
|  | std::unique_ptr<Argument> Ptr; | 
|  | llvm::StringRef ArgName = Search->getName(); | 
|  |  | 
|  | if (ArgName == "AlignedArgument") | 
|  | Ptr = llvm::make_unique<AlignedArgument>(Arg, Attr); | 
|  | else if (ArgName == "EnumArgument") | 
|  | Ptr = llvm::make_unique<EnumArgument>(Arg, Attr); | 
|  | else if (ArgName == "ExprArgument") | 
|  | Ptr = llvm::make_unique<ExprArgument>(Arg, Attr); | 
|  | else if (ArgName == "FunctionArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *"); | 
|  | else if (ArgName == "NamedArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *"); | 
|  | else if (ArgName == "IdentifierArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *"); | 
|  | else if (ArgName == "DefaultBoolArgument") | 
|  | Ptr = llvm::make_unique<DefaultSimpleArgument>( | 
|  | Arg, Attr, "bool", Arg.getValueAsBit("Default")); | 
|  | else if (ArgName == "BoolArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "bool"); | 
|  | else if (ArgName == "DefaultIntArgument") | 
|  | Ptr = llvm::make_unique<DefaultSimpleArgument>( | 
|  | Arg, Attr, "int", Arg.getValueAsInt("Default")); | 
|  | else if (ArgName == "IntArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "int"); | 
|  | else if (ArgName == "StringArgument") | 
|  | Ptr = llvm::make_unique<StringArgument>(Arg, Attr); | 
|  | else if (ArgName == "TypeArgument") | 
|  | Ptr = llvm::make_unique<TypeArgument>(Arg, Attr); | 
|  | else if (ArgName == "UnsignedArgument") | 
|  | 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") | 
|  | Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr); | 
|  | else if (ArgName == "VariadicParamIdxArgument") | 
|  | Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr); | 
|  | else if (ArgName == "ParamIdxArgument") | 
|  | Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx"); | 
|  | else if (ArgName == "VersionArgument") | 
|  | Ptr = llvm::make_unique<VersionArgument>(Arg, Attr); | 
|  |  | 
|  | if (!Ptr) { | 
|  | // Search in reverse order so that the most-derived type is handled first. | 
|  | ArrayRef<std::pair<Record*, SMRange>> Bases = Search->getSuperClasses(); | 
|  | for (const auto &Base : llvm::reverse(Bases)) { | 
|  | if ((Ptr = createArgument(Arg, Attr, Base.first))) | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Ptr && Arg.getValueAsBit("Optional")) | 
|  | Ptr->setOptional(true); | 
|  |  | 
|  | if (Ptr && Arg.getValueAsBit("Fake")) | 
|  | Ptr->setFake(true); | 
|  |  | 
|  | return Ptr; | 
|  | } | 
|  |  | 
|  | static void writeAvailabilityValue(raw_ostream &OS) { | 
|  | OS << "\" << getPlatform()->getName();\n" | 
|  | << "  if (getStrict()) OS << \", strict\";\n" | 
|  | << "  if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" | 
|  | << "  if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" | 
|  | << "  if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" | 
|  | << "  if (getUnavailable()) OS << \", unavailable\";\n" | 
|  | << "  OS << \""; | 
|  | } | 
|  |  | 
|  | static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) { | 
|  | OS << "\\\"\" << getMessage() << \"\\\"\";\n"; | 
|  | // Only GNU deprecated has an optional fixit argument at the second position. | 
|  | if (Variety == "GNU") | 
|  | OS << "    if (!getReplacement().empty()) OS << \", \\\"\"" | 
|  | " << getReplacement() << \"\\\"\";\n"; | 
|  | OS << "    OS << \""; | 
|  | } | 
|  |  | 
|  | static void writeGetSpellingFunction(Record &R, raw_ostream &OS) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); | 
|  |  | 
|  | OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n"; | 
|  | if (Spellings.empty()) { | 
|  | OS << "  return \"(No spelling)\";\n}\n\n"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | OS << "  switch (SpellingListIndex) {\n" | 
|  | "  default:\n" | 
|  | "    llvm_unreachable(\"Unknown attribute spelling!\");\n" | 
|  | "    return \"(No spelling)\";\n"; | 
|  |  | 
|  | for (unsigned I = 0; I < Spellings.size(); ++I) | 
|  | OS << "  case " << I << ":\n" | 
|  | "    return \"" << Spellings[I].name() << "\";\n"; | 
|  | // End of the switch statement. | 
|  | OS << "  }\n"; | 
|  | // End of the getSpelling function. | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | static void | 
|  | writePrettyPrintFunction(Record &R, | 
|  | const std::vector<std::unique_ptr<Argument>> &Args, | 
|  | raw_ostream &OS) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); | 
|  |  | 
|  | OS << "void " << R.getName() << "Attr::printPretty(" | 
|  | << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n"; | 
|  |  | 
|  | if (Spellings.empty()) { | 
|  | 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].name(); | 
|  | std::string Variety = Spellings[I].variety(); | 
|  |  | 
|  | if (Variety == "GNU") { | 
|  | Prefix = " __attribute__(("; | 
|  | Suffix = "))"; | 
|  | } else if (Variety == "CXX11" || Variety == "C2x") { | 
|  | Prefix = " [["; | 
|  | Suffix = "]]"; | 
|  | std::string Namespace = Spellings[I].nameSpace(); | 
|  | if (!Namespace.empty()) { | 
|  | Spelling += Namespace; | 
|  | Spelling += "::"; | 
|  | } | 
|  | } else if (Variety == "Declspec") { | 
|  | Prefix = " __declspec("; | 
|  | Suffix = ")"; | 
|  | } else if (Variety == "Microsoft") { | 
|  | Prefix = "["; | 
|  | Suffix = "]"; | 
|  | } else if (Variety == "Keyword") { | 
|  | Prefix = " "; | 
|  | Suffix = ""; | 
|  | } else if (Variety == "Pragma") { | 
|  | Prefix = "#pragma "; | 
|  | Suffix = "\n"; | 
|  | std::string Namespace = Spellings[I].nameSpace(); | 
|  | if (!Namespace.empty()) { | 
|  | Spelling += Namespace; | 
|  | Spelling += " "; | 
|  | } | 
|  | } else { | 
|  | llvm_unreachable("Unknown attribute syntax variety!"); | 
|  | } | 
|  |  | 
|  | Spelling += Name; | 
|  |  | 
|  | OS << | 
|  | "  case " << I << " : {\n" | 
|  | "    OS << \"" << Prefix << Spelling; | 
|  |  | 
|  | if (Variety == "Pragma") { | 
|  | OS << "\";\n"; | 
|  | OS << "    printPrettyPragma(OS, Policy);\n"; | 
|  | OS << "    OS << \"\\n\";"; | 
|  | OS << "    break;\n"; | 
|  | OS << "  }\n"; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (Spelling == "availability") { | 
|  | OS << "("; | 
|  | writeAvailabilityValue(OS); | 
|  | OS << ")"; | 
|  | } else if (Spelling == "deprecated" || Spelling == "gnu::deprecated") { | 
|  | OS << "("; | 
|  | writeDeprecatedAttrValue(OS, Variety); | 
|  | OS << ")"; | 
|  | } else { | 
|  | // To avoid printing parentheses around an empty argument list or | 
|  | // printing spurious commas at the end of an argument list, we need to | 
|  | // determine where the last provided non-fake argument is. | 
|  | unsigned NonFakeArgs = 0; | 
|  | unsigned TrailingOptArgs = 0; | 
|  | bool FoundNonOptArg = false; | 
|  | for (const auto &arg : llvm::reverse(Args)) { | 
|  | if (arg->isFake()) | 
|  | continue; | 
|  | ++NonFakeArgs; | 
|  | if (FoundNonOptArg) | 
|  | continue; | 
|  | // FIXME: arg->getIsOmitted() == "false" means we haven't implemented | 
|  | // any way to detect whether the argument was omitted. | 
|  | if (!arg->isOptional() || arg->getIsOmitted() == "false") { | 
|  | FoundNonOptArg = true; | 
|  | continue; | 
|  | } | 
|  | if (!TrailingOptArgs++) | 
|  | OS << "\";\n" | 
|  | << "    unsigned TrailingOmittedArgs = 0;\n"; | 
|  | OS << "    if (" << arg->getIsOmitted() << ")\n" | 
|  | << "      ++TrailingOmittedArgs;\n"; | 
|  | } | 
|  | if (TrailingOptArgs) | 
|  | OS << "    OS << \""; | 
|  | if (TrailingOptArgs < NonFakeArgs) | 
|  | OS << "("; | 
|  | else if (TrailingOptArgs) | 
|  | OS << "\";\n" | 
|  | << "    if (TrailingOmittedArgs < " << NonFakeArgs << ")\n" | 
|  | << "       OS << \"(\";\n" | 
|  | << "    OS << \""; | 
|  | unsigned ArgIndex = 0; | 
|  | for (const auto &arg : Args) { | 
|  | if (arg->isFake()) | 
|  | continue; | 
|  | if (ArgIndex) { | 
|  | if (ArgIndex >= NonFakeArgs - TrailingOptArgs) | 
|  | OS << "\";\n" | 
|  | << "    if (" << ArgIndex << " < " << NonFakeArgs | 
|  | << " - TrailingOmittedArgs)\n" | 
|  | << "      OS << \", \";\n" | 
|  | << "    OS << \""; | 
|  | else | 
|  | OS << ", "; | 
|  | } | 
|  | std::string IsOmitted = arg->getIsOmitted(); | 
|  | if (arg->isOptional() && IsOmitted != "false") | 
|  | OS << "\";\n" | 
|  | << "    if (!(" << IsOmitted << ")) {\n" | 
|  | << "      OS << \""; | 
|  | arg->writeValue(OS); | 
|  | if (arg->isOptional() && IsOmitted != "false") | 
|  | OS << "\";\n" | 
|  | << "    }\n" | 
|  | << "    OS << \""; | 
|  | ++ArgIndex; | 
|  | } | 
|  | if (TrailingOptArgs < NonFakeArgs) | 
|  | OS << ")"; | 
|  | else if (TrailingOptArgs) | 
|  | OS << "\";\n" | 
|  | << "    if (TrailingOmittedArgs < " << NonFakeArgs << ")\n" | 
|  | << "       OS << \")\";\n" | 
|  | << "    OS << \""; | 
|  | } | 
|  |  | 
|  | OS << Suffix + "\";\n"; | 
|  |  | 
|  | OS << | 
|  | "    break;\n" | 
|  | "  }\n"; | 
|  | } | 
|  |  | 
|  | // End of the switch statement. | 
|  | OS << "}\n"; | 
|  | // End of the print function. | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | /// \brief Return the index of a spelling in a spelling list. | 
|  | static unsigned | 
|  | getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList, | 
|  | const FlattenedSpelling &Spelling) { | 
|  | assert(!SpellingList.empty() && "Spelling list is empty!"); | 
|  |  | 
|  | for (unsigned Index = 0; Index < SpellingList.size(); ++Index) { | 
|  | const FlattenedSpelling &S = SpellingList[Index]; | 
|  | if (S.variety() != Spelling.variety()) | 
|  | continue; | 
|  | if (S.nameSpace() != Spelling.nameSpace()) | 
|  | continue; | 
|  | if (S.name() != Spelling.name()) | 
|  | continue; | 
|  |  | 
|  | return Index; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unknown spelling!"); | 
|  | } | 
|  |  | 
|  | static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { | 
|  | std::vector<Record*> Accessors = R.getValueAsListOfDefs("Accessors"); | 
|  | if (Accessors.empty()) | 
|  | return; | 
|  |  | 
|  | const std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(R); | 
|  | assert(!SpellingList.empty() && | 
|  | "Attribute with empty spelling list can't have accessors!"); | 
|  | for (const auto *Accessor : Accessors) { | 
|  | const StringRef Name = Accessor->getValueAsString("Name"); | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor); | 
|  |  | 
|  | OS << "  bool " << Name << "() const { return SpellingListIndex == "; | 
|  | for (unsigned Index = 0; Index < Spellings.size(); ++Index) { | 
|  | OS << getSpellingListIndex(SpellingList, Spellings[Index]); | 
|  | if (Index != Spellings.size() - 1) | 
|  | OS << " ||\n    SpellingListIndex == "; | 
|  | else | 
|  | OS << "; }\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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()); | 
|  | for (const auto &Spelling : | 
|  | llvm::make_range(std::next(Spellings.begin()), Spellings.end())) { | 
|  | std::string Name = NormalizeNameForSpellingComparison(Spelling.name()); | 
|  | if (Name != FirstName) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | typedef std::map<unsigned, std::string> SemanticSpellingMap; | 
|  | static std::string | 
|  | CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings, | 
|  | SemanticSpellingMap &Map) { | 
|  | // The enumerants are automatically generated based on the variety, | 
|  | // namespace (if present) and name for each attribute spelling. However, | 
|  | // care is taken to avoid trampling on the reserved namespace due to | 
|  | // underscores. | 
|  | std::string Ret("  enum Spelling {\n"); | 
|  | std::set<std::string> Uniques; | 
|  | unsigned Idx = 0; | 
|  | for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) { | 
|  | const FlattenedSpelling &S = *I; | 
|  | const std::string &Variety = S.variety(); | 
|  | const std::string &Spelling = S.name(); | 
|  | const std::string &Namespace = S.nameSpace(); | 
|  | std::string EnumName; | 
|  |  | 
|  | EnumName += (Variety + "_"); | 
|  | if (!Namespace.empty()) | 
|  | EnumName += (NormalizeNameForSpellingComparison(Namespace).str() + | 
|  | "_"); | 
|  | EnumName += NormalizeNameForSpellingComparison(Spelling); | 
|  |  | 
|  | // Even if the name is not unique, this spelling index corresponds to a | 
|  | // particular enumerant name that we've calculated. | 
|  | Map[Idx] = EnumName; | 
|  |  | 
|  | // Since we have been stripping underscores to avoid trampling on the | 
|  | // reserved namespace, we may have inadvertently created duplicate | 
|  | // enumerant names. These duplicates are not considered part of the | 
|  | // semantic spelling, and can be elided. | 
|  | if (Uniques.find(EnumName) != Uniques.end()) | 
|  | continue; | 
|  |  | 
|  | Uniques.insert(EnumName); | 
|  | if (I != Spellings.begin()) | 
|  | Ret += ",\n"; | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | void WriteSemanticSpellingSwitch(const std::string &VarName, | 
|  | const SemanticSpellingMap &Map, | 
|  | raw_ostream &OS) { | 
|  | OS << "  switch (" << VarName << ") {\n    default: " | 
|  | << "llvm_unreachable(\"Unknown spelling list index\");\n"; | 
|  | for (const auto &I : Map) | 
|  | OS << "    case " << I.first << ": return " << I.second << ";\n"; | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | // Emits the LateParsed property for attributes. | 
|  | static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | for (const auto *Attr : Attrs) { | 
|  | bool LateParsed = Attr->getValueAsBit("LateParsed"); | 
|  |  | 
|  | if (LateParsed) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr); | 
|  |  | 
|  | // FIXME: Handle non-GNU attributes | 
|  | for (const auto &I : Spellings) { | 
|  | if (I.variety() != "GNU") | 
|  | continue; | 
|  | OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  | OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; | 
|  | } | 
|  |  | 
|  | static bool hasGNUorCXX11Spelling(const Record &Attribute) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); | 
|  | for (const auto &I : Spellings) { | 
|  | if (I.variety() == "GNU" || I.variety() == "CXX11") | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct AttributeSubjectMatchRule { | 
|  | const Record *MetaSubject; | 
|  | const Record *Constraint; | 
|  |  | 
|  | AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint) | 
|  | : MetaSubject(MetaSubject), Constraint(Constraint) { | 
|  | assert(MetaSubject && "Missing subject"); | 
|  | } | 
|  |  | 
|  | bool isSubRule() const { return Constraint != nullptr; } | 
|  |  | 
|  | std::vector<Record *> getSubjects() const { | 
|  | return (Constraint ? Constraint : MetaSubject) | 
|  | ->getValueAsListOfDefs("Subjects"); | 
|  | } | 
|  |  | 
|  | std::vector<Record *> getLangOpts() const { | 
|  | if (Constraint) { | 
|  | // Lookup the options in the sub-rule first, in case the sub-rule | 
|  | // overrides the rules options. | 
|  | std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts"); | 
|  | if (!Opts.empty()) | 
|  | return Opts; | 
|  | } | 
|  | return MetaSubject->getValueAsListOfDefs("LangOpts"); | 
|  | } | 
|  |  | 
|  | // Abstract rules are used only for sub-rules | 
|  | bool isAbstractRule() const { return getSubjects().empty(); } | 
|  |  | 
|  | StringRef getName() const { | 
|  | return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name"); | 
|  | } | 
|  |  | 
|  | bool isNegatedSubRule() const { | 
|  | assert(isSubRule() && "Not a sub-rule"); | 
|  | return Constraint->getValueAsBit("Negated"); | 
|  | } | 
|  |  | 
|  | std::string getSpelling() const { | 
|  | std::string Result = MetaSubject->getValueAsString("Name"); | 
|  | if (isSubRule()) { | 
|  | Result += '('; | 
|  | if (isNegatedSubRule()) | 
|  | Result += "unless("; | 
|  | Result += getName(); | 
|  | if (isNegatedSubRule()) | 
|  | Result += ')'; | 
|  | Result += ')'; | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string getEnumValueName() const { | 
|  | SmallString<128> Result; | 
|  | Result += "SubjectMatchRule_"; | 
|  | Result += MetaSubject->getValueAsString("Name"); | 
|  | if (isSubRule()) { | 
|  | Result += "_"; | 
|  | if (isNegatedSubRule()) | 
|  | Result += "not_"; | 
|  | Result += Constraint->getValueAsString("Name"); | 
|  | } | 
|  | if (isAbstractRule()) | 
|  | Result += "_abstract"; | 
|  | return Result.str(); | 
|  | } | 
|  |  | 
|  | std::string getEnumValue() const { return "attr::" + getEnumValueName(); } | 
|  |  | 
|  | static const char *EnumName; | 
|  | }; | 
|  |  | 
|  | const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule"; | 
|  |  | 
|  | struct PragmaClangAttributeSupport { | 
|  | std::vector<AttributeSubjectMatchRule> Rules; | 
|  |  | 
|  | class RuleOrAggregateRuleSet { | 
|  | std::vector<AttributeSubjectMatchRule> Rules; | 
|  | bool IsRule; | 
|  | RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules, | 
|  | bool IsRule) | 
|  | : Rules(Rules), IsRule(IsRule) {} | 
|  |  | 
|  | public: | 
|  | bool isRule() const { return IsRule; } | 
|  |  | 
|  | const AttributeSubjectMatchRule &getRule() const { | 
|  | assert(IsRule && "not a rule!"); | 
|  | return Rules[0]; | 
|  | } | 
|  |  | 
|  | ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const { | 
|  | return Rules; | 
|  | } | 
|  |  | 
|  | static RuleOrAggregateRuleSet | 
|  | getRule(const AttributeSubjectMatchRule &Rule) { | 
|  | return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true); | 
|  | } | 
|  | static RuleOrAggregateRuleSet | 
|  | getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) { | 
|  | return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false); | 
|  | } | 
|  | }; | 
|  | llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules; | 
|  |  | 
|  | PragmaClangAttributeSupport(RecordKeeper &Records); | 
|  |  | 
|  | bool isAttributedSupported(const Record &Attribute); | 
|  |  | 
|  | void emitMatchRuleList(raw_ostream &OS); | 
|  |  | 
|  | std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS); | 
|  |  | 
|  | void generateParsingHelpers(raw_ostream &OS); | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static bool doesDeclDeriveFrom(const Record *D, const Record *Base) { | 
|  | const Record *CurrentBase = D->getValueAsDef("Base"); | 
|  | if (!CurrentBase) | 
|  | return false; | 
|  | if (CurrentBase == Base) | 
|  | return true; | 
|  | return doesDeclDeriveFrom(CurrentBase, Base); | 
|  | } | 
|  |  | 
|  | PragmaClangAttributeSupport::PragmaClangAttributeSupport( | 
|  | RecordKeeper &Records) { | 
|  | std::vector<Record *> MetaSubjects = | 
|  | Records.getAllDerivedDefinitions("AttrSubjectMatcherRule"); | 
|  | auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, | 
|  | const Record *MetaSubject, | 
|  | const Record *Constraint) { | 
|  | Rules.emplace_back(MetaSubject, Constraint); | 
|  | std::vector<Record *> ApplicableSubjects = | 
|  | SubjectContainer->getValueAsListOfDefs("Subjects"); | 
|  | for (const auto *Subject : ApplicableSubjects) { | 
|  | bool Inserted = | 
|  | SubjectsToRules | 
|  | .try_emplace(Subject, RuleOrAggregateRuleSet::getRule( | 
|  | AttributeSubjectMatchRule(MetaSubject, | 
|  | Constraint))) | 
|  | .second; | 
|  | if (!Inserted) { | 
|  | PrintFatalError("Attribute subject match rules should not represent" | 
|  | "same attribute subjects."); | 
|  | } | 
|  | } | 
|  | }; | 
|  | for (const auto *MetaSubject : MetaSubjects) { | 
|  | MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr); | 
|  | std::vector<Record *> Constraints = | 
|  | MetaSubject->getValueAsListOfDefs("Constraints"); | 
|  | for (const auto *Constraint : Constraints) | 
|  | MapFromSubjectsToRules(Constraint, MetaSubject, Constraint); | 
|  | } | 
|  |  | 
|  | std::vector<Record *> Aggregates = | 
|  | Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule"); | 
|  | std::vector<Record *> DeclNodes = Records.getAllDerivedDefinitions("DDecl"); | 
|  | for (const auto *Aggregate : Aggregates) { | 
|  | Record *SubjectDecl = Aggregate->getValueAsDef("Subject"); | 
|  |  | 
|  | // Gather sub-classes of the aggregate subject that act as attribute | 
|  | // subject rules. | 
|  | std::vector<AttributeSubjectMatchRule> Rules; | 
|  | for (const auto *D : DeclNodes) { | 
|  | if (doesDeclDeriveFrom(D, SubjectDecl)) { | 
|  | auto It = SubjectsToRules.find(D); | 
|  | if (It == SubjectsToRules.end()) | 
|  | continue; | 
|  | if (!It->second.isRule() || It->second.getRule().isSubRule()) | 
|  | continue; // Assume that the rule will be included as well. | 
|  | Rules.push_back(It->second.getRule()); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Inserted = | 
|  | SubjectsToRules | 
|  | .try_emplace(SubjectDecl, | 
|  | RuleOrAggregateRuleSet::getAggregateRuleSet(Rules)) | 
|  | .second; | 
|  | if (!Inserted) { | 
|  | PrintFatalError("Attribute subject match rules should not represent" | 
|  | "same attribute subjects."); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static PragmaClangAttributeSupport & | 
|  | getPragmaAttributeSupport(RecordKeeper &Records) { | 
|  | static PragmaClangAttributeSupport Instance(Records); | 
|  | return Instance; | 
|  | } | 
|  |  | 
|  | void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) { | 
|  | OS << "#ifndef ATTR_MATCH_SUB_RULE\n"; | 
|  | OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, " | 
|  | "IsNegated) " | 
|  | << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n"; | 
|  | OS << "#endif\n"; | 
|  | for (const auto &Rule : Rules) { | 
|  | OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '('; | 
|  | OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", " | 
|  | << Rule.isAbstractRule(); | 
|  | if (Rule.isSubRule()) | 
|  | OS << ", " | 
|  | << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue() | 
|  | << ", " << Rule.isNegatedSubRule(); | 
|  | OS << ")\n"; | 
|  | } | 
|  | OS << "#undef ATTR_MATCH_SUB_RULE\n"; | 
|  | } | 
|  |  | 
|  | bool PragmaClangAttributeSupport::isAttributedSupported( | 
|  | const Record &Attribute) { | 
|  | if (Attribute.getValueAsBit("ForcePragmaAttributeSupport")) | 
|  | return true; | 
|  | // 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; | 
|  | // An attribute has no GNU/CXX11 spelling | 
|  | if (!hasGNUorCXX11Spelling(Attribute)) | 
|  | return false; | 
|  | // An attribute subject list has a subject that isn't covered by one of the | 
|  | // subject match rules or has no subjects at all. | 
|  | if (Attribute.isValueUnset("Subjects")) | 
|  | return false; | 
|  | const Record *SubjectObj = Attribute.getValueAsDef("Subjects"); | 
|  | std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); | 
|  | if (Subjects.empty()) | 
|  | return false; | 
|  | for (const auto *Subject : Subjects) { | 
|  | if (SubjectsToRules.find(Subject) == SubjectsToRules.end()) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::string | 
|  | PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, | 
|  | raw_ostream &OS) { | 
|  | if (!isAttributedSupported(Attr)) | 
|  | return "nullptr"; | 
|  | // 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<" | 
|  | << AttributeSubjectMatchRule::EnumName | 
|  | << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n"; | 
|  | if (Attr.isValueUnset("Subjects")) { | 
|  | OS << "}\n\n"; | 
|  | return FnName; | 
|  | } | 
|  | const Record *SubjectObj = Attr.getValueAsDef("Subjects"); | 
|  | std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); | 
|  | for (const auto *Subject : Subjects) { | 
|  | auto It = SubjectsToRules.find(Subject); | 
|  | assert(It != SubjectsToRules.end() && | 
|  | "This attribute is unsupported by #pragma clang attribute"); | 
|  | for (const auto &Rule : It->getSecond().getAggregateRuleSet()) { | 
|  | // The rule might be language specific, so only subtract it from the given | 
|  | // rules if the specific language options are specified. | 
|  | std::vector<Record *> LangOpts = Rule.getLangOpts(); | 
|  | OS << "  MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() | 
|  | << ", /*IsSupported=*/"; | 
|  | if (!LangOpts.empty()) { | 
|  | for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { | 
|  | const StringRef Part = (*I)->getValueAsString("Name"); | 
|  | if ((*I)->getValueAsBit("Negated")) | 
|  | OS << "!"; | 
|  | OS << "LangOpts." << Part; | 
|  | if (I + 1 != E) | 
|  | OS << " || "; | 
|  | } | 
|  | } else | 
|  | OS << "true"; | 
|  | OS << "));\n"; | 
|  | } | 
|  | } | 
|  | OS << "}\n\n"; | 
|  | return FnName; | 
|  | } | 
|  |  | 
|  | void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { | 
|  | // Generate routines that check the names of sub-rules. | 
|  | OS << "Optional<attr::SubjectMatchRule> " | 
|  | "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n"; | 
|  | OS << "  return None;\n"; | 
|  | OS << "}\n\n"; | 
|  |  | 
|  | std::map<const Record *, std::vector<AttributeSubjectMatchRule>> | 
|  | SubMatchRules; | 
|  | for (const auto &Rule : Rules) { | 
|  | if (!Rule.isSubRule()) | 
|  | continue; | 
|  | SubMatchRules[Rule.MetaSubject].push_back(Rule); | 
|  | } | 
|  |  | 
|  | for (const auto &SubMatchRule : SubMatchRules) { | 
|  | OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_" | 
|  | << SubMatchRule.first->getValueAsString("Name") | 
|  | << "(StringRef Name, bool IsUnless) {\n"; | 
|  | OS << "  if (IsUnless)\n"; | 
|  | OS << "    return " | 
|  | "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; | 
|  | for (const auto &Rule : SubMatchRule.second) { | 
|  | if (Rule.isNegatedSubRule()) | 
|  | OS << "    Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() | 
|  | << ").\n"; | 
|  | } | 
|  | OS << "    Default(None);\n"; | 
|  | OS << "  return " | 
|  | "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; | 
|  | for (const auto &Rule : SubMatchRule.second) { | 
|  | if (!Rule.isNegatedSubRule()) | 
|  | OS << "  Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() | 
|  | << ").\n"; | 
|  | } | 
|  | OS << "  Default(None);\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | // Generate the function that checks for the top-level rules. | 
|  | OS << "std::pair<Optional<attr::SubjectMatchRule>, " | 
|  | "Optional<attr::SubjectMatchRule> (*)(StringRef, " | 
|  | "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n"; | 
|  | OS << "  return " | 
|  | "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, " | 
|  | "Optional<attr::SubjectMatchRule> (*) (StringRef, " | 
|  | "bool)>>(Name).\n"; | 
|  | for (const auto &Rule : Rules) { | 
|  | if (Rule.isSubRule()) | 
|  | continue; | 
|  | std::string SubRuleFunction; | 
|  | if (SubMatchRules.count(Rule.MetaSubject)) | 
|  | SubRuleFunction = | 
|  | ("isAttributeSubjectMatchSubRuleFor_" + Rule.getName()).str(); | 
|  | else | 
|  | SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor"; | 
|  | OS << "  Case(\"" << Rule.getName() << "\", std::make_pair(" | 
|  | << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n"; | 
|  | } | 
|  | OS << "  Default(std::make_pair(None, " | 
|  | "defaultIsAttributeSubjectMatchSubRuleFor));\n"; | 
|  | OS << "}\n\n"; | 
|  |  | 
|  | // Generate the function that checks for the submatch rules. | 
|  | OS << "const char *validAttributeSubjectMatchSubRules(" | 
|  | << AttributeSubjectMatchRule::EnumName << " Rule) {\n"; | 
|  | OS << "  switch (Rule) {\n"; | 
|  | for (const auto &SubMatchRule : SubMatchRules) { | 
|  | OS << "  case " | 
|  | << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue() | 
|  | << ":\n"; | 
|  | OS << "  return \"'"; | 
|  | bool IsFirst = true; | 
|  | for (const auto &Rule : SubMatchRule.second) { | 
|  | if (!IsFirst) | 
|  | OS << ", '"; | 
|  | IsFirst = false; | 
|  | if (Rule.isNegatedSubRule()) | 
|  | OS << "unless("; | 
|  | OS << Rule.getName(); | 
|  | if (Rule.isNegatedSubRule()) | 
|  | OS << ')'; | 
|  | OS << "'"; | 
|  | } | 
|  | OS << "\";\n"; | 
|  | } | 
|  | OS << "  default: return nullptr;\n"; | 
|  | OS << "  }\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | template <typename Fn> | 
|  | static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); | 
|  | SmallDenseSet<StringRef, 8> Seen; | 
|  | for (const FlattenedSpelling &S : Spellings) { | 
|  | if (Seen.insert(S.name()).second) | 
|  | F(S); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// \brief Emits the first-argument-is-type property for attributes. | 
|  | static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n"; | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | for (const auto *Attr : Attrs) { | 
|  | // Determine whether the first argument is a type. | 
|  | std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args"); | 
|  | if (Args.empty()) | 
|  | continue; | 
|  |  | 
|  | if (Args[0]->getSuperClasses().back().first->getName() != "TypeArgument") | 
|  | continue; | 
|  |  | 
|  | // All these spellings take a single type argument. | 
|  | forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { | 
|  | OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; | 
|  | }); | 
|  | } | 
|  | OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n"; | 
|  | } | 
|  |  | 
|  | /// \brief Emits the parse-arguments-in-unevaluated-context property for | 
|  | /// attributes. | 
|  | static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n"; | 
|  | ParsedAttrMap Attrs = getParsedAttrList(Records); | 
|  | for (const auto &I : Attrs) { | 
|  | const Record &Attr = *I.second; | 
|  |  | 
|  | if (!Attr.getValueAsBit("ParseArgumentsAsUnevaluated")) | 
|  | continue; | 
|  |  | 
|  | // All these spellings take are parsed unevaluated. | 
|  | forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { | 
|  | OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; | 
|  | }); | 
|  | } | 
|  | OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n"; | 
|  | } | 
|  |  | 
|  | static bool isIdentifierArgument(Record *Arg) { | 
|  | return !Arg->getSuperClasses().empty() && | 
|  | llvm::StringSwitch<bool>(Arg->getSuperClasses().back().first->getName()) | 
|  | .Case("IdentifierArgument", true) | 
|  | .Case("EnumArgument", true) | 
|  | .Case("VariadicEnumArgument", true) | 
|  | .Default(false); | 
|  | } | 
|  |  | 
|  | // Emits the first-argument-is-identifier property for attributes. | 
|  | static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n"; | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | for (const auto *Attr : Attrs) { | 
|  | // Determine whether the first argument is an identifier. | 
|  | std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args"); | 
|  | if (Args.empty() || !isIdentifierArgument(Args[0])) | 
|  | continue; | 
|  |  | 
|  | // All these spellings take an identifier argument. | 
|  | forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { | 
|  | OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; | 
|  | }); | 
|  | } | 
|  | OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n"; | 
|  | } | 
|  |  | 
|  | namespace clang { | 
|  |  | 
|  | // Emits the class definitions for attributes. | 
|  | void 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"; | 
|  |  | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  |  | 
|  | // FIXME: Currently, documentation is generated as-needed due to the fact | 
|  | // that there is no way to allow a generated project "reach into" the docs | 
|  | // directory (for instance, it may be an out-of-tree build). However, we want | 
|  | // to ensure that every attribute has a Documentation field, and produce an | 
|  | // error if it has been neglected. Otherwise, the on-demand generation which | 
|  | // happens server-side will fail. This code is ensuring that functionality, | 
|  | // even though this Emitter doesn't technically need the documentation. | 
|  | // 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; | 
|  | bool Inheritable = false; | 
|  | for (const auto &Super : llvm::reverse(Supers)) { | 
|  | const Record *R = Super.first; | 
|  | if (R->getName() != "TargetSpecificAttr" && SuperName.empty()) | 
|  | SuperName = R->getName(); | 
|  | if (R->getName() == "InheritableAttr") | 
|  | Inheritable = true; | 
|  | } | 
|  |  | 
|  | OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; | 
|  |  | 
|  | std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); | 
|  | std::vector<std::unique_ptr<Argument>> Args; | 
|  | Args.reserve(ArgRecords.size()); | 
|  |  | 
|  | bool HasOptArg = false; | 
|  | bool HasFakeArg = false; | 
|  | for (const auto *ArgRecord : ArgRecords) { | 
|  | Args.emplace_back(createArgument(*ArgRecord, R.getName())); | 
|  | Args.back()->writeDeclarations(OS); | 
|  | OS << "\n\n"; | 
|  |  | 
|  | // For these purposes, fake takes priority over optional. | 
|  | if (Args.back()->isFake()) { | 
|  | HasFakeArg = true; | 
|  | } else if (Args.back()->isOptional()) { | 
|  | HasOptArg = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | OS << "public:\n"; | 
|  |  | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); | 
|  |  | 
|  | // If there are zero or one spellings, all spelling-related functionality | 
|  | // can be elided. If all of the spellings share the same name, the spelling | 
|  | // functionality can also be elided. | 
|  | bool ElideSpelling = (Spellings.size() <= 1) || | 
|  | SpellingNamesAreCommon(Spellings); | 
|  |  | 
|  | // This maps spelling index values to semantic Spelling enumerants. | 
|  | SemanticSpellingMap SemanticToSyntacticMap; | 
|  |  | 
|  | if (!ElideSpelling) | 
|  | OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); | 
|  |  | 
|  | // Emit CreateImplicit factory methods. | 
|  | auto emitCreateImplicit = [&](bool emitFake) { | 
|  | OS << "  static " << R.getName() << "Attr *CreateImplicit("; | 
|  | OS << "ASTContext &Ctx"; | 
|  | if (!ElideSpelling) | 
|  | OS << ", Spelling S"; | 
|  | for (auto const &ai : Args) { | 
|  | if (ai->isFake() && !emitFake) continue; | 
|  | OS << ", "; | 
|  | ai->writeCtorParameters(OS); | 
|  | } | 
|  | OS << ", SourceRange Loc = SourceRange()"; | 
|  | OS << ") {\n"; | 
|  | OS << "    auto *A = new (Ctx) " << R.getName(); | 
|  | OS << "Attr(Loc, Ctx, "; | 
|  | for (auto const &ai : Args) { | 
|  | if (ai->isFake() && !emitFake) continue; | 
|  | ai->writeImplicitCtorArgs(OS); | 
|  | OS << ", "; | 
|  | } | 
|  | OS << (ElideSpelling ? "0" : "S") << ");\n"; | 
|  | OS << "    A->setImplicit(true);\n"; | 
|  | OS << "    return A;\n  }\n\n"; | 
|  | }; | 
|  |  | 
|  | // Emit a CreateImplicit that takes all the arguments. | 
|  | emitCreateImplicit(true); | 
|  |  | 
|  | // Emit a CreateImplicit that takes all the non-fake arguments. | 
|  | if (HasFakeArg) { | 
|  | emitCreateImplicit(false); | 
|  | } | 
|  |  | 
|  | // Emit constructors. | 
|  | auto emitCtor = [&](bool emitOpt, bool emitFake) { | 
|  | auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) { | 
|  | if (arg->isFake()) return emitFake; | 
|  | if (arg->isOptional()) return emitOpt; | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; | 
|  | for (auto const &ai : Args) { | 
|  | if (!shouldEmitArg(ai)) continue; | 
|  | OS << "              , "; | 
|  | ai->writeCtorParameters(OS); | 
|  | OS << "\n"; | 
|  | } | 
|  |  | 
|  | OS << "              , "; | 
|  | OS << "unsigned SI\n"; | 
|  |  | 
|  | OS << "             )\n"; | 
|  | OS << "    : " << SuperName << "(attr::" << R.getName() << ", R, SI, " | 
|  | << ( R.getValueAsBit("LateParsed") ? "true" : "false" ); | 
|  | if (Inheritable) { | 
|  | OS << ", " | 
|  | << (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true" | 
|  | : "false"); | 
|  | } | 
|  | OS << ")\n"; | 
|  |  | 
|  | for (auto const &ai : Args) { | 
|  | OS << "              , "; | 
|  | if (!shouldEmitArg(ai)) { | 
|  | ai->writeCtorDefaultInitializers(OS); | 
|  | } else { | 
|  | ai->writeCtorInitializers(OS); | 
|  | } | 
|  | OS << "\n"; | 
|  | } | 
|  |  | 
|  | OS << "  {\n"; | 
|  |  | 
|  | for (auto const &ai : Args) { | 
|  | if (!shouldEmitArg(ai)) continue; | 
|  | ai->writeCtorBody(OS); | 
|  | } | 
|  | OS << "  }\n\n"; | 
|  | }; | 
|  |  | 
|  | // Emit a constructor that includes all the arguments. | 
|  | // This is necessary for cloning. | 
|  | emitCtor(true, true); | 
|  |  | 
|  | // 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 (!ElideSpelling) { | 
|  | assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list"); | 
|  | OS << "  Spelling getSemanticSpelling() const {\n"; | 
|  | WriteSemanticSpellingSwitch("SpellingListIndex", SemanticToSyntacticMap, | 
|  | OS); | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | writeAttrAccessorDefinition(R, OS); | 
|  |  | 
|  | for (auto const &ai : Args) { | 
|  | ai->writeAccessors(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); | 
|  | else if (ai->isVariadicEnumArg()) | 
|  | static_cast<const VariadicEnumArgument *>(ai.get()) | 
|  | ->writeConversion(OS); | 
|  | } | 
|  |  | 
|  | OS << R.getValueAsString("AdditionalMembers"); | 
|  | OS << "\n\n"; | 
|  |  | 
|  | OS << "  static bool classof(const Attr *A) { return A->getKind() == " | 
|  | << "attr::" << R.getName() << "; }\n"; | 
|  |  | 
|  | OS << "};\n\n"; | 
|  | } | 
|  |  | 
|  | OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n"; | 
|  | } | 
|  |  | 
|  | // Emits the class method definitions for attributes. | 
|  | void 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(getLocation(), C"; | 
|  | for (auto const &ai : Args) { | 
|  | OS << ", "; | 
|  | ai->writeCloneArgs(OS); | 
|  | } | 
|  | OS << ", getSpellingListIndex());\n"; | 
|  | OS << "  A->Inherited = Inherited;\n"; | 
|  | OS << "  A->IsPackExpansion = IsPackExpansion;\n"; | 
|  | OS << "  A->Implicit = Implicit;\n"; | 
|  | OS << "  return A;\n}\n\n"; | 
|  |  | 
|  | 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 << "  }\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 | 
|  |  | 
|  | static void emitAttrList(raw_ostream &OS, StringRef Class, | 
|  | const std::vector<Record*> &AttrList) { | 
|  | for (auto Cur : AttrList) { | 
|  | OS << Class << "(" << Cur->getName() << ")\n"; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Determines if an attribute has a Pragma spelling. | 
|  | static bool AttrHasPragmaSpelling(const Record *R) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R); | 
|  | return llvm::find_if(Spellings, [](const FlattenedSpelling &S) { | 
|  | return S.variety() == "Pragma"; | 
|  | }) != Spellings.end(); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct AttrClassDescriptor { | 
|  | const char * const MacroName; | 
|  | const char * const TableGenName; | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static const AttrClassDescriptor AttrClassDescriptors[] = { | 
|  | { "ATTR", "Attr" }, | 
|  | { "STMT_ATTR", "StmtAttr" }, | 
|  | { "INHERITABLE_ATTR", "InheritableAttr" }, | 
|  | { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }, | 
|  | { "PARAMETER_ABI_ATTR", "ParameterABIAttr" } | 
|  | }; | 
|  |  | 
|  | static void emitDefaultDefine(raw_ostream &OS, StringRef name, | 
|  | const char *superName) { | 
|  | OS << "#ifndef " << name << "\n"; | 
|  | OS << "#define " << name << "(NAME) "; | 
|  | if (superName) OS << superName << "(NAME)"; | 
|  | OS << "\n#endif\n\n"; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// A class of attributes. | 
|  | struct AttrClass { | 
|  | const AttrClassDescriptor &Descriptor; | 
|  | Record *TheRecord; | 
|  | AttrClass *SuperClass = nullptr; | 
|  | std::vector<AttrClass*> SubClasses; | 
|  | std::vector<Record*> Attrs; | 
|  |  | 
|  | AttrClass(const AttrClassDescriptor &Descriptor, Record *R) | 
|  | : Descriptor(Descriptor), TheRecord(R) {} | 
|  |  | 
|  | void emitDefaultDefines(raw_ostream &OS) const { | 
|  | // Default the macro unless this is a root class (i.e. Attr). | 
|  | if (SuperClass) { | 
|  | emitDefaultDefine(OS, Descriptor.MacroName, | 
|  | SuperClass->Descriptor.MacroName); | 
|  | } | 
|  | } | 
|  |  | 
|  | void emitUndefs(raw_ostream &OS) const { | 
|  | OS << "#undef " << Descriptor.MacroName << "\n"; | 
|  | } | 
|  |  | 
|  | void emitAttrList(raw_ostream &OS) const { | 
|  | for (auto SubClass : SubClasses) { | 
|  | SubClass->emitAttrList(OS); | 
|  | } | 
|  |  | 
|  | ::emitAttrList(OS, Descriptor.MacroName, Attrs); | 
|  | } | 
|  |  | 
|  | void classifyAttrOnRoot(Record *Attr) { | 
|  | bool result = classifyAttr(Attr); | 
|  | assert(result && "failed to classify on root"); (void) result; | 
|  | } | 
|  |  | 
|  | void emitAttrRange(raw_ostream &OS) const { | 
|  | OS << "ATTR_RANGE(" << Descriptor.TableGenName | 
|  | << ", " << getFirstAttr()->getName() | 
|  | << ", " << getLastAttr()->getName() << ")\n"; | 
|  | } | 
|  |  | 
|  | private: | 
|  | bool classifyAttr(Record *Attr) { | 
|  | // Check all the subclasses. | 
|  | for (auto SubClass : SubClasses) { | 
|  | if (SubClass->classifyAttr(Attr)) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // It's not more specific than this class, but it might still belong here. | 
|  | if (Attr->isSubClassOf(TheRecord)) { | 
|  | Attrs.push_back(Attr); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Record *getFirstAttr() const { | 
|  | if (!SubClasses.empty()) | 
|  | return SubClasses.front()->getFirstAttr(); | 
|  | return Attrs.front(); | 
|  | } | 
|  |  | 
|  | Record *getLastAttr() const { | 
|  | if (!Attrs.empty()) | 
|  | return Attrs.back(); | 
|  | return SubClasses.back()->getLastAttr(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// The entire hierarchy of attribute classes. | 
|  | class AttrClassHierarchy { | 
|  | std::vector<std::unique_ptr<AttrClass>> Classes; | 
|  |  | 
|  | public: | 
|  | AttrClassHierarchy(RecordKeeper &Records) { | 
|  | // Find records for all the classes. | 
|  | for (auto &Descriptor : AttrClassDescriptors) { | 
|  | Record *ClassRecord = Records.getClass(Descriptor.TableGenName); | 
|  | AttrClass *Class = new AttrClass(Descriptor, ClassRecord); | 
|  | Classes.emplace_back(Class); | 
|  | } | 
|  |  | 
|  | // Link up the hierarchy. | 
|  | for (auto &Class : Classes) { | 
|  | if (AttrClass *SuperClass = findSuperClass(Class->TheRecord)) { | 
|  | Class->SuperClass = SuperClass; | 
|  | SuperClass->SubClasses.push_back(Class.get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | for (auto i = Classes.begin(), e = Classes.end(); i != e; ++i) { | 
|  | assert((i == Classes.begin()) == ((*i)->SuperClass == nullptr) && | 
|  | "only the first class should be a root class!"); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void emitDefaultDefines(raw_ostream &OS) const { | 
|  | for (auto &Class : Classes) { | 
|  | Class->emitDefaultDefines(OS); | 
|  | } | 
|  | } | 
|  |  | 
|  | void emitUndefs(raw_ostream &OS) const { | 
|  | for (auto &Class : Classes) { | 
|  | Class->emitUndefs(OS); | 
|  | } | 
|  | } | 
|  |  | 
|  | void emitAttrLists(raw_ostream &OS) const { | 
|  | // Just start from the root class. | 
|  | Classes[0]->emitAttrList(OS); | 
|  | } | 
|  |  | 
|  | void emitAttrRanges(raw_ostream &OS) const { | 
|  | for (auto &Class : Classes) | 
|  | Class->emitAttrRange(OS); | 
|  | } | 
|  |  | 
|  | void classifyAttr(Record *Attr) { | 
|  | // Add the attribute to the root class. | 
|  | Classes[0]->classifyAttrOnRoot(Attr); | 
|  | } | 
|  |  | 
|  | private: | 
|  | AttrClass *findClassByRecord(Record *R) const { | 
|  | for (auto &Class : Classes) { | 
|  | if (Class->TheRecord == R) | 
|  | return Class.get(); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | AttrClass *findSuperClass(Record *R) const { | 
|  | // TableGen flattens the superclass list, so we just need to walk it | 
|  | // in reverse. | 
|  | auto SuperClasses = R->getSuperClasses(); | 
|  | for (signed i = 0, e = SuperClasses.size(); i != e; ++i) { | 
|  | auto SuperClass = findClassByRecord(SuperClasses[e - i - 1].first); | 
|  | if (SuperClass) return SuperClass; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | namespace clang { | 
|  |  | 
|  | // Emits the enumeration list for attributes. | 
|  | void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("List of all attributes that Clang recognizes", OS); | 
|  |  | 
|  | AttrClassHierarchy Hierarchy(Records); | 
|  |  | 
|  | // Add defaulting macro definitions. | 
|  | Hierarchy.emitDefaultDefines(OS); | 
|  | emitDefaultDefine(OS, "PRAGMA_SPELLING_ATTR", nullptr); | 
|  |  | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  | std::vector<Record *> PragmaAttrs; | 
|  | for (auto *Attr : Attrs) { | 
|  | if (!Attr->getValueAsBit("ASTNode")) | 
|  | continue; | 
|  |  | 
|  | // Add the attribute to the ad-hoc groups. | 
|  | if (AttrHasPragmaSpelling(Attr)) | 
|  | PragmaAttrs.push_back(Attr); | 
|  |  | 
|  | // Place it in the hierarchy. | 
|  | Hierarchy.classifyAttr(Attr); | 
|  | } | 
|  |  | 
|  | // Emit the main attribute list. | 
|  | Hierarchy.emitAttrLists(OS); | 
|  |  | 
|  | // Emit the ad hoc groups. | 
|  | emitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs); | 
|  |  | 
|  | // Emit the attribute ranges. | 
|  | OS << "#ifdef ATTR_RANGE\n"; | 
|  | Hierarchy.emitAttrRanges(OS); | 
|  | OS << "#undef ATTR_RANGE\n"; | 
|  | OS << "#endif\n"; | 
|  |  | 
|  | Hierarchy.emitUndefs(OS); | 
|  | OS << "#undef PRAGMA_SPELLING_ATTR\n"; | 
|  | } | 
|  |  | 
|  | // Emits the enumeration list for attributes. | 
|  | void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader( | 
|  | "List of all attribute subject matching rules that Clang recognizes", OS); | 
|  | PragmaClangAttributeSupport &PragmaAttributeSupport = | 
|  | getPragmaAttributeSupport(Records); | 
|  | emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr); | 
|  | PragmaAttributeSupport.emitMatchRuleList(OS); | 
|  | OS << "#undef ATTR_MATCH_RULE\n"; | 
|  | } | 
|  |  | 
|  | // Emits the code to read an attribute from a precompiled header. | 
|  | void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Attribute deserialization code", OS); | 
|  |  | 
|  | Record *InhClass = Records.getClass("InheritableAttr"); | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), | 
|  | ArgRecords; | 
|  | std::vector<std::unique_ptr<Argument>> Args; | 
|  |  | 
|  | OS << "  switch (Kind) {\n"; | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  |  | 
|  | OS << "  case attr::" << R.getName() << ": {\n"; | 
|  | if (R.isSubClassOf(InhClass)) | 
|  | OS << "    bool isInherited = Record.readInt();\n"; | 
|  | OS << "    bool isImplicit = Record.readInt();\n"; | 
|  | OS << "    unsigned Spelling = Record.readInt();\n"; | 
|  | ArgRecords = R.getValueAsListOfDefs("Args"); | 
|  | Args.clear(); | 
|  | for (const auto *Arg : ArgRecords) { | 
|  | Args.emplace_back(createArgument(*Arg, R.getName())); | 
|  | Args.back()->writePCHReadDecls(OS); | 
|  | } | 
|  | OS << "    New = new (Context) " << R.getName() << "Attr(Range, Context"; | 
|  | for (auto const &ri : Args) { | 
|  | OS << ", "; | 
|  | ri->writePCHReadArgs(OS); | 
|  | } | 
|  | OS << ", Spelling);\n"; | 
|  | if (R.isSubClassOf(InhClass)) | 
|  | OS << "    cast<InheritableAttr>(New)->setInherited(isInherited);\n"; | 
|  | OS << "    New->setImplicit(isImplicit);\n"; | 
|  | OS << "    break;\n"; | 
|  | OS << "  }\n"; | 
|  | } | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | // Emits the code to write an attribute to a precompiled header. | 
|  | void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Attribute serialization code", OS); | 
|  |  | 
|  | Record *InhClass = Records.getClass("InheritableAttr"); | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; | 
|  |  | 
|  | OS << "  switch (A->getKind()) {\n"; | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  | OS << "  case attr::" << R.getName() << ": {\n"; | 
|  | Args = R.getValueAsListOfDefs("Args"); | 
|  | if (R.isSubClassOf(InhClass) || !Args.empty()) | 
|  | OS << "    const auto *SA = cast<" << R.getName() | 
|  | << "Attr>(A);\n"; | 
|  | if (R.isSubClassOf(InhClass)) | 
|  | OS << "    Record.push_back(SA->isInherited());\n"; | 
|  | OS << "    Record.push_back(A->isImplicit());\n"; | 
|  | OS << "    Record.push_back(A->getSpellingListIndex());\n"; | 
|  |  | 
|  | for (const auto *Arg : Args) | 
|  | createArgument(*Arg, R.getName())->writePCHWrite(OS); | 
|  | OS << "    break;\n"; | 
|  | OS << "  }\n"; | 
|  | } | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | // Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test' | 
|  | // parameter with only a single check type, if applicable. | 
|  | static void GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test, | 
|  | std::string *FnName, | 
|  | StringRef ListName, | 
|  | StringRef CheckAgainst, | 
|  | StringRef Scope) { | 
|  | if (!R->isValueUnset(ListName)) { | 
|  | Test += " && ("; | 
|  | std::vector<StringRef> Items = R->getValueAsListOfStrings(ListName); | 
|  | for (auto I = Items.begin(), E = Items.end(); I != E; ++I) { | 
|  | StringRef Part = *I; | 
|  | Test += CheckAgainst; | 
|  | Test += " == "; | 
|  | Test += Scope; | 
|  | Test += Part; | 
|  | if (I + 1 != E) | 
|  | Test += " || "; | 
|  | if (FnName) | 
|  | *FnName += Part; | 
|  | } | 
|  | Test += ")"; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Generate a conditional expression to check if the current target satisfies | 
|  | // the conditions for a TargetSpecificAttr record, and append the code for | 
|  | // those checks to the Test string. If the FnName string pointer is non-null, | 
|  | // append a unique suffix to distinguish this set of target checks from other | 
|  | // TargetSpecificAttr records. | 
|  | static void GenerateTargetSpecificAttrChecks(const Record *R, | 
|  | std::vector<StringRef> &Arches, | 
|  | std::string &Test, | 
|  | std::string *FnName) { | 
|  | // It is assumed that there will be an llvm::Triple object | 
|  | // named "T" and a TargetInfo object named "Target" within | 
|  | // scope that can be used to determine whether the attribute exists in | 
|  | // a given target. | 
|  | Test += "true"; | 
|  | // If one or more architectures is specified, check those.  Arches are handled | 
|  | // differently because GenerateTargetRequirements needs to combine the list | 
|  | // with ParseKind. | 
|  | if (!Arches.empty()) { | 
|  | Test += " && ("; | 
|  | for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { | 
|  | StringRef Part = *I; | 
|  | Test += "T.getArch() == llvm::Triple::"; | 
|  | Test += Part; | 
|  | if (I + 1 != E) | 
|  | Test += " || "; | 
|  | if (FnName) | 
|  | *FnName += Part; | 
|  | } | 
|  | Test += ")"; | 
|  | } | 
|  |  | 
|  | // If the attribute is specific to particular OSes, check those. | 
|  | GenerateTargetSpecificAttrCheck(R, Test, FnName, "OSes", "T.getOS()", | 
|  | "llvm::Triple::"); | 
|  |  | 
|  | // If one or more CXX ABIs are specified, check those as well. | 
|  | GenerateTargetSpecificAttrCheck(R, Test, FnName, "CXXABIs", | 
|  | "Target.getCXXABI().getKind()", | 
|  | "TargetCXXABI::"); | 
|  | // If one or more object formats is specified, check those. | 
|  | GenerateTargetSpecificAttrCheck(R, Test, FnName, "ObjectFormats", | 
|  | "T.getObjectFormat()", "llvm::Triple::"); | 
|  | } | 
|  |  | 
|  | static void GenerateHasAttrSpellingStringSwitch( | 
|  | const std::vector<Record *> &Attrs, raw_ostream &OS, | 
|  | const std::string &Variety = "", const std::string &Scope = "") { | 
|  | for (const auto *Attr : Attrs) { | 
|  | // C++11-style attributes have specific version information associated with | 
|  | // 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: | 
|  | // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations | 
|  | int Version = 1; | 
|  |  | 
|  | if (Variety == "CXX11") { | 
|  | std::vector<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings"); | 
|  | for (const auto &Spelling : Spellings) { | 
|  | if (Spelling->getValueAsString("Variety") == "CXX11") { | 
|  | Version = static_cast<int>(Spelling->getValueAsInt("Version")); | 
|  | if (Scope.empty() && Version == 1) | 
|  | PrintError(Spelling->getLoc(), "C++ standard attributes must " | 
|  | "have valid version information."); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string Test; | 
|  | if (Attr->isSubClassOf("TargetSpecificAttr")) { | 
|  | const Record *R = Attr->getValueAsDef("Target"); | 
|  | std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches"); | 
|  | GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr); | 
|  |  | 
|  | // If this is the C++11 variety, also add in the LangOpts test. | 
|  | if (Variety == "CXX11") | 
|  | Test += " && LangOpts.CPlusPlus11"; | 
|  | else if (Variety == "C2x") | 
|  | Test += " && LangOpts.DoubleSquareBracketAttributes"; | 
|  | } else if (Variety == "CXX11") | 
|  | // C++11 mode should be checked against LangOpts, which is presumed to be | 
|  | // present in the caller. | 
|  | Test = "LangOpts.CPlusPlus11"; | 
|  | else if (Variety == "C2x") | 
|  | Test = "LangOpts.DoubleSquareBracketAttributes"; | 
|  |  | 
|  | std::string TestStr = | 
|  | !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1"; | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr); | 
|  | for (const auto &S : Spellings) | 
|  | if (Variety.empty() || (Variety == S.variety() && | 
|  | (Scope.empty() || Scope == S.nameSpace()))) | 
|  | OS << "    .Case(\"" << S.name() << "\", " << TestStr << ")\n"; | 
|  | } | 
|  | OS << "    .Default(0);\n"; | 
|  | } | 
|  |  | 
|  | // Emits the list of spellings for attributes. | 
|  | void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Code to implement the __has_attribute logic", OS); | 
|  |  | 
|  | // Separate all of the attributes out into four group: generic, C++11, GNU, | 
|  | // and declspecs. Then generate a big switch statement for each of them. | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  | std::vector<Record *> Declspec, Microsoft, GNU, Pragma; | 
|  | std::map<std::string, std::vector<Record *>> CXX, C2x; | 
|  |  | 
|  | // Walk over the list of all attributes, and split them out based on the | 
|  | // spelling variety. | 
|  | for (auto *R : Attrs) { | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R); | 
|  | for (const auto &SI : Spellings) { | 
|  | const std::string &Variety = SI.variety(); | 
|  | if (Variety == "GNU") | 
|  | GNU.push_back(R); | 
|  | else if (Variety == "Declspec") | 
|  | Declspec.push_back(R); | 
|  | else if (Variety == "Microsoft") | 
|  | Microsoft.push_back(R); | 
|  | else if (Variety == "CXX11") | 
|  | CXX[SI.nameSpace()].push_back(R); | 
|  | else if (Variety == "C2x") | 
|  | C2x[SI.nameSpace()].push_back(R); | 
|  | else if (Variety == "Pragma") | 
|  | Pragma.push_back(R); | 
|  | } | 
|  | } | 
|  |  | 
|  | OS << "const llvm::Triple &T = Target.getTriple();\n"; | 
|  | OS << "switch (Syntax) {\n"; | 
|  | OS << "case AttrSyntax::GNU:\n"; | 
|  | OS << "  return llvm::StringSwitch<int>(Name)\n"; | 
|  | GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU"); | 
|  | OS << "case AttrSyntax::Declspec:\n"; | 
|  | OS << "  return llvm::StringSwitch<int>(Name)\n"; | 
|  | GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec"); | 
|  | OS << "case AttrSyntax::Microsoft:\n"; | 
|  | OS << "  return llvm::StringSwitch<int>(Name)\n"; | 
|  | GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft"); | 
|  | OS << "case AttrSyntax::Pragma:\n"; | 
|  | OS << "  return llvm::StringSwitch<int>(Name)\n"; | 
|  | GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); | 
|  | auto fn = [&OS](const char *Spelling, const char *Variety, | 
|  | const std::map<std::string, std::vector<Record *>> &List) { | 
|  | OS << "case AttrSyntax::" << Variety << ": {\n"; | 
|  | // C++11-style attributes are further split out based on the Scope. | 
|  | for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { | 
|  | if (I != List.cbegin()) | 
|  | OS << " else "; | 
|  | if (I->first.empty()) | 
|  | OS << "if (!Scope || Scope->getName() == \"\") {\n"; | 
|  | else | 
|  | OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; | 
|  | OS << "  return llvm::StringSwitch<int>(Name)\n"; | 
|  | GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); | 
|  | OS << "}"; | 
|  | } | 
|  | OS << "\n} break;\n"; | 
|  | }; | 
|  | fn("CXX11", "CXX", CXX); | 
|  | fn("C2x", "C", C2x); | 
|  | OS << "}\n"; | 
|  | } | 
|  |  | 
|  | void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Code to translate different attribute spellings " | 
|  | "into internal identifiers", OS); | 
|  |  | 
|  | OS << "  switch (AttrKind) {\n"; | 
|  |  | 
|  | ParsedAttrMap Attrs = getParsedAttrList(Records); | 
|  | for (const auto &I : Attrs) { | 
|  | const Record &R = *I.second; | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); | 
|  | OS << "  case AT_" << I.first << ": {\n"; | 
|  | for (unsigned I = 0; I < Spellings.size(); ++ I) { | 
|  | OS << "    if (Name == \"" << Spellings[I].name() << "\" && " | 
|  | << "SyntaxUsed == " | 
|  | << StringSwitch<unsigned>(Spellings[I].variety()) | 
|  | .Case("GNU", 0) | 
|  | .Case("CXX11", 1) | 
|  | .Case("C2x", 2) | 
|  | .Case("Declspec", 3) | 
|  | .Case("Microsoft", 4) | 
|  | .Case("Keyword", 5) | 
|  | .Case("Pragma", 6) | 
|  | .Default(0) | 
|  | << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" | 
|  | << "        return " << I << ";\n"; | 
|  | } | 
|  |  | 
|  | OS << "    break;\n"; | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | OS << "  }\n"; | 
|  | OS << "  return 0;\n"; | 
|  | } | 
|  |  | 
|  | // Emits code used by RecursiveASTVisitor to visit attributes | 
|  | void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS); | 
|  |  | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | // Write method declarations for Traverse* methods. | 
|  | // We emit this here because we only generate methods for attributes that | 
|  | // are declared as ASTNodes. | 
|  | OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n"; | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  | OS << "  bool Traverse" | 
|  | << R.getName() << "Attr(" << R.getName() << "Attr *A);\n"; | 
|  | OS << "  bool Visit" | 
|  | << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" | 
|  | << "    return true; \n" | 
|  | << "  }\n"; | 
|  | } | 
|  | OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n"; | 
|  |  | 
|  | // Write individual Traverse* methods for each attribute class. | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  |  | 
|  | OS << "template <typename Derived>\n" | 
|  | << "bool VISITORCLASS<Derived>::Traverse" | 
|  | << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" | 
|  | << "  if (!getDerived().VisitAttr(A))\n" | 
|  | << "    return false;\n" | 
|  | << "  if (!getDerived().Visit" << R.getName() << "Attr(A))\n" | 
|  | << "    return false;\n"; | 
|  |  | 
|  | std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); | 
|  | for (const auto *Arg : ArgRecords) | 
|  | createArgument(*Arg, R.getName())->writeASTVisitorTraversal(OS); | 
|  |  | 
|  | OS << "  return true;\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | // Write generic Traverse routine | 
|  | OS << "template <typename Derived>\n" | 
|  | << "bool VISITORCLASS<Derived>::TraverseAttr(Attr *A) {\n" | 
|  | << "  if (!A)\n" | 
|  | << "    return true;\n" | 
|  | << "\n" | 
|  | << "  switch (A->getKind()) {\n"; | 
|  |  | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  |  | 
|  | OS << "    case attr::" << R.getName() << ":\n" | 
|  | << "      return getDerived().Traverse" << R.getName() << "Attr(" | 
|  | << "cast<" << R.getName() << "Attr>(A));\n"; | 
|  | } | 
|  | OS << "  }\n";  // end switch | 
|  | OS << "  llvm_unreachable(\"bad attribute kind\");\n"; | 
|  | OS << "}\n";  // end function | 
|  | OS << "#endif  // ATTR_VISITOR_DECLS_ONLY\n"; | 
|  | } | 
|  |  | 
|  | void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs, | 
|  | raw_ostream &OS, | 
|  | bool AppliesToDecl) { | 
|  |  | 
|  | OS << "  switch (At->getKind()) {\n"; | 
|  | for (const auto *Attr : Attrs) { | 
|  | const Record &R = *Attr; | 
|  | if (!R.getValueAsBit("ASTNode")) | 
|  | continue; | 
|  | OS << "    case attr::" << R.getName() << ": {\n"; | 
|  | bool ShouldClone = R.getValueAsBit("Clone") && | 
|  | (!AppliesToDecl || | 
|  | R.getValueAsBit("MeaningfulToClassTemplateDefinition")); | 
|  |  | 
|  | if (!ShouldClone) { | 
|  | OS << "      return nullptr;\n"; | 
|  | OS << "    }\n"; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | OS << "      const auto *A = cast<" | 
|  | << R.getName() << "Attr>(At);\n"; | 
|  | bool TDependent = R.getValueAsBit("TemplateDependent"); | 
|  |  | 
|  | if (!TDependent) { | 
|  | OS << "      return A->clone(C);\n"; | 
|  | OS << "    }\n"; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); | 
|  | std::vector<std::unique_ptr<Argument>> Args; | 
|  | Args.reserve(ArgRecords.size()); | 
|  |  | 
|  | for (const auto *ArgRecord : ArgRecords) | 
|  | Args.emplace_back(createArgument(*ArgRecord, R.getName())); | 
|  |  | 
|  | for (auto const &ai : Args) | 
|  | ai->writeTemplateInstantiation(OS); | 
|  |  | 
|  | OS << "      return new (C) " << R.getName() << "Attr(A->getLocation(), C"; | 
|  | for (auto const &ai : Args) { | 
|  | OS << ", "; | 
|  | ai->writeTemplateInstantiationArgs(OS); | 
|  | } | 
|  | OS << ", A->getSpellingListIndex());\n    }\n"; | 
|  | } | 
|  | OS << "  } // end switch\n" | 
|  | << "  llvm_unreachable(\"Unknown attribute!\");\n" | 
|  | << "  return nullptr;\n"; | 
|  | } | 
|  |  | 
|  | // Emits code to instantiate dependent attributes on templates. | 
|  | void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Template instantiation code for attributes", OS); | 
|  |  | 
|  | std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  |  | 
|  | OS << "namespace clang {\n" | 
|  | << "namespace sema {\n\n" | 
|  | << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " | 
|  | << "Sema &S,\n" | 
|  | << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; | 
|  | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false); | 
|  | OS << "}\n\n" | 
|  | << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" | 
|  | << " ASTContext &C, Sema &S,\n" | 
|  | << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; | 
|  | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true); | 
|  | OS << "}\n\n" | 
|  | << "} // end namespace sema\n" | 
|  | << "} // end namespace clang\n"; | 
|  | } | 
|  |  | 
|  | // Emits the list of parsed attributes. | 
|  | void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("List of all attributes that Clang recognizes", 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"; | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool isArgVariadic(const Record &R, StringRef AttrName) { | 
|  | return createArgument(R, AttrName)->isVariadic(); | 
|  | } | 
|  |  | 
|  | static void emitArgInfo(const Record &R, raw_ostream &OS) { | 
|  | // This function will count the number of arguments specified for the | 
|  | // attribute and emit the number of required arguments followed by the | 
|  | // number of optional arguments. | 
|  | std::vector<Record *> Args = R.getValueAsListOfDefs("Args"); | 
|  | unsigned ArgCount = 0, OptCount = 0; | 
|  | bool HasVariadic = false; | 
|  | for (const auto *Arg : Args) { | 
|  | // If the arg is fake, it's the user's job to supply it: general parsing | 
|  | // logic shouldn't need to know anything about it. | 
|  | if (Arg->getValueAsBit("Fake")) | 
|  | continue; | 
|  | Arg->getValueAsBit("Optional") ? ++OptCount : ++ArgCount; | 
|  | if (!HasVariadic && isArgVariadic(*Arg, R.getName())) | 
|  | HasVariadic = true; | 
|  | } | 
|  |  | 
|  | // 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 AttributeList &,"; | 
|  | OS << "const Decl *) {\n"; | 
|  | OS << "  return true;\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | static std::string GetDiagnosticSpelling(const Record &R) { | 
|  | std::string Ret = R.getValueAsString("DiagSpelling"); | 
|  | if (!Ret.empty()) | 
|  | return Ret; | 
|  |  | 
|  | // If we couldn't find the DiagSpelling in this object, we can check to see | 
|  | // if the object is one that has a base, and if it is, loop up to the Base | 
|  | // member recursively. | 
|  | std::string Super = R.getSuperClasses().back().first->getName(); | 
|  | if (Super == "DDecl" || Super == "DStmt") | 
|  | return GetDiagnosticSpelling(*R.getValueAsDef("Base")); | 
|  |  | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | static std::string CalculateDiagnostic(const Record &S) { | 
|  | // If the SubjectList object has a custom diagnostic associated with it, | 
|  | // return that directly. | 
|  | const StringRef CustomDiag = S.getValueAsString("CustomDiag"); | 
|  | if (!CustomDiag.empty()) | 
|  | return ("\"" + Twine(CustomDiag) + "\"").str(); | 
|  |  | 
|  | std::vector<std::string> DiagList; | 
|  | std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects"); | 
|  | for (const auto *Subject : Subjects) { | 
|  | const Record &R = *Subject; | 
|  | // Get the diagnostic text from the Decl or Stmt node given. | 
|  | std::string V = GetDiagnosticSpelling(R); | 
|  | if (V.empty()) { | 
|  | PrintError(R.getLoc(), | 
|  | "Could not determine diagnostic spelling for the node: " + | 
|  | R.getName() + "; please add one to DeclNodes.td"); | 
|  | } else { | 
|  | // The node may contain a list of elements itself, so split the elements | 
|  | // by a comma, and trim any whitespace. | 
|  | SmallVector<StringRef, 2> Frags; | 
|  | llvm::SplitString(V, Frags, ","); | 
|  | for (auto Str : Frags) { | 
|  | DiagList.push_back(Str.trim()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (DiagList.empty()) { | 
|  | PrintFatalError(S.getLoc(), | 
|  | "Could not deduce diagnostic argument for Attr subjects"); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | // FIXME: this is not particularly good for localization purposes and ideally | 
|  | // should be part of the diagnostics engine itself with some sort of list | 
|  | // specifier. | 
|  |  | 
|  | // A single member of the list can be returned directly. | 
|  | if (DiagList.size() == 1) | 
|  | return '"' + DiagList.front() + '"'; | 
|  |  | 
|  | if (DiagList.size() == 2) | 
|  | return '"' + DiagList[0] + " and " + DiagList[1] + '"'; | 
|  |  | 
|  | // If there are more than two in the list, we serialize the first N - 1 | 
|  | // elements with a comma. This leaves the string in the state: foo, bar, | 
|  | // baz (but misses quux). We can then add ", and " for the last element | 
|  | // manually. | 
|  | std::string Diag = llvm::join(DiagList.begin(), DiagList.end() - 1, ", "); | 
|  | return '"' + Diag + ", and " + *(DiagList.end() - 1) + '"'; | 
|  | } | 
|  |  | 
|  | static std::string GetSubjectWithSuffix(const Record *R) { | 
|  | const std::string &B = R->getName(); | 
|  | if (B == "DeclBase") | 
|  | return "Decl"; | 
|  | return B + "Decl"; | 
|  | } | 
|  |  | 
|  | static std::string functionNameForCustomAppertainsTo(const Record &Subject) { | 
|  | return "is" + Subject.getName().str(); | 
|  | } | 
|  |  | 
|  | static std::string 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. | 
|  | static std::set<std::string> CustomSubjectSet; | 
|  | auto I = CustomSubjectSet.find(FnName); | 
|  | if (I != CustomSubjectSet.end()) | 
|  | return *I; | 
|  |  | 
|  | Record *Base = Subject.getValueAsDef("Base"); | 
|  |  | 
|  | // Not currently support custom subjects within custom subjects. | 
|  | if (Base->isSubClassOf("SubsetSubject")) { | 
|  | PrintFatalError(Subject.getLoc(), | 
|  | "SubsetSubjects within SubsetSubjects is not supported"); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | OS << "static bool " << FnName << "(const Decl *D) {\n"; | 
|  | OS << "  if (const auto *S = dyn_cast<"; | 
|  | OS << GetSubjectWithSuffix(Base); | 
|  | OS << ">(D))\n"; | 
|  | OS << "    return " << Subject.getValueAsString("CheckCode") << ";\n"; | 
|  | OS << "  return false;\n"; | 
|  | OS << "}\n\n"; | 
|  |  | 
|  | CustomSubjectSet.insert(FnName); | 
|  | return FnName; | 
|  | } | 
|  |  | 
|  | static std::string 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"; | 
|  |  | 
|  | const Record *SubjectObj = Attr.getValueAsDef("Subjects"); | 
|  | std::vector<Record*> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); | 
|  |  | 
|  | // If the list of subjects is empty, it is assumed that the attribute | 
|  | // appertains to everything. | 
|  | if (Subjects.empty()) | 
|  | return "defaultAppertainsTo"; | 
|  |  | 
|  | 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. | 
|  | std::string FnName = "check" + Attr.getName().str() + "AppertainsTo"; | 
|  | std::stringstream SS; | 
|  | SS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr, "; | 
|  | SS << "const Decl *D) {\n"; | 
|  | SS << "  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 ((*I)->isSubClassOf("SubsetSubject")) { | 
|  | SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)"; | 
|  | } else { | 
|  | SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)"; | 
|  | } | 
|  |  | 
|  | if (I + 1 != E) | 
|  | SS << " && "; | 
|  | } | 
|  | SS << ") {\n"; | 
|  | SS << "    S.Diag(Attr.getLoc(), diag::"; | 
|  | SS << (Warn ? "warn_attribute_wrong_decl_type_str" : | 
|  | "err_attribute_wrong_decl_type_str"); | 
|  | SS << ")\n"; | 
|  | SS << "      << Attr.getName() << "; | 
|  | SS << CalculateDiagnostic(*SubjectObj) << ";\n"; | 
|  | SS << "    return false;\n"; | 
|  | SS << "  }\n"; | 
|  | SS << "  return true;\n"; | 
|  | SS << "}\n\n"; | 
|  |  | 
|  | OS << SS.str(); | 
|  | return FnName; | 
|  | } | 
|  |  | 
|  | static void | 
|  | emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport, | 
|  | raw_ostream &OS) { | 
|  | OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, " | 
|  | << AttributeSubjectMatchRule::EnumName << " rule) {\n"; | 
|  | OS << "  switch (rule) {\n"; | 
|  | for (const auto &Rule : PragmaAttributeSupport.Rules) { | 
|  | if (Rule.isAbstractRule()) { | 
|  | OS << "  case " << Rule.getEnumValue() << ":\n"; | 
|  | OS << "    assert(false && \"Abstract matcher rule isn't allowed\");\n"; | 
|  | OS << "    return false;\n"; | 
|  | continue; | 
|  | } | 
|  | std::vector<Record *> Subjects = Rule.getSubjects(); | 
|  | assert(!Subjects.empty() && "Missing subjects"); | 
|  | OS << "  case " << Rule.getEnumValue() << ":\n"; | 
|  | OS << "    return "; | 
|  | for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { | 
|  | // If the subject has custom code associated with it, use the function | 
|  | // that was generated for GenerateAppertainsTo to check if the declaration | 
|  | // is valid. | 
|  | if ((*I)->isSubClassOf("SubsetSubject")) | 
|  | OS << functionNameForCustomAppertainsTo(**I) << "(D)"; | 
|  | else | 
|  | OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)"; | 
|  |  | 
|  | if (I + 1 != E) | 
|  | OS << " || "; | 
|  | } | 
|  | OS << ";\n"; | 
|  | } | 
|  | OS << "  }\n"; | 
|  | OS << "  llvm_unreachable(\"Invalid match rule\");\nreturn false;\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { | 
|  | OS << "static bool defaultDiagnoseLangOpts(Sema &, "; | 
|  | OS << "const AttributeList &) {\n"; | 
|  | OS << "  return true;\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | static std::string GenerateLangOptRequirements(const Record &R, | 
|  | raw_ostream &OS) { | 
|  | // If the attribute has an empty or unset list of language requirements, | 
|  | // return the default handler. | 
|  | std::vector<Record *> LangOpts = R.getValueAsListOfDefs("LangOpts"); | 
|  | if (LangOpts.empty()) | 
|  | return "defaultDiagnoseLangOpts"; | 
|  |  | 
|  | // Generate the test condition, as well as 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", Test; | 
|  | for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { | 
|  | const StringRef Part = (*I)->getValueAsString("Name"); | 
|  | if ((*I)->getValueAsBit("Negated")) { | 
|  | FnName += "Not"; | 
|  | Test += "!"; | 
|  | } | 
|  | Test += "S.LangOpts."; | 
|  | Test +=  Part; | 
|  | if (I + 1 != E) | 
|  | Test += " || "; | 
|  | FnName += Part; | 
|  | } | 
|  | 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 AttributeList &Attr) {\n"; | 
|  | OS << "  if (" << Test << ")\n"; | 
|  | OS << "    return true;\n\n"; | 
|  | OS << "  S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; | 
|  | OS << "<< Attr.getName();\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 | 
|  | // target handler. | 
|  | if (!Attr.isSubClassOf("TargetSpecificAttr")) | 
|  | return "defaultTargetRequirements"; | 
|  |  | 
|  | // Get the list of architectures to be tested for. | 
|  | const Record *R = Attr.getValueAsDef("Target"); | 
|  | std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches"); | 
|  |  | 
|  | // If there are other attributes which share the same parsed attribute kind, | 
|  | // such as target-specific attributes with a shared spelling, collapse the | 
|  | // duplicate architectures. This is required because a shared target-specific | 
|  | // attribute has only one AttributeList::Kind enumeration value, but it | 
|  | // applies to multiple target architectures. In order for the attribute to be | 
|  | // considered valid, all of its architectures need to be included. | 
|  | if (!Attr.isValueUnset("ParseKind")) { | 
|  | const StringRef APK = Attr.getValueAsString("ParseKind"); | 
|  | for (const auto &I : Dupes) { | 
|  | if (I.first == APK) { | 
|  | std::vector<StringRef> DA = | 
|  | I.second->getValueAsDef("Target")->getValueAsListOfStrings( | 
|  | "Arches"); | 
|  | Arches.insert(Arches.end(), DA.begin(), DA.end()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string FnName = "isTarget"; | 
|  | std::string Test; | 
|  | 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 << "  const llvm::Triple &T = Target.getTriple();\n"; | 
|  | OS << "  return " << Test << ";\n"; | 
|  | OS << "}\n\n"; | 
|  |  | 
|  | CustomTargetSet.insert(FnName); | 
|  | return FnName; | 
|  | } | 
|  |  | 
|  | static void GenerateDefaultSpellingIndexToSemanticSpelling(raw_ostream &OS) { | 
|  | OS << "static unsigned defaultSpellingIndexToSemanticSpelling(" | 
|  | << "const AttributeList &Attr) {\n"; | 
|  | OS << "  return UINT_MAX;\n"; | 
|  | OS << "}\n\n"; | 
|  | } | 
|  |  | 
|  | static std::string 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"; | 
|  |  | 
|  | 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"; | 
|  |  | 
|  | // 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 AttributeList &Attr) {\n"; | 
|  | OS << Enum; | 
|  | OS << "  unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; | 
|  | WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS); | 
|  | OS << "}\n\n"; | 
|  |  | 
|  | return Name; | 
|  | } | 
|  |  | 
|  | static bool IsKnownToGCC(const Record &Attr) { | 
|  | // Look at the spellings for this subject; if there are any spellings which | 
|  | // claim to be known to GCC, the attribute is known to GCC. | 
|  | return llvm::any_of( | 
|  | GetFlattenedSpellings(Attr), | 
|  | [](const FlattenedSpelling &S) { return S.knownToGCC(); }); | 
|  | } | 
|  |  | 
|  | /// Emits the parsed attribute helpers | 
|  | void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Parsed attribute helpers", OS); | 
|  |  | 
|  | PragmaClangAttributeSupport &PragmaAttributeSupport = | 
|  | getPragmaAttributeSupport(Records); | 
|  |  | 
|  | // Get the list of parsed attributes, and accept the optional list of | 
|  | // duplicates due to the ParseKind. | 
|  | 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}; | 
|  | 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. | 
|  | // It would be beneficial to test whether the duplicates are "similar | 
|  | // enough" to each other to not cause problems. For instance, check that | 
|  | // the spellings are identical, and custom parsing rules match, etc. | 
|  |  | 
|  | // We need to generate struct instances based off ParsedAttrInfo from | 
|  | // AttributeList.cpp. | 
|  | SS << "  { "; | 
|  | emitArgInfo(*I->second, SS); | 
|  | SS << ", " << I->second->getValueAsBit("HasCustomParsing"); | 
|  | SS << ", " << I->second->isSubClassOf("TargetSpecificAttr"); | 
|  | SS << ", " << I->second->isSubClassOf("TypeAttr"); | 
|  | 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"; | 
|  | } | 
|  |  | 
|  | OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n"; | 
|  | OS << SS.str(); | 
|  | OS << "};\n\n"; | 
|  |  | 
|  | // Generate the attribute match rules. | 
|  | emitAttributeMatchRules(PragmaAttributeSupport, OS); | 
|  | } | 
|  |  | 
|  | // Emits the kind list of parsed attributes | 
|  | void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Attribute name matcher", OS); | 
|  |  | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  | std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11, | 
|  | Keywords, Pragma, C2x; | 
|  | std::set<std::string> Seen; | 
|  | for (const auto *A : Attrs) { | 
|  | const Record &Attr = *A; | 
|  |  | 
|  | bool SemaHandler = Attr.getValueAsBit("SemaHandler"); | 
|  | bool Ignored = Attr.getValueAsBit("Ignored"); | 
|  | if (SemaHandler || Ignored) { | 
|  | // Attribute spellings can be shared between target-specific attributes, | 
|  | // and can be shared between syntaxes for the same attribute. For | 
|  | // instance, an attribute can be spelled GNU<"interrupt"> for an ARM- | 
|  | // specific attribute, or MSP430-specific attribute. Additionally, an | 
|  | // attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport"> | 
|  | // for the same semantic attribute. Ultimately, we need to map each of | 
|  | // these to a single AttributeList::Kind value, but the StringMatcher | 
|  | // class cannot handle duplicate match strings. So we generate a list of | 
|  | // string to match based on the syntax, and emit multiple string matchers | 
|  | // depending on the syntax used. | 
|  | std::string AttrName; | 
|  | if (Attr.isSubClassOf("TargetSpecificAttr") && | 
|  | !Attr.isValueUnset("ParseKind")) { | 
|  | AttrName = Attr.getValueAsString("ParseKind"); | 
|  | if (Seen.find(AttrName) != Seen.end()) | 
|  | continue; | 
|  | Seen.insert(AttrName); | 
|  | } else | 
|  | AttrName = NormalizeAttrName(StringRef(Attr.getName())).str(); | 
|  |  | 
|  | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); | 
|  | for (const auto &S : Spellings) { | 
|  | const std::string &RawSpelling = S.name(); | 
|  | std::vector<StringMatcher::StringPair> *Matches = nullptr; | 
|  | std::string Spelling; | 
|  | const std::string &Variety = S.variety(); | 
|  | if (Variety == "CXX11") { | 
|  | Matches = &CXX11; | 
|  | Spelling += S.nameSpace(); | 
|  | Spelling += "::"; | 
|  | } else if (Variety == "C2x") { | 
|  | Matches = &C2x; | 
|  | Spelling += S.nameSpace(); | 
|  | Spelling += "::"; | 
|  | } else if (Variety == "GNU") | 
|  | Matches = &GNU; | 
|  | else if (Variety == "Declspec") | 
|  | Matches = &Declspec; | 
|  | else if (Variety == "Microsoft") | 
|  | Matches = &Microsoft; | 
|  | else if (Variety == "Keyword") | 
|  | Matches = &Keywords; | 
|  | else if (Variety == "Pragma") | 
|  | Matches = &Pragma; | 
|  |  | 
|  | assert(Matches && "Unsupported spelling variety found"); | 
|  |  | 
|  | if (Variety == "GNU") | 
|  | Spelling += NormalizeGNUAttrSpelling(RawSpelling); | 
|  | else | 
|  | Spelling += RawSpelling; | 
|  |  | 
|  | if (SemaHandler) | 
|  | Matches->push_back(StringMatcher::StringPair(Spelling, | 
|  | "return AttributeList::AT_" + AttrName + ";")); | 
|  | else | 
|  | Matches->push_back(StringMatcher::StringPair(Spelling, | 
|  | "return AttributeList::IgnoredAttribute;")); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | OS << "static AttributeList::Kind getAttrKind(StringRef Name, "; | 
|  | OS << "AttributeList::Syntax Syntax) {\n"; | 
|  | OS << "  if (AttributeList::AS_GNU == Syntax) {\n"; | 
|  | StringMatcher("Name", GNU, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_Declspec == Syntax) {\n"; | 
|  | StringMatcher("Name", Declspec, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_Microsoft == Syntax) {\n"; | 
|  | StringMatcher("Name", Microsoft, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_CXX11 == Syntax) {\n"; | 
|  | StringMatcher("Name", CXX11, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_C2x == Syntax) {\n"; | 
|  | StringMatcher("Name", C2x, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_Keyword == Syntax || "; | 
|  | OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n"; | 
|  | StringMatcher("Name", Keywords, OS).Emit(); | 
|  | OS << "  } else if (AttributeList::AS_Pragma == Syntax) {\n"; | 
|  | StringMatcher("Name", Pragma, OS).Emit(); | 
|  | OS << "  }\n"; | 
|  | OS << "  return AttributeList::UnknownAttribute;\n" | 
|  | << "}\n"; | 
|  | } | 
|  |  | 
|  | // Emits the code to dump an attribute. | 
|  | void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) { | 
|  | emitSourceFileHeader("Attribute 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::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); | 
|  | if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings)) | 
|  | OS << "    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 *AI : Args) | 
|  | createArgument(*AI, R.getName())->writeDumpChildren(OS); | 
|  | } | 
|  | OS << | 
|  | "    break;\n" | 
|  | "  }\n"; | 
|  | } | 
|  | OS << "  }\n"; | 
|  | } | 
|  |  | 
|  | void EmitClangAttrParserStringSwitches(RecordKeeper &Records, | 
|  | raw_ostream &OS) { | 
|  | emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS); | 
|  | emitClangAttrArgContextList(Records, OS); | 
|  | emitClangAttrIdentifierArgList(Records, OS); | 
|  | emitClangAttrTypeArgList(Records, OS); | 
|  | emitClangAttrLateParsedList(Records, OS); | 
|  | } | 
|  |  | 
|  | void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, | 
|  | raw_ostream &OS) { | 
|  | getPragmaAttributeSupport(Records).generateParsingHelpers(OS); | 
|  | } | 
|  |  | 
|  | class DocumentationData { | 
|  | public: | 
|  | const Record *Documentation; | 
|  | const Record *Attribute; | 
|  | std::string Heading; | 
|  | unsigned SupportedSpellings; | 
|  |  | 
|  | DocumentationData(const Record &Documentation, const Record &Attribute, | 
|  | const std::pair<std::string, unsigned> HeadingAndKinds) | 
|  | : Documentation(&Documentation), Attribute(&Attribute), | 
|  | Heading(std::move(HeadingAndKinds.first)), | 
|  | SupportedSpellings(HeadingAndKinds.second) {} | 
|  | }; | 
|  |  | 
|  | static void WriteCategoryHeader(const Record *DocCategory, | 
|  | raw_ostream &OS) { | 
|  | const StringRef Name = DocCategory->getValueAsString("Name"); | 
|  | OS << Name << "\n" << std::string(Name.size(), '=') << "\n"; | 
|  |  | 
|  | // If there is content, print that as well. | 
|  | const StringRef ContentStr = DocCategory->getValueAsString("Content"); | 
|  | // Trim leading and trailing newlines and spaces. | 
|  | OS << ContentStr.trim(); | 
|  |  | 
|  | 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) { | 
|  | // 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); | 
|  |  | 
|  | // 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) | 
|  | Heading = Spellings.begin()->name(); | 
|  | else { | 
|  | 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()); | 
|  | Uniques.insert(Spelling); | 
|  | } | 
|  | // If the semantic map has only one spelling, that is sufficient for our | 
|  | // needs. | 
|  | if (Uniques.size() == 1) | 
|  | Heading = *Uniques.begin(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If the heading is still empty, it is an error. | 
|  | if (Heading.empty()) | 
|  | 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; | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | static void WriteDocumentation(RecordKeeper &Records, | 
|  | const DocumentationData &Doc, raw_ostream &OS) { | 
|  | OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n"; | 
|  |  | 
|  | // 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 << "   \""; | 
|  | 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"; | 
|  | OS << "\"\n\n"; | 
|  |  | 
|  | // If the attribute is deprecated, print a message about it, and possibly | 
|  | // provide a replacement attribute. | 
|  | if (!Doc.Documentation->isValueUnset("Deprecated")) { | 
|  | OS << "This attribute has been deprecated, and may be removed in a future " | 
|  | << "version of Clang."; | 
|  | const Record &Deprecated = *Doc.Documentation->getValueAsDef("Deprecated"); | 
|  | const StringRef Replacement = Deprecated.getValueAsString("Replacement"); | 
|  | if (!Replacement.empty()) | 
|  | OS << "  This attribute has been superseded by ``" << Replacement | 
|  | << "``."; | 
|  | OS << "\n\n"; | 
|  | } | 
|  |  | 
|  | const StringRef ContentStr = Doc.Documentation->getValueAsString("Content"); | 
|  | // Trim leading and trailing newlines and spaces. | 
|  | OS << ContentStr.trim(); | 
|  |  | 
|  | OS << "\n\n\n"; | 
|  | } | 
|  |  | 
|  | void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { | 
|  | // Get the documentation introduction paragraph. | 
|  | const Record *Documentation = Records.getDef("GlobalDocumentation"); | 
|  | if (!Documentation) { | 
|  | PrintFatalError("The Documentation top-level definition is missing, " | 
|  | "no documentation will be generated."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | OS << Documentation->getValueAsString("Intro") << "\n"; | 
|  |  | 
|  | // Gather the Documentation lists from each of the attributes, based on the | 
|  | // category provided. | 
|  | std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); | 
|  | std::map<const Record *, std::vector<DocumentationData>> SplitDocs; | 
|  | for (const auto *A : Attrs) { | 
|  | const Record &Attr = *A; | 
|  | std::vector<Record *> Docs = Attr.getValueAsListOfDefs("Documentation"); | 
|  | for (const auto *D : Docs) { | 
|  | const Record &Doc = *D; | 
|  | const Record *Category = Doc.getValueAsDef("Category"); | 
|  | // If the category is "undocumented", then there cannot be any other | 
|  | // documentation categories (otherwise, the attribute would become | 
|  | // documented). | 
|  | const StringRef Cat = Category->getValueAsString("Name"); | 
|  | bool Undocumented = Cat == "Undocumented"; | 
|  | if (Undocumented && Docs.size() > 1) | 
|  | PrintFatalError(Doc.getLoc(), | 
|  | "Attribute is \"Undocumented\", but has multiple " | 
|  | "documentation categories"); | 
|  |  | 
|  | if (!Undocumented) | 
|  | SplitDocs[Category].push_back(DocumentationData( | 
|  | Doc, Attr, GetAttributeHeadingAndSpellingKinds(Doc, Attr))); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Having split the attributes out based on what documentation goes where, | 
|  | // we can begin to generate sections of documentation. | 
|  | for (auto &I : SplitDocs) { | 
|  | WriteCategoryHeader(I.first, OS); | 
|  |  | 
|  | llvm::sort(I.second.begin(), I.second.end(), | 
|  | [](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. | 
|  | for (const auto &Doc : I.second) | 
|  | WriteDocumentation(Records, Doc, OS); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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"; | 
|  | for (const auto &I : Attrs) { | 
|  | if (!Support.isAttributedSupported(*I.second)) | 
|  | continue; | 
|  | OS << I.first; | 
|  | if (I.second->isValueUnset("Subjects")) { | 
|  | OS << " ()\n"; | 
|  | continue; | 
|  | } | 
|  | const Record *SubjectObj = I.second->getValueAsDef("Subjects"); | 
|  | std::vector<Record *> Subjects = | 
|  | SubjectObj->getValueAsListOfDefs("Subjects"); | 
|  | OS << " ("; | 
|  | for (const auto &Subject : llvm::enumerate(Subjects)) { | 
|  | if (Subject.index()) | 
|  | OS << ", "; | 
|  | PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = | 
|  | Support.SubjectsToRules.find(Subject.value())->getSecond(); | 
|  | if (RuleSet.isRule()) { | 
|  | OS << RuleSet.getRule().getEnumValueName(); | 
|  | continue; | 
|  | } | 
|  | OS << "("; | 
|  | for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) { | 
|  | if (Rule.index()) | 
|  | OS << ", "; | 
|  | OS << Rule.value().getEnumValueName(); | 
|  | } | 
|  | OS << ")"; | 
|  | } | 
|  | OS << ")\n"; | 
|  | } | 
|  | } | 
|  |  | 
|  | } // end namespace clang |