10b57cec5SDimitry Andric //===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // These tablegen backends emit Clang attribute processing code 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 13a7dea167SDimitry Andric #include "TableGenBackends.h" 14480093f4SDimitry Andric #include "ASTTableGen.h" 15a7dea167SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 170b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 180b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 19349cc55cSDimitry Andric #include "llvm/ADT/MapVector.h" 200b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 220b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 240b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h" 250b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 260b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h" 270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 290b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 300b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 310b57cec5SDimitry Andric #include "llvm/TableGen/StringMatcher.h" 320b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 330b57cec5SDimitry Andric #include <algorithm> 340b57cec5SDimitry Andric #include <cassert> 350b57cec5SDimitry Andric #include <cctype> 360b57cec5SDimitry Andric #include <cstddef> 370b57cec5SDimitry Andric #include <cstdint> 380b57cec5SDimitry Andric #include <map> 390b57cec5SDimitry Andric #include <memory> 40bdd1243dSDimitry Andric #include <optional> 410b57cec5SDimitry Andric #include <set> 420b57cec5SDimitry Andric #include <sstream> 430b57cec5SDimitry Andric #include <string> 440b57cec5SDimitry Andric #include <utility> 450b57cec5SDimitry Andric #include <vector> 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric using namespace llvm; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric namespace { 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric class FlattenedSpelling { 520b57cec5SDimitry Andric std::string V, N, NS; 535ffd83dbSDimitry Andric bool K = false; 5406c3fb27SDimitry Andric const Record &OriginalSpelling; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric public: 570b57cec5SDimitry Andric FlattenedSpelling(const std::string &Variety, const std::string &Name, 5806c3fb27SDimitry Andric const std::string &Namespace, bool KnownToGCC, 5906c3fb27SDimitry Andric const Record &OriginalSpelling) 6006c3fb27SDimitry Andric : V(Variety), N(Name), NS(Namespace), K(KnownToGCC), 6106c3fb27SDimitry Andric OriginalSpelling(OriginalSpelling) {} 625ffd83dbSDimitry Andric explicit FlattenedSpelling(const Record &Spelling) 635ffd83dbSDimitry Andric : V(std::string(Spelling.getValueAsString("Variety"))), 6406c3fb27SDimitry Andric N(std::string(Spelling.getValueAsString("Name"))), 6506c3fb27SDimitry Andric OriginalSpelling(Spelling) { 660b57cec5SDimitry Andric assert(V != "GCC" && V != "Clang" && 670b57cec5SDimitry Andric "Given a GCC spelling, which means this hasn't been flattened!"); 685f757f3fSDimitry Andric if (V == "CXX11" || V == "C23" || V == "Pragma") 695ffd83dbSDimitry Andric NS = std::string(Spelling.getValueAsString("Namespace")); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric const std::string &variety() const { return V; } 730b57cec5SDimitry Andric const std::string &name() const { return N; } 740b57cec5SDimitry Andric const std::string &nameSpace() const { return NS; } 750b57cec5SDimitry Andric bool knownToGCC() const { return K; } 7606c3fb27SDimitry Andric const Record &getSpellingRecord() const { return OriginalSpelling; } 770b57cec5SDimitry Andric }; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric } // end anonymous namespace 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric static std::vector<FlattenedSpelling> 820b57cec5SDimitry Andric GetFlattenedSpellings(const Record &Attr) { 830b57cec5SDimitry Andric std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings"); 840b57cec5SDimitry Andric std::vector<FlattenedSpelling> Ret; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric for (const auto &Spelling : Spellings) { 870b57cec5SDimitry Andric StringRef Variety = Spelling->getValueAsString("Variety"); 880b57cec5SDimitry Andric StringRef Name = Spelling->getValueAsString("Name"); 890b57cec5SDimitry Andric if (Variety == "GCC") { 9006c3fb27SDimitry Andric Ret.emplace_back("GNU", std::string(Name), "", true, *Spelling); 9106c3fb27SDimitry Andric Ret.emplace_back("CXX11", std::string(Name), "gnu", true, *Spelling); 920b57cec5SDimitry Andric if (Spelling->getValueAsBit("AllowInC")) 935f757f3fSDimitry Andric Ret.emplace_back("C23", std::string(Name), "gnu", true, *Spelling); 945ffd83dbSDimitry Andric } else if (Variety == "Clang") { 9506c3fb27SDimitry Andric Ret.emplace_back("GNU", std::string(Name), "", false, *Spelling); 9606c3fb27SDimitry Andric Ret.emplace_back("CXX11", std::string(Name), "clang", false, *Spelling); 975ffd83dbSDimitry Andric if (Spelling->getValueAsBit("AllowInC")) 985f757f3fSDimitry Andric Ret.emplace_back("C23", std::string(Name), "clang", false, *Spelling); 990b57cec5SDimitry Andric } else 1000b57cec5SDimitry Andric Ret.push_back(FlattenedSpelling(*Spelling)); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric return Ret; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric static std::string ReadPCHRecord(StringRef type) { 1070b57cec5SDimitry Andric return StringSwitch<std::string>(type) 108*0fca6ea1SDimitry Andric .EndsWith("Decl *", "Record.readDeclAs<" + 1095ffd83dbSDimitry Andric std::string(type.data(), 0, type.size() - 1) + 110*0fca6ea1SDimitry Andric ">()") 111480093f4SDimitry Andric .Case("TypeSourceInfo *", "Record.readTypeSourceInfo()") 1120b57cec5SDimitry Andric .Case("Expr *", "Record.readExpr()") 113480093f4SDimitry Andric .Case("IdentifierInfo *", "Record.readIdentifier()") 1140b57cec5SDimitry Andric .Case("StringRef", "Record.readString()") 1150b57cec5SDimitry Andric .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())") 1165ffd83dbSDimitry Andric .Case("OMPTraitInfo *", "Record.readOMPTraitInfo()") 1170b57cec5SDimitry Andric .Default("Record.readInt()"); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Get a type that is suitable for storing an object of the specified type. 1210b57cec5SDimitry Andric static StringRef getStorageType(StringRef type) { 1220b57cec5SDimitry Andric return StringSwitch<StringRef>(type) 1230b57cec5SDimitry Andric .Case("StringRef", "std::string") 1240b57cec5SDimitry Andric .Default(type); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric // Assumes that the way to get the value is SA->getname() 1280b57cec5SDimitry Andric static std::string WritePCHRecord(StringRef type, StringRef name) { 1295ffd83dbSDimitry Andric return "Record." + 1305ffd83dbSDimitry Andric StringSwitch<std::string>(type) 1310b57cec5SDimitry Andric .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ");\n") 1325ffd83dbSDimitry Andric .Case("TypeSourceInfo *", 1335ffd83dbSDimitry Andric "AddTypeSourceInfo(" + std::string(name) + ");\n") 1340b57cec5SDimitry Andric .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") 1355ffd83dbSDimitry Andric .Case("IdentifierInfo *", 1365ffd83dbSDimitry Andric "AddIdentifierRef(" + std::string(name) + ");\n") 1370b57cec5SDimitry Andric .Case("StringRef", "AddString(" + std::string(name) + ");\n") 1385ffd83dbSDimitry Andric .Case("ParamIdx", 1395ffd83dbSDimitry Andric "push_back(" + std::string(name) + ".serialize());\n") 1405ffd83dbSDimitry Andric .Case("OMPTraitInfo *", 1415ffd83dbSDimitry Andric "writeOMPTraitInfo(" + std::string(name) + ");\n") 1420b57cec5SDimitry Andric .Default("push_back(" + std::string(name) + ");\n"); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // Normalize attribute name by removing leading and trailing 1460b57cec5SDimitry Andric // underscores. For example, __foo, foo__, __foo__ would 1470b57cec5SDimitry Andric // become foo. 1480b57cec5SDimitry Andric static StringRef NormalizeAttrName(StringRef AttrName) { 1490b57cec5SDimitry Andric AttrName.consume_front("__"); 1500b57cec5SDimitry Andric AttrName.consume_back("__"); 1510b57cec5SDimitry Andric return AttrName; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Normalize the name by removing any and all leading and trailing underscores. 1550b57cec5SDimitry Andric // This is different from NormalizeAttrName in that it also handles names like 1560b57cec5SDimitry Andric // _pascal and __pascal. 1570b57cec5SDimitry Andric static StringRef NormalizeNameForSpellingComparison(StringRef Name) { 1580b57cec5SDimitry Andric return Name.trim("_"); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // Normalize the spelling of a GNU attribute (i.e. "x" in "__attribute__((x))"), 1620b57cec5SDimitry Andric // removing "__" if it appears at the beginning and end of the attribute's name. 1630b57cec5SDimitry Andric static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) { 1645f757f3fSDimitry Andric if (AttrSpelling.starts_with("__") && AttrSpelling.ends_with("__")) { 1650b57cec5SDimitry Andric AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric return AttrSpelling; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric typedef std::vector<std::pair<std::string, const Record *>> ParsedAttrMap; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, 174*0fca6ea1SDimitry Andric ParsedAttrMap *Dupes = nullptr, 175*0fca6ea1SDimitry Andric bool SemaOnly = true) { 1760b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 1770b57cec5SDimitry Andric std::set<std::string> Seen; 1780b57cec5SDimitry Andric ParsedAttrMap R; 1790b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 180*0fca6ea1SDimitry Andric if (!SemaOnly || Attr->getValueAsBit("SemaHandler")) { 1810b57cec5SDimitry Andric std::string AN; 1820b57cec5SDimitry Andric if (Attr->isSubClassOf("TargetSpecificAttr") && 1830b57cec5SDimitry Andric !Attr->isValueUnset("ParseKind")) { 1845ffd83dbSDimitry Andric AN = std::string(Attr->getValueAsString("ParseKind")); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric // If this attribute has already been handled, it does not need to be 1870b57cec5SDimitry Andric // handled again. 1880b57cec5SDimitry Andric if (Seen.find(AN) != Seen.end()) { 1890b57cec5SDimitry Andric if (Dupes) 1900b57cec5SDimitry Andric Dupes->push_back(std::make_pair(AN, Attr)); 1910b57cec5SDimitry Andric continue; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric Seen.insert(AN); 1940b57cec5SDimitry Andric } else 1950b57cec5SDimitry Andric AN = NormalizeAttrName(Attr->getName()).str(); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric R.push_back(std::make_pair(AN, Attr)); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric return R; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric namespace { 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric class Argument { 2060b57cec5SDimitry Andric std::string lowerName, upperName; 2070b57cec5SDimitry Andric StringRef attrName; 2080b57cec5SDimitry Andric bool isOpt; 2090b57cec5SDimitry Andric bool Fake; 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric public: 21281ad6265SDimitry Andric Argument(StringRef Arg, StringRef Attr) 21381ad6265SDimitry Andric : lowerName(std::string(Arg)), upperName(lowerName), attrName(Attr), 21481ad6265SDimitry Andric isOpt(false), Fake(false) { 2150b57cec5SDimitry Andric if (!lowerName.empty()) { 2160b57cec5SDimitry Andric lowerName[0] = std::tolower(lowerName[0]); 2170b57cec5SDimitry Andric upperName[0] = std::toupper(upperName[0]); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric // Work around MinGW's macro definition of 'interface' to 'struct'. We 2200b57cec5SDimitry Andric // have an attribute argument called 'Interface', so only the lower case 2210b57cec5SDimitry Andric // name conflicts with the macro definition. 2220b57cec5SDimitry Andric if (lowerName == "interface") 2230b57cec5SDimitry Andric lowerName = "interface_"; 2240b57cec5SDimitry Andric } 22581ad6265SDimitry Andric Argument(const Record &Arg, StringRef Attr) 22681ad6265SDimitry Andric : Argument(Arg.getValueAsString("Name"), Attr) {} 2270b57cec5SDimitry Andric virtual ~Argument() = default; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric StringRef getLowerName() const { return lowerName; } 2300b57cec5SDimitry Andric StringRef getUpperName() const { return upperName; } 2310b57cec5SDimitry Andric StringRef getAttrName() const { return attrName; } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric bool isOptional() const { return isOpt; } 2340b57cec5SDimitry Andric void setOptional(bool set) { isOpt = set; } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric bool isFake() const { return Fake; } 2370b57cec5SDimitry Andric void setFake(bool fake) { Fake = fake; } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric // These functions print the argument contents formatted in different ways. 2400b57cec5SDimitry Andric virtual void writeAccessors(raw_ostream &OS) const = 0; 2410b57cec5SDimitry Andric virtual void writeAccessorDefinitions(raw_ostream &OS) const {} 2420b57cec5SDimitry Andric virtual void writeASTVisitorTraversal(raw_ostream &OS) const {} 2430b57cec5SDimitry Andric virtual void writeCloneArgs(raw_ostream &OS) const = 0; 2440b57cec5SDimitry Andric virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; 2450b57cec5SDimitry Andric virtual void writeTemplateInstantiation(raw_ostream &OS) const {} 2460b57cec5SDimitry Andric virtual void writeCtorBody(raw_ostream &OS) const {} 2470b57cec5SDimitry Andric virtual void writeCtorInitializers(raw_ostream &OS) const = 0; 2480b57cec5SDimitry Andric virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0; 2490b57cec5SDimitry Andric virtual void writeCtorParameters(raw_ostream &OS) const = 0; 2500b57cec5SDimitry Andric virtual void writeDeclarations(raw_ostream &OS) const = 0; 2510b57cec5SDimitry Andric virtual void writePCHReadArgs(raw_ostream &OS) const = 0; 2520b57cec5SDimitry Andric virtual void writePCHReadDecls(raw_ostream &OS) const = 0; 2530b57cec5SDimitry Andric virtual void writePCHWrite(raw_ostream &OS) const = 0; 2540b57cec5SDimitry Andric virtual std::string getIsOmitted() const { return "false"; } 2550b57cec5SDimitry Andric virtual void writeValue(raw_ostream &OS) const = 0; 2560b57cec5SDimitry Andric virtual void writeDump(raw_ostream &OS) const = 0; 2570b57cec5SDimitry Andric virtual void writeDumpChildren(raw_ostream &OS) const {} 2580b57cec5SDimitry Andric virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; } 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric virtual bool isEnumArg() const { return false; } 2610b57cec5SDimitry Andric virtual bool isVariadicEnumArg() const { return false; } 2620b57cec5SDimitry Andric virtual bool isVariadic() const { return false; } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric virtual void writeImplicitCtorArgs(raw_ostream &OS) const { 2650b57cec5SDimitry Andric OS << getUpperName(); 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric }; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric class SimpleArgument : public Argument { 2700b57cec5SDimitry Andric std::string type; 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric public: 2730b57cec5SDimitry Andric SimpleArgument(const Record &Arg, StringRef Attr, std::string T) 2740b57cec5SDimitry Andric : Argument(Arg, Attr), type(std::move(T)) {} 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric std::string getType() const { return type; } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 2790b57cec5SDimitry Andric OS << " " << type << " get" << getUpperName() << "() const {\n"; 2800b57cec5SDimitry Andric OS << " return " << getLowerName() << ";\n"; 2810b57cec5SDimitry Andric OS << " }"; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 2850b57cec5SDimitry Andric OS << getLowerName(); 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 2890b57cec5SDimitry Andric OS << "A->get" << getUpperName() << "()"; 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 2930b57cec5SDimitry Andric OS << getLowerName() << "(" << getUpperName() << ")"; 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 2970b57cec5SDimitry Andric OS << getLowerName() << "()"; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 3010b57cec5SDimitry Andric OS << type << " " << getUpperName(); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 3050b57cec5SDimitry Andric OS << type << " " << getLowerName() << ";"; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 3090b57cec5SDimitry Andric std::string read = ReadPCHRecord(type); 3100b57cec5SDimitry Andric OS << " " << type << " " << getLowerName() << " = " << read << ";\n"; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 3140b57cec5SDimitry Andric OS << getLowerName(); 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 3185ffd83dbSDimitry Andric OS << " " 3195ffd83dbSDimitry Andric << WritePCHRecord(type, 3205ffd83dbSDimitry Andric "SA->get" + std::string(getUpperName()) + "()"); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric std::string getIsOmitted() const override { 3245f757f3fSDimitry Andric auto IsOneOf = [](StringRef subject, auto... list) { 3255f757f3fSDimitry Andric return ((subject == list) || ...); 3265f757f3fSDimitry Andric }; 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric if (IsOneOf(type, "IdentifierInfo *", "Expr *")) 3290b57cec5SDimitry Andric return "!get" + getUpperName().str() + "()"; 3305f757f3fSDimitry Andric if (IsOneOf(type, "TypeSourceInfo *")) 331a7dea167SDimitry Andric return "!get" + getUpperName().str() + "Loc()"; 3325f757f3fSDimitry Andric if (IsOneOf(type, "ParamIdx")) 3330b57cec5SDimitry Andric return "!get" + getUpperName().str() + "().isValid()"; 3345f757f3fSDimitry Andric 3355f757f3fSDimitry Andric assert(IsOneOf(type, "unsigned", "int", "bool", "FunctionDecl *", 3365f757f3fSDimitry Andric "VarDecl *")); 3370b57cec5SDimitry Andric return "false"; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 3410b57cec5SDimitry Andric if (type == "FunctionDecl *") 3420b57cec5SDimitry Andric OS << "\" << get" << getUpperName() 3430b57cec5SDimitry Andric << "()->getNameInfo().getAsString() << \""; 3440b57cec5SDimitry Andric else if (type == "IdentifierInfo *") 3450b57cec5SDimitry Andric // Some non-optional (comma required) identifier arguments can be the 3460b57cec5SDimitry Andric // empty string but are then recorded as a nullptr. 3470b57cec5SDimitry Andric OS << "\" << (get" << getUpperName() << "() ? get" << getUpperName() 3480b57cec5SDimitry Andric << "()->getName() : \"\") << \""; 349e8d8bef9SDimitry Andric else if (type == "VarDecl *") 350e8d8bef9SDimitry Andric OS << "\" << get" << getUpperName() << "()->getName() << \""; 3510b57cec5SDimitry Andric else if (type == "TypeSourceInfo *") 3520b57cec5SDimitry Andric OS << "\" << get" << getUpperName() << "().getAsString() << \""; 3530b57cec5SDimitry Andric else if (type == "ParamIdx") 3540b57cec5SDimitry Andric OS << "\" << get" << getUpperName() << "().getSourceIndex() << \""; 3550b57cec5SDimitry Andric else 3560b57cec5SDimitry Andric OS << "\" << get" << getUpperName() << "() << \""; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 3605f757f3fSDimitry Andric if (StringRef(type).ends_with("Decl *")) { 3610b57cec5SDimitry Andric OS << " OS << \" \";\n"; 3620b57cec5SDimitry Andric OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; 3630b57cec5SDimitry Andric } else if (type == "IdentifierInfo *") { 3640b57cec5SDimitry Andric // Some non-optional (comma required) identifier arguments can be the 3650b57cec5SDimitry Andric // empty string but are then recorded as a nullptr. 3660b57cec5SDimitry Andric OS << " if (SA->get" << getUpperName() << "())\n" 3670b57cec5SDimitry Andric << " OS << \" \" << SA->get" << getUpperName() 3680b57cec5SDimitry Andric << "()->getName();\n"; 3690b57cec5SDimitry Andric } else if (type == "TypeSourceInfo *") { 370a7dea167SDimitry Andric if (isOptional()) 371a7dea167SDimitry Andric OS << " if (SA->get" << getUpperName() << "Loc())"; 3720b57cec5SDimitry Andric OS << " OS << \" \" << SA->get" << getUpperName() 3730b57cec5SDimitry Andric << "().getAsString();\n"; 3740b57cec5SDimitry Andric } else if (type == "bool") { 3750b57cec5SDimitry Andric OS << " if (SA->get" << getUpperName() << "()) OS << \" " 3760b57cec5SDimitry Andric << getUpperName() << "\";\n"; 3770b57cec5SDimitry Andric } else if (type == "int" || type == "unsigned") { 3780b57cec5SDimitry Andric OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; 3790b57cec5SDimitry Andric } else if (type == "ParamIdx") { 3800b57cec5SDimitry Andric if (isOptional()) 3810b57cec5SDimitry Andric OS << " if (SA->get" << getUpperName() << "().isValid())\n "; 3820b57cec5SDimitry Andric OS << " OS << \" \" << SA->get" << getUpperName() 3830b57cec5SDimitry Andric << "().getSourceIndex();\n"; 3845ffd83dbSDimitry Andric } else if (type == "OMPTraitInfo *") { 3855ffd83dbSDimitry Andric OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; 3860b57cec5SDimitry Andric } else { 3870b57cec5SDimitry Andric llvm_unreachable("Unknown SimpleArgument type!"); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric }; 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric class DefaultSimpleArgument : public SimpleArgument { 3930b57cec5SDimitry Andric int64_t Default; 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric public: 3960b57cec5SDimitry Andric DefaultSimpleArgument(const Record &Arg, StringRef Attr, 3970b57cec5SDimitry Andric std::string T, int64_t Default) 3980b57cec5SDimitry Andric : SimpleArgument(Arg, Attr, T), Default(Default) {} 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 4010b57cec5SDimitry Andric SimpleArgument::writeAccessors(OS); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric OS << "\n\n static const " << getType() << " Default" << getUpperName() 4040b57cec5SDimitry Andric << " = "; 4050b57cec5SDimitry Andric if (getType() == "bool") 4060b57cec5SDimitry Andric OS << (Default != 0 ? "true" : "false"); 4070b57cec5SDimitry Andric else 4080b57cec5SDimitry Andric OS << Default; 4090b57cec5SDimitry Andric OS << ";"; 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric }; 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric class StringArgument : public Argument { 4140b57cec5SDimitry Andric public: 4150b57cec5SDimitry Andric StringArgument(const Record &Arg, StringRef Attr) 4160b57cec5SDimitry Andric : Argument(Arg, Attr) 4170b57cec5SDimitry Andric {} 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 4200b57cec5SDimitry Andric OS << " llvm::StringRef get" << getUpperName() << "() const {\n"; 4210b57cec5SDimitry Andric OS << " return llvm::StringRef(" << getLowerName() << ", " 4220b57cec5SDimitry Andric << getLowerName() << "Length);\n"; 4230b57cec5SDimitry Andric OS << " }\n"; 4240b57cec5SDimitry Andric OS << " unsigned get" << getUpperName() << "Length() const {\n"; 4250b57cec5SDimitry Andric OS << " return " << getLowerName() << "Length;\n"; 4260b57cec5SDimitry Andric OS << " }\n"; 4270b57cec5SDimitry Andric OS << " void set" << getUpperName() 4280b57cec5SDimitry Andric << "(ASTContext &C, llvm::StringRef S) {\n"; 4290b57cec5SDimitry Andric OS << " " << getLowerName() << "Length = S.size();\n"; 4300b57cec5SDimitry Andric OS << " this->" << getLowerName() << " = new (C, 1) char [" 4310b57cec5SDimitry Andric << getLowerName() << "Length];\n"; 4320b57cec5SDimitry Andric OS << " if (!S.empty())\n"; 4330b57cec5SDimitry Andric OS << " std::memcpy(this->" << getLowerName() << ", S.data(), " 4340b57cec5SDimitry Andric << getLowerName() << "Length);\n"; 4350b57cec5SDimitry Andric OS << " }"; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 4390b57cec5SDimitry Andric OS << "get" << getUpperName() << "()"; 4400b57cec5SDimitry Andric } 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 4430b57cec5SDimitry Andric OS << "A->get" << getUpperName() << "()"; 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric void writeCtorBody(raw_ostream &OS) const override { 4470b57cec5SDimitry Andric OS << " if (!" << getUpperName() << ".empty())\n"; 4480b57cec5SDimitry Andric OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() 4490b57cec5SDimitry Andric << ".data(), " << getLowerName() << "Length);\n"; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 4530b57cec5SDimitry Andric OS << getLowerName() << "Length(" << getUpperName() << ".size())," 4540b57cec5SDimitry Andric << getLowerName() << "(new (Ctx, 1) char[" << getLowerName() 4550b57cec5SDimitry Andric << "Length])"; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 4590b57cec5SDimitry Andric OS << getLowerName() << "Length(0)," << getLowerName() << "(nullptr)"; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 4630b57cec5SDimitry Andric OS << "llvm::StringRef " << getUpperName(); 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 4670b57cec5SDimitry Andric OS << "unsigned " << getLowerName() << "Length;\n"; 4680b57cec5SDimitry Andric OS << "char *" << getLowerName() << ";"; 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 4720b57cec5SDimitry Andric OS << " std::string " << getLowerName() 4730b57cec5SDimitry Andric << "= Record.readString();\n"; 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 4770b57cec5SDimitry Andric OS << getLowerName(); 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 4810b57cec5SDimitry Andric OS << " Record.AddString(SA->get" << getUpperName() << "());\n"; 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 4850b57cec5SDimitry Andric OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 4890b57cec5SDimitry Andric OS << " OS << \" \\\"\" << SA->get" << getUpperName() 4900b57cec5SDimitry Andric << "() << \"\\\"\";\n"; 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric }; 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric class AlignedArgument : public Argument { 4950b57cec5SDimitry Andric public: 4960b57cec5SDimitry Andric AlignedArgument(const Record &Arg, StringRef Attr) 4970b57cec5SDimitry Andric : Argument(Arg, Attr) 4980b57cec5SDimitry Andric {} 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 5010b57cec5SDimitry Andric OS << " bool is" << getUpperName() << "Dependent() const;\n"; 5025ffd83dbSDimitry Andric OS << " bool is" << getUpperName() << "ErrorDependent() const;\n"; 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n"; 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric OS << " bool is" << getUpperName() << "Expr() const {\n"; 5070b57cec5SDimitry Andric OS << " return is" << getLowerName() << "Expr;\n"; 5080b57cec5SDimitry Andric OS << " }\n"; 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric OS << " Expr *get" << getUpperName() << "Expr() const {\n"; 5110b57cec5SDimitry Andric OS << " assert(is" << getLowerName() << "Expr);\n"; 5120b57cec5SDimitry Andric OS << " return " << getLowerName() << "Expr;\n"; 5130b57cec5SDimitry Andric OS << " }\n"; 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n"; 5160b57cec5SDimitry Andric OS << " assert(!is" << getLowerName() << "Expr);\n"; 5170b57cec5SDimitry Andric OS << " return " << getLowerName() << "Type;\n"; 5180b57cec5SDimitry Andric OS << " }"; 51906c3fb27SDimitry Andric 52006c3fb27SDimitry Andric OS << " std::optional<unsigned> getCached" << getUpperName() 52106c3fb27SDimitry Andric << "Value() const {\n"; 52206c3fb27SDimitry Andric OS << " return " << getLowerName() << "Cache;\n"; 52306c3fb27SDimitry Andric OS << " }"; 52406c3fb27SDimitry Andric 52506c3fb27SDimitry Andric OS << " void setCached" << getUpperName() 52606c3fb27SDimitry Andric << "Value(unsigned AlignVal) {\n"; 52706c3fb27SDimitry Andric OS << " " << getLowerName() << "Cache = AlignVal;\n"; 52806c3fb27SDimitry Andric OS << " }"; 5290b57cec5SDimitry Andric } 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric void writeAccessorDefinitions(raw_ostream &OS) const override { 5320b57cec5SDimitry Andric OS << "bool " << getAttrName() << "Attr::is" << getUpperName() 5330b57cec5SDimitry Andric << "Dependent() const {\n"; 5340b57cec5SDimitry Andric OS << " if (is" << getLowerName() << "Expr)\n"; 5350b57cec5SDimitry Andric OS << " return " << getLowerName() << "Expr && (" << getLowerName() 5360b57cec5SDimitry Andric << "Expr->isValueDependent() || " << getLowerName() 5370b57cec5SDimitry Andric << "Expr->isTypeDependent());\n"; 5380b57cec5SDimitry Andric OS << " else\n"; 5390b57cec5SDimitry Andric OS << " return " << getLowerName() 5400b57cec5SDimitry Andric << "Type->getType()->isDependentType();\n"; 5410b57cec5SDimitry Andric OS << "}\n"; 5420b57cec5SDimitry Andric 5435ffd83dbSDimitry Andric OS << "bool " << getAttrName() << "Attr::is" << getUpperName() 5445ffd83dbSDimitry Andric << "ErrorDependent() const {\n"; 5455ffd83dbSDimitry Andric OS << " if (is" << getLowerName() << "Expr)\n"; 5465ffd83dbSDimitry Andric OS << " return " << getLowerName() << "Expr && " << getLowerName() 5475ffd83dbSDimitry Andric << "Expr->containsErrors();\n"; 5485ffd83dbSDimitry Andric OS << " return " << getLowerName() 5495ffd83dbSDimitry Andric << "Type->getType()->containsErrors();\n"; 5505ffd83dbSDimitry Andric OS << "}\n"; 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric void writeASTVisitorTraversal(raw_ostream &OS) const override { 5540b57cec5SDimitry Andric StringRef Name = getUpperName(); 5550b57cec5SDimitry Andric OS << " if (A->is" << Name << "Expr()) {\n" 5560b57cec5SDimitry Andric << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n" 5570b57cec5SDimitry Andric << " return false;\n" 5580b57cec5SDimitry Andric << " } else if (auto *TSI = A->get" << Name << "Type()) {\n" 5590b57cec5SDimitry Andric << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" 5600b57cec5SDimitry Andric << " return false;\n" 5610b57cec5SDimitry Andric << " }\n"; 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 5650b57cec5SDimitry Andric OS << "is" << getLowerName() << "Expr, is" << getLowerName() 5660b57cec5SDimitry Andric << "Expr ? static_cast<void*>(" << getLowerName() 5670b57cec5SDimitry Andric << "Expr) : " << getLowerName() 5680b57cec5SDimitry Andric << "Type"; 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 5720b57cec5SDimitry Andric // FIXME: move the definition in Sema::InstantiateAttrs to here. 5730b57cec5SDimitry Andric // In the meantime, aligned attributes are cloned. 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric void writeCtorBody(raw_ostream &OS) const override { 5770b57cec5SDimitry Andric OS << " if (is" << getLowerName() << "Expr)\n"; 5780b57cec5SDimitry Andric OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>(" 5790b57cec5SDimitry Andric << getUpperName() << ");\n"; 5800b57cec5SDimitry Andric OS << " else\n"; 5810b57cec5SDimitry Andric OS << " " << getLowerName() 5820b57cec5SDimitry Andric << "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName() 5830b57cec5SDimitry Andric << ");\n"; 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 5870b57cec5SDimitry Andric OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)"; 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 5910b57cec5SDimitry Andric OS << "is" << getLowerName() << "Expr(false)"; 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 5950b57cec5SDimitry Andric OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName(); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric void writeImplicitCtorArgs(raw_ostream &OS) const override { 5990b57cec5SDimitry Andric OS << "Is" << getUpperName() << "Expr, " << getUpperName(); 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 6030b57cec5SDimitry Andric OS << "bool is" << getLowerName() << "Expr;\n"; 6040b57cec5SDimitry Andric OS << "union {\n"; 6050b57cec5SDimitry Andric OS << "Expr *" << getLowerName() << "Expr;\n"; 6060b57cec5SDimitry Andric OS << "TypeSourceInfo *" << getLowerName() << "Type;\n"; 60706c3fb27SDimitry Andric OS << "};\n"; 60806c3fb27SDimitry Andric OS << "std::optional<unsigned> " << getLowerName() << "Cache;\n"; 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 6120b57cec5SDimitry Andric OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr"; 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 6160b57cec5SDimitry Andric OS << " bool is" << getLowerName() << "Expr = Record.readInt();\n"; 6170b57cec5SDimitry Andric OS << " void *" << getLowerName() << "Ptr;\n"; 6180b57cec5SDimitry Andric OS << " if (is" << getLowerName() << "Expr)\n"; 6190b57cec5SDimitry Andric OS << " " << getLowerName() << "Ptr = Record.readExpr();\n"; 6200b57cec5SDimitry Andric OS << " else\n"; 6210b57cec5SDimitry Andric OS << " " << getLowerName() 622480093f4SDimitry Andric << "Ptr = Record.readTypeSourceInfo();\n"; 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 6260b57cec5SDimitry Andric OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n"; 6270b57cec5SDimitry Andric OS << " if (SA->is" << getUpperName() << "Expr())\n"; 6280b57cec5SDimitry Andric OS << " Record.AddStmt(SA->get" << getUpperName() << "Expr());\n"; 6290b57cec5SDimitry Andric OS << " else\n"; 6300b57cec5SDimitry Andric OS << " Record.AddTypeSourceInfo(SA->get" << getUpperName() 6310b57cec5SDimitry Andric << "Type());\n"; 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric std::string getIsOmitted() const override { 63506c3fb27SDimitry Andric return "!((is" + getLowerName().str() + "Expr && " + 63606c3fb27SDimitry Andric getLowerName().str() + "Expr) || (!is" + getLowerName().str() + 63706c3fb27SDimitry Andric "Expr && " + getLowerName().str() + "Type))"; 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 6410b57cec5SDimitry Andric OS << "\";\n"; 64206c3fb27SDimitry Andric OS << " if (is" << getLowerName() << "Expr && " << getLowerName() 64306c3fb27SDimitry Andric << "Expr)"; 6440b57cec5SDimitry Andric OS << " " << getLowerName() 6450b57cec5SDimitry Andric << "Expr->printPretty(OS, nullptr, Policy);\n"; 64606c3fb27SDimitry Andric OS << " if (!is" << getLowerName() << "Expr && " << getLowerName() 64706c3fb27SDimitry Andric << "Type)"; 64806c3fb27SDimitry Andric OS << " " << getLowerName() 64906c3fb27SDimitry Andric << "Type->getType().print(OS, Policy);\n"; 6500b57cec5SDimitry Andric OS << " OS << \""; 6510b57cec5SDimitry Andric } 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 6540b57cec5SDimitry Andric OS << " if (!SA->is" << getUpperName() << "Expr())\n"; 6550b57cec5SDimitry Andric OS << " dumpType(SA->get" << getUpperName() 6560b57cec5SDimitry Andric << "Type()->getType());\n"; 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric void writeDumpChildren(raw_ostream &OS) const override { 6600b57cec5SDimitry Andric OS << " if (SA->is" << getUpperName() << "Expr())\n"; 6610b57cec5SDimitry Andric OS << " Visit(SA->get" << getUpperName() << "Expr());\n"; 6620b57cec5SDimitry Andric } 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric void writeHasChildren(raw_ostream &OS) const override { 6650b57cec5SDimitry Andric OS << "SA->is" << getUpperName() << "Expr()"; 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric }; 6680b57cec5SDimitry Andric 6690b57cec5SDimitry Andric class VariadicArgument : public Argument { 6700b57cec5SDimitry Andric std::string Type, ArgName, ArgSizeName, RangeName; 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric protected: 6730b57cec5SDimitry Andric // Assumed to receive a parameter: raw_ostream OS. 6740b57cec5SDimitry Andric virtual void writeValueImpl(raw_ostream &OS) const { 6750b57cec5SDimitry Andric OS << " OS << Val;\n"; 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric // Assumed to receive a parameter: raw_ostream OS. 6780b57cec5SDimitry Andric virtual void writeDumpImpl(raw_ostream &OS) const { 6790b57cec5SDimitry Andric OS << " OS << \" \" << Val;\n"; 6800b57cec5SDimitry Andric } 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric public: 6830b57cec5SDimitry Andric VariadicArgument(const Record &Arg, StringRef Attr, std::string T) 6840b57cec5SDimitry Andric : Argument(Arg, Attr), Type(std::move(T)), 6850b57cec5SDimitry Andric ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"), 6865ffd83dbSDimitry Andric RangeName(std::string(getLowerName())) {} 6870b57cec5SDimitry Andric 68881ad6265SDimitry Andric VariadicArgument(StringRef Arg, StringRef Attr, std::string T) 68981ad6265SDimitry Andric : Argument(Arg, Attr), Type(std::move(T)), 69081ad6265SDimitry Andric ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"), 69181ad6265SDimitry Andric RangeName(std::string(getLowerName())) {} 69281ad6265SDimitry Andric 6930b57cec5SDimitry Andric const std::string &getType() const { return Type; } 6940b57cec5SDimitry Andric const std::string &getArgName() const { return ArgName; } 6950b57cec5SDimitry Andric const std::string &getArgSizeName() const { return ArgSizeName; } 6960b57cec5SDimitry Andric bool isVariadic() const override { return true; } 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 6990b57cec5SDimitry Andric std::string IteratorType = getLowerName().str() + "_iterator"; 7000b57cec5SDimitry Andric std::string BeginFn = getLowerName().str() + "_begin()"; 7010b57cec5SDimitry Andric std::string EndFn = getLowerName().str() + "_end()"; 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric OS << " typedef " << Type << "* " << IteratorType << ";\n"; 7040b57cec5SDimitry Andric OS << " " << IteratorType << " " << BeginFn << " const {" 7050b57cec5SDimitry Andric << " return " << ArgName << "; }\n"; 7060b57cec5SDimitry Andric OS << " " << IteratorType << " " << EndFn << " const {" 7070b57cec5SDimitry Andric << " return " << ArgName << " + " << ArgSizeName << "; }\n"; 7080b57cec5SDimitry Andric OS << " unsigned " << getLowerName() << "_size() const {" 7090b57cec5SDimitry Andric << " return " << ArgSizeName << "; }\n"; 7100b57cec5SDimitry Andric OS << " llvm::iterator_range<" << IteratorType << "> " << RangeName 7110b57cec5SDimitry Andric << "() const { return llvm::make_range(" << BeginFn << ", " << EndFn 7120b57cec5SDimitry Andric << "); }\n"; 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric 71581ad6265SDimitry Andric void writeSetter(raw_ostream &OS) const { 71681ad6265SDimitry Andric OS << " void set" << getUpperName() << "(ASTContext &Ctx, "; 71781ad6265SDimitry Andric writeCtorParameters(OS); 71881ad6265SDimitry Andric OS << ") {\n"; 71981ad6265SDimitry Andric OS << " " << ArgSizeName << " = " << getUpperName() << "Size;\n"; 72081ad6265SDimitry Andric OS << " " << ArgName << " = new (Ctx, 16) " << getType() << "[" 72181ad6265SDimitry Andric << ArgSizeName << "];\n"; 72281ad6265SDimitry Andric OS << " "; 72381ad6265SDimitry Andric writeCtorBody(OS); 72481ad6265SDimitry Andric OS << " }\n"; 72581ad6265SDimitry Andric } 72681ad6265SDimitry Andric 7270b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 7280b57cec5SDimitry Andric OS << ArgName << ", " << ArgSizeName; 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric 7310b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 7320b57cec5SDimitry Andric // This isn't elegant, but we have to go through public methods... 7330b57cec5SDimitry Andric OS << "A->" << getLowerName() << "_begin(), " 7340b57cec5SDimitry Andric << "A->" << getLowerName() << "_size()"; 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric void writeASTVisitorTraversal(raw_ostream &OS) const override { 7380b57cec5SDimitry Andric // FIXME: Traverse the elements. 7390b57cec5SDimitry Andric } 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric void writeCtorBody(raw_ostream &OS) const override { 7425ffd83dbSDimitry Andric OS << " std::copy(" << getUpperName() << ", " << getUpperName() << " + " 7435ffd83dbSDimitry Andric << ArgSizeName << ", " << ArgName << ");\n"; 7440b57cec5SDimitry Andric } 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 7470b57cec5SDimitry Andric OS << ArgSizeName << "(" << getUpperName() << "Size), " 7480b57cec5SDimitry Andric << ArgName << "(new (Ctx, 16) " << getType() << "[" 7490b57cec5SDimitry Andric << ArgSizeName << "])"; 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 7530b57cec5SDimitry Andric OS << ArgSizeName << "(0), " << ArgName << "(nullptr)"; 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 7570b57cec5SDimitry Andric OS << getType() << " *" << getUpperName() << ", unsigned " 7580b57cec5SDimitry Andric << getUpperName() << "Size"; 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric void writeImplicitCtorArgs(raw_ostream &OS) const override { 7620b57cec5SDimitry Andric OS << getUpperName() << ", " << getUpperName() << "Size"; 7630b57cec5SDimitry Andric } 7640b57cec5SDimitry Andric 7650b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 7660b57cec5SDimitry Andric OS << " unsigned " << ArgSizeName << ";\n"; 7670b57cec5SDimitry Andric OS << " " << getType() << " *" << ArgName << ";"; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 7710b57cec5SDimitry Andric OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n"; 7720b57cec5SDimitry Andric OS << " SmallVector<" << getType() << ", 4> " 7730b57cec5SDimitry Andric << getLowerName() << ";\n"; 7740b57cec5SDimitry Andric OS << " " << getLowerName() << ".reserve(" << getLowerName() 7750b57cec5SDimitry Andric << "Size);\n"; 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric // If we can't store the values in the current type (if it's something 7780b57cec5SDimitry Andric // like StringRef), store them in a different type and convert the 7790b57cec5SDimitry Andric // container afterwards. 7805ffd83dbSDimitry Andric std::string StorageType = std::string(getStorageType(getType())); 7815ffd83dbSDimitry Andric std::string StorageName = std::string(getLowerName()); 7820b57cec5SDimitry Andric if (StorageType != getType()) { 7830b57cec5SDimitry Andric StorageName += "Storage"; 7840b57cec5SDimitry Andric OS << " SmallVector<" << StorageType << ", 4> " 7850b57cec5SDimitry Andric << StorageName << ";\n"; 7860b57cec5SDimitry Andric OS << " " << StorageName << ".reserve(" << getLowerName() 7870b57cec5SDimitry Andric << "Size);\n"; 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n"; 7910b57cec5SDimitry Andric std::string read = ReadPCHRecord(Type); 7920b57cec5SDimitry Andric OS << " " << StorageName << ".push_back(" << read << ");\n"; 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric if (StorageType != getType()) { 7950b57cec5SDimitry Andric OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n"; 7960b57cec5SDimitry Andric OS << " " << getLowerName() << ".push_back(" 7970b57cec5SDimitry Andric << StorageName << "[i]);\n"; 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 8020b57cec5SDimitry Andric OS << getLowerName() << ".data(), " << getLowerName() << "Size"; 8030b57cec5SDimitry Andric } 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 8060b57cec5SDimitry Andric OS << " Record.push_back(SA->" << getLowerName() << "_size());\n"; 8070b57cec5SDimitry Andric OS << " for (auto &Val : SA->" << RangeName << "())\n"; 8080b57cec5SDimitry Andric OS << " " << WritePCHRecord(Type, "Val"); 8090b57cec5SDimitry Andric } 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 8120b57cec5SDimitry Andric OS << "\";\n"; 813fe6060f1SDimitry Andric OS << " for (const auto &Val : " << RangeName << "()) {\n" 814fe6060f1SDimitry Andric << " DelimitAttributeArgument(OS, IsFirstArgument);\n"; 8150b57cec5SDimitry Andric writeValueImpl(OS); 8160b57cec5SDimitry Andric OS << " }\n"; 8170b57cec5SDimitry Andric OS << " OS << \""; 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 8210b57cec5SDimitry Andric OS << " for (const auto &Val : SA->" << RangeName << "())\n"; 8220b57cec5SDimitry Andric writeDumpImpl(OS); 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric }; 8250b57cec5SDimitry Andric 826bdd1243dSDimitry Andric class VariadicOMPInteropInfoArgument : public VariadicArgument { 827bdd1243dSDimitry Andric public: 828bdd1243dSDimitry Andric VariadicOMPInteropInfoArgument(const Record &Arg, StringRef Attr) 829bdd1243dSDimitry Andric : VariadicArgument(Arg, Attr, "OMPInteropInfo") {} 830bdd1243dSDimitry Andric 831bdd1243dSDimitry Andric void writeDump(raw_ostream &OS) const override { 832bdd1243dSDimitry Andric OS << " for (" << getAttrName() << "Attr::" << getLowerName() 833bdd1243dSDimitry Andric << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" 834bdd1243dSDimitry Andric << getLowerName() << "_end(); I != E; ++I) {\n"; 835bdd1243dSDimitry Andric OS << " if (I->IsTarget && I->IsTargetSync)\n"; 836bdd1243dSDimitry Andric OS << " OS << \" Target_TargetSync\";\n"; 837bdd1243dSDimitry Andric OS << " else if (I->IsTarget)\n"; 838bdd1243dSDimitry Andric OS << " OS << \" Target\";\n"; 839bdd1243dSDimitry Andric OS << " else\n"; 840bdd1243dSDimitry Andric OS << " OS << \" TargetSync\";\n"; 841bdd1243dSDimitry Andric OS << " }\n"; 842bdd1243dSDimitry Andric } 843bdd1243dSDimitry Andric 844bdd1243dSDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 845bdd1243dSDimitry Andric OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n"; 846bdd1243dSDimitry Andric OS << " SmallVector<OMPInteropInfo, 4> " << getLowerName() << ";\n"; 847bdd1243dSDimitry Andric OS << " " << getLowerName() << ".reserve(" << getLowerName() 848bdd1243dSDimitry Andric << "Size);\n"; 849bdd1243dSDimitry Andric OS << " for (unsigned I = 0, E = " << getLowerName() << "Size; "; 850bdd1243dSDimitry Andric OS << "I != E; ++I) {\n"; 851bdd1243dSDimitry Andric OS << " bool IsTarget = Record.readBool();\n"; 852bdd1243dSDimitry Andric OS << " bool IsTargetSync = Record.readBool();\n"; 853bdd1243dSDimitry Andric OS << " " << getLowerName() 854bdd1243dSDimitry Andric << ".emplace_back(IsTarget, IsTargetSync);\n"; 855bdd1243dSDimitry Andric OS << " }\n"; 856bdd1243dSDimitry Andric } 857bdd1243dSDimitry Andric 858bdd1243dSDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 859bdd1243dSDimitry Andric OS << " Record.push_back(SA->" << getLowerName() << "_size());\n"; 860bdd1243dSDimitry Andric OS << " for (" << getAttrName() << "Attr::" << getLowerName() 861bdd1243dSDimitry Andric << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" 862bdd1243dSDimitry Andric << getLowerName() << "_end(); I != E; ++I) {\n"; 863bdd1243dSDimitry Andric OS << " Record.writeBool(I->IsTarget);\n"; 864bdd1243dSDimitry Andric OS << " Record.writeBool(I->IsTargetSync);\n"; 865bdd1243dSDimitry Andric OS << " }\n"; 866bdd1243dSDimitry Andric } 867bdd1243dSDimitry Andric }; 868bdd1243dSDimitry Andric 8690b57cec5SDimitry Andric class VariadicParamIdxArgument : public VariadicArgument { 8700b57cec5SDimitry Andric public: 8710b57cec5SDimitry Andric VariadicParamIdxArgument(const Record &Arg, StringRef Attr) 8720b57cec5SDimitry Andric : VariadicArgument(Arg, Attr, "ParamIdx") {} 8730b57cec5SDimitry Andric 8740b57cec5SDimitry Andric public: 8750b57cec5SDimitry Andric void writeValueImpl(raw_ostream &OS) const override { 8760b57cec5SDimitry Andric OS << " OS << Val.getSourceIndex();\n"; 8770b57cec5SDimitry Andric } 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric void writeDumpImpl(raw_ostream &OS) const override { 8800b57cec5SDimitry Andric OS << " OS << \" \" << Val.getSourceIndex();\n"; 8810b57cec5SDimitry Andric } 8820b57cec5SDimitry Andric }; 8830b57cec5SDimitry Andric 8840b57cec5SDimitry Andric struct VariadicParamOrParamIdxArgument : public VariadicArgument { 8850b57cec5SDimitry Andric VariadicParamOrParamIdxArgument(const Record &Arg, StringRef Attr) 8860b57cec5SDimitry Andric : VariadicArgument(Arg, Attr, "int") {} 8870b57cec5SDimitry Andric }; 8880b57cec5SDimitry Andric 8890b57cec5SDimitry Andric // Unique the enums, but maintain the original declaration ordering. 8900b57cec5SDimitry Andric std::vector<StringRef> 8910b57cec5SDimitry Andric uniqueEnumsInOrder(const std::vector<StringRef> &enums) { 8920b57cec5SDimitry Andric std::vector<StringRef> uniques; 8930b57cec5SDimitry Andric SmallDenseSet<StringRef, 8> unique_set; 8940b57cec5SDimitry Andric for (const auto &i : enums) { 8950b57cec5SDimitry Andric if (unique_set.insert(i).second) 8960b57cec5SDimitry Andric uniques.push_back(i); 8970b57cec5SDimitry Andric } 8980b57cec5SDimitry Andric return uniques; 8990b57cec5SDimitry Andric } 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric class EnumArgument : public Argument { 9025f757f3fSDimitry Andric std::string fullType; 9035f757f3fSDimitry Andric StringRef shortType; 9040b57cec5SDimitry Andric std::vector<StringRef> values, enums, uniques; 9055f757f3fSDimitry Andric bool isExternal; 906*0fca6ea1SDimitry Andric bool isCovered; 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric public: 9090b57cec5SDimitry Andric EnumArgument(const Record &Arg, StringRef Attr) 9105f757f3fSDimitry Andric : Argument(Arg, Attr), values(Arg.getValueAsListOfStrings("Values")), 9110b57cec5SDimitry Andric enums(Arg.getValueAsListOfStrings("Enums")), 9125f757f3fSDimitry Andric uniques(uniqueEnumsInOrder(enums)), 913*0fca6ea1SDimitry Andric isExternal(Arg.getValueAsBit("IsExternalType")), 914*0fca6ea1SDimitry Andric isCovered(Arg.getValueAsBit("IsCovered")) { 9155f757f3fSDimitry Andric StringRef Type = Arg.getValueAsString("Type"); 9165f757f3fSDimitry Andric shortType = isExternal ? Type.rsplit("::").second : Type; 9175f757f3fSDimitry Andric // If shortType didn't contain :: at all rsplit will give us an empty 9185f757f3fSDimitry Andric // string. 9195f757f3fSDimitry Andric if (shortType.empty()) 9205f757f3fSDimitry Andric shortType = Type; 9215f757f3fSDimitry Andric fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str(); 9225f757f3fSDimitry Andric 9230b57cec5SDimitry Andric // FIXME: Emit a proper error 9240b57cec5SDimitry Andric assert(!uniques.empty()); 9250b57cec5SDimitry Andric } 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric bool isEnumArg() const override { return true; } 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 9305f757f3fSDimitry Andric OS << " " << fullType << " get" << getUpperName() << "() const {\n"; 9310b57cec5SDimitry Andric OS << " return " << getLowerName() << ";\n"; 9320b57cec5SDimitry Andric OS << " }"; 9330b57cec5SDimitry Andric } 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 9360b57cec5SDimitry Andric OS << getLowerName(); 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 9400b57cec5SDimitry Andric OS << "A->get" << getUpperName() << "()"; 9410b57cec5SDimitry Andric } 9420b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 9430b57cec5SDimitry Andric OS << getLowerName() << "(" << getUpperName() << ")"; 9440b57cec5SDimitry Andric } 9450b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 9465f757f3fSDimitry Andric OS << getLowerName() << "(" << fullType << "(0))"; 9470b57cec5SDimitry Andric } 9480b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 9495f757f3fSDimitry Andric OS << fullType << " " << getUpperName(); 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 9525f757f3fSDimitry Andric if (!isExternal) { 9530b57cec5SDimitry Andric auto i = uniques.cbegin(), e = uniques.cend(); 9540b57cec5SDimitry Andric // The last one needs to not have a comma. 9550b57cec5SDimitry Andric --e; 9560b57cec5SDimitry Andric 9570b57cec5SDimitry Andric OS << "public:\n"; 9585f757f3fSDimitry Andric OS << " enum " << shortType << " {\n"; 9590b57cec5SDimitry Andric for (; i != e; ++i) 9600b57cec5SDimitry Andric OS << " " << *i << ",\n"; 9610b57cec5SDimitry Andric OS << " " << *e << "\n"; 9620b57cec5SDimitry Andric OS << " };\n"; 9635f757f3fSDimitry Andric } 9645f757f3fSDimitry Andric 9650b57cec5SDimitry Andric OS << "private:\n"; 9665f757f3fSDimitry Andric OS << " " << fullType << " " << getLowerName() << ";"; 9670b57cec5SDimitry Andric } 9680b57cec5SDimitry Andric 9690b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 9705f757f3fSDimitry Andric OS << " " << fullType << " " << getLowerName() << "(static_cast<" 9715f757f3fSDimitry Andric << fullType << ">(Record.readInt()));\n"; 9720b57cec5SDimitry Andric } 9730b57cec5SDimitry Andric 9740b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 9750b57cec5SDimitry Andric OS << getLowerName(); 9760b57cec5SDimitry Andric } 9770b57cec5SDimitry Andric 9780b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 9795f757f3fSDimitry Andric OS << "Record.push_back(static_cast<uint64_t>(SA->get" << getUpperName() 9805f757f3fSDimitry Andric << "()));\n"; 9810b57cec5SDimitry Andric } 9820b57cec5SDimitry Andric 9830b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 9840b57cec5SDimitry Andric // FIXME: this isn't 100% correct -- some enum arguments require printing 9850b57cec5SDimitry Andric // as a string literal, while others require printing as an identifier. 9860b57cec5SDimitry Andric // Tablegen currently does not distinguish between the two forms. 9875f757f3fSDimitry Andric OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << shortType 9885f757f3fSDimitry Andric << "ToStr(get" << getUpperName() << "()) << \"\\\""; 9890b57cec5SDimitry Andric } 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 9920b57cec5SDimitry Andric OS << " switch(SA->get" << getUpperName() << "()) {\n"; 9930b57cec5SDimitry Andric for (const auto &I : uniques) { 9945f757f3fSDimitry Andric OS << " case " << fullType << "::" << I << ":\n"; 9950b57cec5SDimitry Andric OS << " OS << \" " << I << "\";\n"; 9960b57cec5SDimitry Andric OS << " break;\n"; 9970b57cec5SDimitry Andric } 998*0fca6ea1SDimitry Andric if (!isCovered) { 9995f757f3fSDimitry Andric OS << " default:\n"; 10005f757f3fSDimitry Andric OS << " llvm_unreachable(\"Invalid attribute value\");\n"; 10015f757f3fSDimitry Andric } 10020b57cec5SDimitry Andric OS << " }\n"; 10030b57cec5SDimitry Andric } 10040b57cec5SDimitry Andric 10055ffd83dbSDimitry Andric void writeConversion(raw_ostream &OS, bool Header) const { 10065ffd83dbSDimitry Andric if (Header) { 10075f757f3fSDimitry Andric OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, " 10085f757f3fSDimitry Andric << fullType << " &Out);\n"; 10095f757f3fSDimitry Andric OS << " static const char *Convert" << shortType << "ToStr(" 10105f757f3fSDimitry Andric << fullType << " Val);\n"; 10115ffd83dbSDimitry Andric return; 10125ffd83dbSDimitry Andric } 10135ffd83dbSDimitry Andric 10145f757f3fSDimitry Andric OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType 10155f757f3fSDimitry Andric << "(StringRef Val, " << fullType << " &Out) {\n"; 10165f757f3fSDimitry Andric OS << " std::optional<" << fullType << "> " 10175f757f3fSDimitry Andric << "R = llvm::StringSwitch<std::optional<" << fullType << ">>(Val)\n"; 10180b57cec5SDimitry Andric for (size_t I = 0; I < enums.size(); ++I) { 10190b57cec5SDimitry Andric OS << " .Case(\"" << values[I] << "\", "; 10205f757f3fSDimitry Andric OS << fullType << "::" << enums[I] << ")\n"; 10210b57cec5SDimitry Andric } 10225f757f3fSDimitry Andric OS << " .Default(std::optional<" << fullType << ">());\n"; 10230b57cec5SDimitry Andric OS << " if (R) {\n"; 10240b57cec5SDimitry Andric OS << " Out = *R;\n return true;\n }\n"; 10250b57cec5SDimitry Andric OS << " return false;\n"; 10260b57cec5SDimitry Andric OS << "}\n\n"; 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric // Mapping from enumeration values back to enumeration strings isn't 10290b57cec5SDimitry Andric // trivial because some enumeration values have multiple named 10300b57cec5SDimitry Andric // enumerators, such as type_visibility(internal) and 10310b57cec5SDimitry Andric // type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden. 10325f757f3fSDimitry Andric OS << "const char *" << getAttrName() << "Attr::Convert" << shortType 10335f757f3fSDimitry Andric << "ToStr(" << fullType << " Val) {\n" 10340b57cec5SDimitry Andric << " switch(Val) {\n"; 10350b57cec5SDimitry Andric SmallDenseSet<StringRef, 8> Uniques; 10360b57cec5SDimitry Andric for (size_t I = 0; I < enums.size(); ++I) { 10370b57cec5SDimitry Andric if (Uniques.insert(enums[I]).second) 10385f757f3fSDimitry Andric OS << " case " << fullType << "::" << enums[I] << ": return \"" 10395f757f3fSDimitry Andric << values[I] << "\";\n"; 10405f757f3fSDimitry Andric } 1041*0fca6ea1SDimitry Andric if (!isCovered) { 10425f757f3fSDimitry Andric OS << " default: llvm_unreachable(\"Invalid attribute value\");\n"; 10430b57cec5SDimitry Andric } 10440b57cec5SDimitry Andric OS << " }\n" 10450b57cec5SDimitry Andric << " llvm_unreachable(\"No enumerator with that value\");\n" 10460b57cec5SDimitry Andric << "}\n"; 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric }; 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric class VariadicEnumArgument: public VariadicArgument { 10515f757f3fSDimitry Andric std::string fullType; 10525f757f3fSDimitry Andric StringRef shortType; 10530b57cec5SDimitry Andric std::vector<StringRef> values, enums, uniques; 10545f757f3fSDimitry Andric bool isExternal; 1055*0fca6ea1SDimitry Andric bool isCovered; 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric protected: 10580b57cec5SDimitry Andric void writeValueImpl(raw_ostream &OS) const override { 10590b57cec5SDimitry Andric // FIXME: this isn't 100% correct -- some enum arguments require printing 10600b57cec5SDimitry Andric // as a string literal, while others require printing as an identifier. 10610b57cec5SDimitry Andric // Tablegen currently does not distinguish between the two forms. 10625f757f3fSDimitry Andric OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" 10635f757f3fSDimitry Andric << shortType << "ToStr(Val)" 10645f757f3fSDimitry Andric << "<< \"\\\"\";\n"; 10650b57cec5SDimitry Andric } 10660b57cec5SDimitry Andric 10670b57cec5SDimitry Andric public: 10680b57cec5SDimitry Andric VariadicEnumArgument(const Record &Arg, StringRef Attr) 10695ffd83dbSDimitry Andric : VariadicArgument(Arg, Attr, 10705ffd83dbSDimitry Andric std::string(Arg.getValueAsString("Type"))), 10710b57cec5SDimitry Andric values(Arg.getValueAsListOfStrings("Values")), 10720b57cec5SDimitry Andric enums(Arg.getValueAsListOfStrings("Enums")), 10735f757f3fSDimitry Andric uniques(uniqueEnumsInOrder(enums)), 1074*0fca6ea1SDimitry Andric isExternal(Arg.getValueAsBit("IsExternalType")), 1075*0fca6ea1SDimitry Andric isCovered(Arg.getValueAsBit("IsCovered")) { 10765f757f3fSDimitry Andric StringRef Type = Arg.getValueAsString("Type"); 10775f757f3fSDimitry Andric shortType = isExternal ? Type.rsplit("::").second : Type; 10785f757f3fSDimitry Andric // If shortType didn't contain :: at all rsplit will give us an empty 10795f757f3fSDimitry Andric // string. 10805f757f3fSDimitry Andric if (shortType.empty()) 10815f757f3fSDimitry Andric shortType = Type; 10825f757f3fSDimitry Andric fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str(); 10830b57cec5SDimitry Andric 10840b57cec5SDimitry Andric // FIXME: Emit a proper error 10850b57cec5SDimitry Andric assert(!uniques.empty()); 10860b57cec5SDimitry Andric } 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric bool isVariadicEnumArg() const override { return true; } 10890b57cec5SDimitry Andric 10900b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 10915f757f3fSDimitry Andric if (!isExternal) { 10920b57cec5SDimitry Andric auto i = uniques.cbegin(), e = uniques.cend(); 10930b57cec5SDimitry Andric // The last one needs to not have a comma. 10940b57cec5SDimitry Andric --e; 10950b57cec5SDimitry Andric 10960b57cec5SDimitry Andric OS << "public:\n"; 10975f757f3fSDimitry Andric OS << " enum " << shortType << " {\n"; 10980b57cec5SDimitry Andric for (; i != e; ++i) 10990b57cec5SDimitry Andric OS << " " << *i << ",\n"; 11000b57cec5SDimitry Andric OS << " " << *e << "\n"; 11010b57cec5SDimitry Andric OS << " };\n"; 11025f757f3fSDimitry Andric } 11030b57cec5SDimitry Andric OS << "private:\n"; 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric VariadicArgument::writeDeclarations(OS); 11060b57cec5SDimitry Andric } 11070b57cec5SDimitry Andric 11080b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 11090b57cec5SDimitry Andric OS << " for (" << getAttrName() << "Attr::" << getLowerName() 11100b57cec5SDimitry Andric << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" 11110b57cec5SDimitry Andric << getLowerName() << "_end(); I != E; ++I) {\n"; 11120b57cec5SDimitry Andric OS << " switch(*I) {\n"; 11130b57cec5SDimitry Andric for (const auto &UI : uniques) { 11145f757f3fSDimitry Andric OS << " case " << fullType << "::" << UI << ":\n"; 11150b57cec5SDimitry Andric OS << " OS << \" " << UI << "\";\n"; 11160b57cec5SDimitry Andric OS << " break;\n"; 11170b57cec5SDimitry Andric } 1118*0fca6ea1SDimitry Andric if (!isCovered) { 1119*0fca6ea1SDimitry Andric OS << " default:\n"; 1120*0fca6ea1SDimitry Andric OS << " llvm_unreachable(\"Invalid attribute value\");\n"; 1121*0fca6ea1SDimitry Andric } 11220b57cec5SDimitry Andric OS << " }\n"; 11230b57cec5SDimitry Andric OS << " }\n"; 11240b57cec5SDimitry Andric } 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 11270b57cec5SDimitry Andric OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n"; 11285f757f3fSDimitry Andric OS << " SmallVector<" << fullType << ", 4> " << getLowerName() 11290b57cec5SDimitry Andric << ";\n"; 11300b57cec5SDimitry Andric OS << " " << getLowerName() << ".reserve(" << getLowerName() 11310b57cec5SDimitry Andric << "Size);\n"; 11320b57cec5SDimitry Andric OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; 11335f757f3fSDimitry Andric OS << " " << getLowerName() << ".push_back(" 11345f757f3fSDimitry Andric << "static_cast<" << fullType << ">(Record.readInt()));\n"; 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 11380b57cec5SDimitry Andric OS << " Record.push_back(SA->" << getLowerName() << "_size());\n"; 11390b57cec5SDimitry Andric OS << " for (" << getAttrName() << "Attr::" << getLowerName() 11400b57cec5SDimitry Andric << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" 11410b57cec5SDimitry Andric << getLowerName() << "_end(); i != e; ++i)\n"; 11425f757f3fSDimitry Andric OS << " " << WritePCHRecord(fullType, "(*i)"); 11430b57cec5SDimitry Andric } 11440b57cec5SDimitry Andric 11455ffd83dbSDimitry Andric void writeConversion(raw_ostream &OS, bool Header) const { 11465ffd83dbSDimitry Andric if (Header) { 11475f757f3fSDimitry Andric OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, " 11485f757f3fSDimitry Andric << fullType << " &Out);\n"; 11495f757f3fSDimitry Andric OS << " static const char *Convert" << shortType << "ToStr(" 11505f757f3fSDimitry Andric << fullType << " Val);\n"; 11515ffd83dbSDimitry Andric return; 11525ffd83dbSDimitry Andric } 11535ffd83dbSDimitry Andric 11545f757f3fSDimitry Andric OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType 11555ffd83dbSDimitry Andric << "(StringRef Val, "; 11565f757f3fSDimitry Andric OS << fullType << " &Out) {\n"; 11575f757f3fSDimitry Andric OS << " std::optional<" << fullType 1158bdd1243dSDimitry Andric << "> R = llvm::StringSwitch<std::optional<"; 11595f757f3fSDimitry Andric OS << fullType << ">>(Val)\n"; 11600b57cec5SDimitry Andric for (size_t I = 0; I < enums.size(); ++I) { 11610b57cec5SDimitry Andric OS << " .Case(\"" << values[I] << "\", "; 11625f757f3fSDimitry Andric OS << fullType << "::" << enums[I] << ")\n"; 11630b57cec5SDimitry Andric } 11645f757f3fSDimitry Andric OS << " .Default(std::optional<" << fullType << ">());\n"; 11650b57cec5SDimitry Andric OS << " if (R) {\n"; 11660b57cec5SDimitry Andric OS << " Out = *R;\n return true;\n }\n"; 11670b57cec5SDimitry Andric OS << " return false;\n"; 11680b57cec5SDimitry Andric OS << "}\n\n"; 11690b57cec5SDimitry Andric 11705f757f3fSDimitry Andric OS << "const char *" << getAttrName() << "Attr::Convert" << shortType 11715f757f3fSDimitry Andric << "ToStr(" << fullType << " Val) {\n" 11720b57cec5SDimitry Andric << " switch(Val) {\n"; 11730b57cec5SDimitry Andric SmallDenseSet<StringRef, 8> Uniques; 11740b57cec5SDimitry Andric for (size_t I = 0; I < enums.size(); ++I) { 11750b57cec5SDimitry Andric if (Uniques.insert(enums[I]).second) 11765f757f3fSDimitry Andric OS << " case " << fullType << "::" << enums[I] << ": return \"" 11775f757f3fSDimitry Andric << values[I] << "\";\n"; 11780b57cec5SDimitry Andric } 1179*0fca6ea1SDimitry Andric if (!isCovered) { 1180*0fca6ea1SDimitry Andric OS << " default: llvm_unreachable(\"Invalid attribute value\");\n"; 1181*0fca6ea1SDimitry Andric } 11820b57cec5SDimitry Andric OS << " }\n" 11830b57cec5SDimitry Andric << " llvm_unreachable(\"No enumerator with that value\");\n" 11840b57cec5SDimitry Andric << "}\n"; 11850b57cec5SDimitry Andric } 11860b57cec5SDimitry Andric }; 11870b57cec5SDimitry Andric 11880b57cec5SDimitry Andric class VersionArgument : public Argument { 11890b57cec5SDimitry Andric public: 11900b57cec5SDimitry Andric VersionArgument(const Record &Arg, StringRef Attr) 11910b57cec5SDimitry Andric : Argument(Arg, Attr) 11920b57cec5SDimitry Andric {} 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 11950b57cec5SDimitry Andric OS << " VersionTuple get" << getUpperName() << "() const {\n"; 11960b57cec5SDimitry Andric OS << " return " << getLowerName() << ";\n"; 11970b57cec5SDimitry Andric OS << " }\n"; 11980b57cec5SDimitry Andric OS << " void set" << getUpperName() 11990b57cec5SDimitry Andric << "(ASTContext &C, VersionTuple V) {\n"; 12000b57cec5SDimitry Andric OS << " " << getLowerName() << " = V;\n"; 12010b57cec5SDimitry Andric OS << " }"; 12020b57cec5SDimitry Andric } 12030b57cec5SDimitry Andric 12040b57cec5SDimitry Andric void writeCloneArgs(raw_ostream &OS) const override { 12050b57cec5SDimitry Andric OS << "get" << getUpperName() << "()"; 12060b57cec5SDimitry Andric } 12070b57cec5SDimitry Andric 12080b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 12090b57cec5SDimitry Andric OS << "A->get" << getUpperName() << "()"; 12100b57cec5SDimitry Andric } 12110b57cec5SDimitry Andric 12120b57cec5SDimitry Andric void writeCtorInitializers(raw_ostream &OS) const override { 12130b57cec5SDimitry Andric OS << getLowerName() << "(" << getUpperName() << ")"; 12140b57cec5SDimitry Andric } 12150b57cec5SDimitry Andric 12160b57cec5SDimitry Andric void writeCtorDefaultInitializers(raw_ostream &OS) const override { 12170b57cec5SDimitry Andric OS << getLowerName() << "()"; 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric void writeCtorParameters(raw_ostream &OS) const override { 12210b57cec5SDimitry Andric OS << "VersionTuple " << getUpperName(); 12220b57cec5SDimitry Andric } 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric void writeDeclarations(raw_ostream &OS) const override { 12250b57cec5SDimitry Andric OS << "VersionTuple " << getLowerName() << ";\n"; 12260b57cec5SDimitry Andric } 12270b57cec5SDimitry Andric 12280b57cec5SDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 12290b57cec5SDimitry Andric OS << " VersionTuple " << getLowerName() 12300b57cec5SDimitry Andric << "= Record.readVersionTuple();\n"; 12310b57cec5SDimitry Andric } 12320b57cec5SDimitry Andric 12330b57cec5SDimitry Andric void writePCHReadArgs(raw_ostream &OS) const override { 12340b57cec5SDimitry Andric OS << getLowerName(); 12350b57cec5SDimitry Andric } 12360b57cec5SDimitry Andric 12370b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 12380b57cec5SDimitry Andric OS << " Record.AddVersionTuple(SA->get" << getUpperName() << "());\n"; 12390b57cec5SDimitry Andric } 12400b57cec5SDimitry Andric 12410b57cec5SDimitry Andric void writeValue(raw_ostream &OS) const override { 12420b57cec5SDimitry Andric OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; 12430b57cec5SDimitry Andric } 12440b57cec5SDimitry Andric 12450b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override { 12460b57cec5SDimitry Andric OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; 12470b57cec5SDimitry Andric } 12480b57cec5SDimitry Andric }; 12490b57cec5SDimitry Andric 12500b57cec5SDimitry Andric class ExprArgument : public SimpleArgument { 12510b57cec5SDimitry Andric public: 12520b57cec5SDimitry Andric ExprArgument(const Record &Arg, StringRef Attr) 12530b57cec5SDimitry Andric : SimpleArgument(Arg, Attr, "Expr *") 12540b57cec5SDimitry Andric {} 12550b57cec5SDimitry Andric 12560b57cec5SDimitry Andric void writeASTVisitorTraversal(raw_ostream &OS) const override { 12570b57cec5SDimitry Andric OS << " if (!" 12580b57cec5SDimitry Andric << "getDerived().TraverseStmt(A->get" << getUpperName() << "()))\n"; 12590b57cec5SDimitry Andric OS << " return false;\n"; 12600b57cec5SDimitry Andric } 12610b57cec5SDimitry Andric 12620b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 12630b57cec5SDimitry Andric OS << "tempInst" << getUpperName(); 12640b57cec5SDimitry Andric } 12650b57cec5SDimitry Andric 12660b57cec5SDimitry Andric void writeTemplateInstantiation(raw_ostream &OS) const override { 12670b57cec5SDimitry Andric OS << " " << getType() << " tempInst" << getUpperName() << ";\n"; 12680b57cec5SDimitry Andric OS << " {\n"; 12690b57cec5SDimitry Andric OS << " EnterExpressionEvaluationContext " 12700b57cec5SDimitry Andric << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n"; 12710b57cec5SDimitry Andric OS << " ExprResult " << "Result = S.SubstExpr(" 12720b57cec5SDimitry Andric << "A->get" << getUpperName() << "(), TemplateArgs);\n"; 1273e8d8bef9SDimitry Andric OS << " if (Result.isInvalid())\n"; 1274e8d8bef9SDimitry Andric OS << " return nullptr;\n"; 1275e8d8bef9SDimitry Andric OS << " tempInst" << getUpperName() << " = Result.get();\n"; 12760b57cec5SDimitry Andric OS << " }\n"; 12770b57cec5SDimitry Andric } 12780b57cec5SDimitry Andric 1279bdd1243dSDimitry Andric void writeValue(raw_ostream &OS) const override { 1280bdd1243dSDimitry Andric OS << "\";\n"; 1281bdd1243dSDimitry Andric OS << " get" << getUpperName() 1282bdd1243dSDimitry Andric << "()->printPretty(OS, nullptr, Policy);\n"; 1283bdd1243dSDimitry Andric OS << " OS << \""; 1284bdd1243dSDimitry Andric } 1285bdd1243dSDimitry Andric 12860b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override {} 12870b57cec5SDimitry Andric 12880b57cec5SDimitry Andric void writeDumpChildren(raw_ostream &OS) const override { 12890b57cec5SDimitry Andric OS << " Visit(SA->get" << getUpperName() << "());\n"; 12900b57cec5SDimitry Andric } 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric void writeHasChildren(raw_ostream &OS) const override { OS << "true"; } 12930b57cec5SDimitry Andric }; 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric class VariadicExprArgument : public VariadicArgument { 12960b57cec5SDimitry Andric public: 12970b57cec5SDimitry Andric VariadicExprArgument(const Record &Arg, StringRef Attr) 12980b57cec5SDimitry Andric : VariadicArgument(Arg, Attr, "Expr *") 12990b57cec5SDimitry Andric {} 13000b57cec5SDimitry Andric 130181ad6265SDimitry Andric VariadicExprArgument(StringRef ArgName, StringRef Attr) 130281ad6265SDimitry Andric : VariadicArgument(ArgName, Attr, "Expr *") {} 130381ad6265SDimitry Andric 13040b57cec5SDimitry Andric void writeASTVisitorTraversal(raw_ostream &OS) const override { 13050b57cec5SDimitry Andric OS << " {\n"; 13060b57cec5SDimitry Andric OS << " " << getType() << " *I = A->" << getLowerName() 13070b57cec5SDimitry Andric << "_begin();\n"; 13080b57cec5SDimitry Andric OS << " " << getType() << " *E = A->" << getLowerName() 13090b57cec5SDimitry Andric << "_end();\n"; 13100b57cec5SDimitry Andric OS << " for (; I != E; ++I) {\n"; 13110b57cec5SDimitry Andric OS << " if (!getDerived().TraverseStmt(*I))\n"; 13120b57cec5SDimitry Andric OS << " return false;\n"; 13130b57cec5SDimitry Andric OS << " }\n"; 13140b57cec5SDimitry Andric OS << " }\n"; 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 13180b57cec5SDimitry Andric OS << "tempInst" << getUpperName() << ", " 13190b57cec5SDimitry Andric << "A->" << getLowerName() << "_size()"; 13200b57cec5SDimitry Andric } 13210b57cec5SDimitry Andric 13220b57cec5SDimitry Andric void writeTemplateInstantiation(raw_ostream &OS) const override { 13230b57cec5SDimitry Andric OS << " auto *tempInst" << getUpperName() 13240b57cec5SDimitry Andric << " = new (C, 16) " << getType() 13250b57cec5SDimitry Andric << "[A->" << getLowerName() << "_size()];\n"; 13260b57cec5SDimitry Andric OS << " {\n"; 13270b57cec5SDimitry Andric OS << " EnterExpressionEvaluationContext " 13280b57cec5SDimitry Andric << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n"; 13290b57cec5SDimitry Andric OS << " " << getType() << " *TI = tempInst" << getUpperName() 13300b57cec5SDimitry Andric << ";\n"; 13310b57cec5SDimitry Andric OS << " " << getType() << " *I = A->" << getLowerName() 13320b57cec5SDimitry Andric << "_begin();\n"; 13330b57cec5SDimitry Andric OS << " " << getType() << " *E = A->" << getLowerName() 13340b57cec5SDimitry Andric << "_end();\n"; 13350b57cec5SDimitry Andric OS << " for (; I != E; ++I, ++TI) {\n"; 13360b57cec5SDimitry Andric OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n"; 1337e8d8bef9SDimitry Andric OS << " if (Result.isInvalid())\n"; 1338e8d8bef9SDimitry Andric OS << " return nullptr;\n"; 1339e8d8bef9SDimitry Andric OS << " *TI = Result.get();\n"; 13400b57cec5SDimitry Andric OS << " }\n"; 13410b57cec5SDimitry Andric OS << " }\n"; 13420b57cec5SDimitry Andric } 13430b57cec5SDimitry Andric 13440b57cec5SDimitry Andric void writeDump(raw_ostream &OS) const override {} 13450b57cec5SDimitry Andric 13460b57cec5SDimitry Andric void writeDumpChildren(raw_ostream &OS) const override { 13470b57cec5SDimitry Andric OS << " for (" << getAttrName() << "Attr::" << getLowerName() 13480b57cec5SDimitry Andric << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" 13490b57cec5SDimitry Andric << getLowerName() << "_end(); I != E; ++I)\n"; 13500b57cec5SDimitry Andric OS << " Visit(*I);\n"; 13510b57cec5SDimitry Andric } 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric void writeHasChildren(raw_ostream &OS) const override { 13540b57cec5SDimitry Andric OS << "SA->" << getLowerName() << "_begin() != " 13550b57cec5SDimitry Andric << "SA->" << getLowerName() << "_end()"; 13560b57cec5SDimitry Andric } 13570b57cec5SDimitry Andric }; 13580b57cec5SDimitry Andric 13590b57cec5SDimitry Andric class VariadicIdentifierArgument : public VariadicArgument { 13600b57cec5SDimitry Andric public: 13610b57cec5SDimitry Andric VariadicIdentifierArgument(const Record &Arg, StringRef Attr) 13620b57cec5SDimitry Andric : VariadicArgument(Arg, Attr, "IdentifierInfo *") 13630b57cec5SDimitry Andric {} 13640b57cec5SDimitry Andric }; 13650b57cec5SDimitry Andric 13660b57cec5SDimitry Andric class VariadicStringArgument : public VariadicArgument { 13670b57cec5SDimitry Andric public: 13680b57cec5SDimitry Andric VariadicStringArgument(const Record &Arg, StringRef Attr) 13690b57cec5SDimitry Andric : VariadicArgument(Arg, Attr, "StringRef") 13700b57cec5SDimitry Andric {} 13710b57cec5SDimitry Andric 13720b57cec5SDimitry Andric void writeCtorBody(raw_ostream &OS) const override { 13730b57cec5SDimitry Andric OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n" 13740b57cec5SDimitry Andric " ++I) {\n" 13750b57cec5SDimitry Andric " StringRef Ref = " << getUpperName() << "[I];\n" 13760b57cec5SDimitry Andric " if (!Ref.empty()) {\n" 13770b57cec5SDimitry Andric " char *Mem = new (Ctx, 1) char[Ref.size()];\n" 13780b57cec5SDimitry Andric " std::memcpy(Mem, Ref.data(), Ref.size());\n" 13790b57cec5SDimitry Andric " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n" 13800b57cec5SDimitry Andric " }\n" 13810b57cec5SDimitry Andric " }\n"; 13820b57cec5SDimitry Andric } 13830b57cec5SDimitry Andric 13840b57cec5SDimitry Andric void writeValueImpl(raw_ostream &OS) const override { 13850b57cec5SDimitry Andric OS << " OS << \"\\\"\" << Val << \"\\\"\";\n"; 13860b57cec5SDimitry Andric } 13870b57cec5SDimitry Andric }; 13880b57cec5SDimitry Andric 13890b57cec5SDimitry Andric class TypeArgument : public SimpleArgument { 13900b57cec5SDimitry Andric public: 13910b57cec5SDimitry Andric TypeArgument(const Record &Arg, StringRef Attr) 13920b57cec5SDimitry Andric : SimpleArgument(Arg, Attr, "TypeSourceInfo *") 13930b57cec5SDimitry Andric {} 13940b57cec5SDimitry Andric 13950b57cec5SDimitry Andric void writeAccessors(raw_ostream &OS) const override { 13960b57cec5SDimitry Andric OS << " QualType get" << getUpperName() << "() const {\n"; 13970b57cec5SDimitry Andric OS << " return " << getLowerName() << "->getType();\n"; 13980b57cec5SDimitry Andric OS << " }"; 13990b57cec5SDimitry Andric OS << " " << getType() << " get" << getUpperName() << "Loc() const {\n"; 14000b57cec5SDimitry Andric OS << " return " << getLowerName() << ";\n"; 14010b57cec5SDimitry Andric OS << " }"; 14020b57cec5SDimitry Andric } 14030b57cec5SDimitry Andric 14040b57cec5SDimitry Andric void writeASTVisitorTraversal(raw_ostream &OS) const override { 14050b57cec5SDimitry Andric OS << " if (auto *TSI = A->get" << getUpperName() << "Loc())\n"; 14060b57cec5SDimitry Andric OS << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n"; 14070b57cec5SDimitry Andric OS << " return false;\n"; 14080b57cec5SDimitry Andric } 14090b57cec5SDimitry Andric 1410e8d8bef9SDimitry Andric void writeTemplateInstantiation(raw_ostream &OS) const override { 1411e8d8bef9SDimitry Andric OS << " " << getType() << " tempInst" << getUpperName() << " =\n"; 1412e8d8bef9SDimitry Andric OS << " S.SubstType(A->get" << getUpperName() << "Loc(), " 1413e8d8bef9SDimitry Andric << "TemplateArgs, A->getLoc(), A->getAttrName());\n"; 1414e8d8bef9SDimitry Andric OS << " if (!tempInst" << getUpperName() << ")\n"; 1415e8d8bef9SDimitry Andric OS << " return nullptr;\n"; 1416e8d8bef9SDimitry Andric } 1417e8d8bef9SDimitry Andric 14180b57cec5SDimitry Andric void writeTemplateInstantiationArgs(raw_ostream &OS) const override { 1419e8d8bef9SDimitry Andric OS << "tempInst" << getUpperName(); 14200b57cec5SDimitry Andric } 14210b57cec5SDimitry Andric 14220b57cec5SDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 14235ffd83dbSDimitry Andric OS << " " 14245ffd83dbSDimitry Andric << WritePCHRecord(getType(), 14255ffd83dbSDimitry Andric "SA->get" + std::string(getUpperName()) + "Loc()"); 14260b57cec5SDimitry Andric } 14270b57cec5SDimitry Andric }; 14280b57cec5SDimitry Andric 14297a6dacacSDimitry Andric class WrappedAttr : public SimpleArgument { 14307a6dacacSDimitry Andric public: 14317a6dacacSDimitry Andric WrappedAttr(const Record &Arg, StringRef Attr) 14327a6dacacSDimitry Andric : SimpleArgument(Arg, Attr, "Attr *") {} 14337a6dacacSDimitry Andric 14347a6dacacSDimitry Andric void writePCHReadDecls(raw_ostream &OS) const override { 14357a6dacacSDimitry Andric OS << " Attr *" << getLowerName() << " = Record.readAttr();"; 14367a6dacacSDimitry Andric } 14377a6dacacSDimitry Andric 14387a6dacacSDimitry Andric void writePCHWrite(raw_ostream &OS) const override { 14397a6dacacSDimitry Andric OS << " AddAttr(SA->get" << getUpperName() << "());"; 14407a6dacacSDimitry Andric } 14417a6dacacSDimitry Andric 14427a6dacacSDimitry Andric void writeDump(raw_ostream &OS) const override {} 14437a6dacacSDimitry Andric 14447a6dacacSDimitry Andric void writeDumpChildren(raw_ostream &OS) const override { 14457a6dacacSDimitry Andric OS << " Visit(SA->get" << getUpperName() << "());\n"; 14467a6dacacSDimitry Andric } 14477a6dacacSDimitry Andric 14487a6dacacSDimitry Andric void writeHasChildren(raw_ostream &OS) const override { OS << "true"; } 14497a6dacacSDimitry Andric }; 14507a6dacacSDimitry Andric 14510b57cec5SDimitry Andric } // end anonymous namespace 14520b57cec5SDimitry Andric 14530b57cec5SDimitry Andric static std::unique_ptr<Argument> 14540b57cec5SDimitry Andric createArgument(const Record &Arg, StringRef Attr, 14550b57cec5SDimitry Andric const Record *Search = nullptr) { 14560b57cec5SDimitry Andric if (!Search) 14570b57cec5SDimitry Andric Search = &Arg; 14580b57cec5SDimitry Andric 14590b57cec5SDimitry Andric std::unique_ptr<Argument> Ptr; 14600b57cec5SDimitry Andric llvm::StringRef ArgName = Search->getName(); 14610b57cec5SDimitry Andric 14620b57cec5SDimitry Andric if (ArgName == "AlignedArgument") 1463a7dea167SDimitry Andric Ptr = std::make_unique<AlignedArgument>(Arg, Attr); 14640b57cec5SDimitry Andric else if (ArgName == "EnumArgument") 1465a7dea167SDimitry Andric Ptr = std::make_unique<EnumArgument>(Arg, Attr); 14660b57cec5SDimitry Andric else if (ArgName == "ExprArgument") 1467a7dea167SDimitry Andric Ptr = std::make_unique<ExprArgument>(Arg, Attr); 14685ffd83dbSDimitry Andric else if (ArgName == "DeclArgument") 14695ffd83dbSDimitry Andric Ptr = std::make_unique<SimpleArgument>( 14705ffd83dbSDimitry Andric Arg, Attr, (Arg.getValueAsDef("Kind")->getName() + "Decl *").str()); 14710b57cec5SDimitry Andric else if (ArgName == "IdentifierArgument") 1472a7dea167SDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *"); 14730b57cec5SDimitry Andric else if (ArgName == "DefaultBoolArgument") 1474a7dea167SDimitry Andric Ptr = std::make_unique<DefaultSimpleArgument>( 14750b57cec5SDimitry Andric Arg, Attr, "bool", Arg.getValueAsBit("Default")); 14760b57cec5SDimitry Andric else if (ArgName == "BoolArgument") 1477a7dea167SDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "bool"); 14780b57cec5SDimitry Andric else if (ArgName == "DefaultIntArgument") 1479a7dea167SDimitry Andric Ptr = std::make_unique<DefaultSimpleArgument>( 14800b57cec5SDimitry Andric Arg, Attr, "int", Arg.getValueAsInt("Default")); 14810b57cec5SDimitry Andric else if (ArgName == "IntArgument") 1482a7dea167SDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "int"); 14830b57cec5SDimitry Andric else if (ArgName == "StringArgument") 1484a7dea167SDimitry Andric Ptr = std::make_unique<StringArgument>(Arg, Attr); 14850b57cec5SDimitry Andric else if (ArgName == "TypeArgument") 1486a7dea167SDimitry Andric Ptr = std::make_unique<TypeArgument>(Arg, Attr); 14870b57cec5SDimitry Andric else if (ArgName == "UnsignedArgument") 1488a7dea167SDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "unsigned"); 14890b57cec5SDimitry Andric else if (ArgName == "VariadicUnsignedArgument") 1490a7dea167SDimitry Andric Ptr = std::make_unique<VariadicArgument>(Arg, Attr, "unsigned"); 14910b57cec5SDimitry Andric else if (ArgName == "VariadicStringArgument") 1492a7dea167SDimitry Andric Ptr = std::make_unique<VariadicStringArgument>(Arg, Attr); 14930b57cec5SDimitry Andric else if (ArgName == "VariadicEnumArgument") 1494a7dea167SDimitry Andric Ptr = std::make_unique<VariadicEnumArgument>(Arg, Attr); 14950b57cec5SDimitry Andric else if (ArgName == "VariadicExprArgument") 1496a7dea167SDimitry Andric Ptr = std::make_unique<VariadicExprArgument>(Arg, Attr); 14970b57cec5SDimitry Andric else if (ArgName == "VariadicParamIdxArgument") 1498a7dea167SDimitry Andric Ptr = std::make_unique<VariadicParamIdxArgument>(Arg, Attr); 14990b57cec5SDimitry Andric else if (ArgName == "VariadicParamOrParamIdxArgument") 1500a7dea167SDimitry Andric Ptr = std::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr); 15010b57cec5SDimitry Andric else if (ArgName == "ParamIdxArgument") 1502a7dea167SDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx"); 15030b57cec5SDimitry Andric else if (ArgName == "VariadicIdentifierArgument") 1504a7dea167SDimitry Andric Ptr = std::make_unique<VariadicIdentifierArgument>(Arg, Attr); 15050b57cec5SDimitry Andric else if (ArgName == "VersionArgument") 1506a7dea167SDimitry Andric Ptr = std::make_unique<VersionArgument>(Arg, Attr); 15077a6dacacSDimitry Andric else if (ArgName == "WrappedAttr") 15087a6dacacSDimitry Andric Ptr = std::make_unique<WrappedAttr>(Arg, Attr); 15095ffd83dbSDimitry Andric else if (ArgName == "OMPTraitInfoArgument") 15105ffd83dbSDimitry Andric Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "OMPTraitInfo *"); 1511bdd1243dSDimitry Andric else if (ArgName == "VariadicOMPInteropInfoArgument") 1512bdd1243dSDimitry Andric Ptr = std::make_unique<VariadicOMPInteropInfoArgument>(Arg, Attr); 15130b57cec5SDimitry Andric 15140b57cec5SDimitry Andric if (!Ptr) { 15150b57cec5SDimitry Andric // Search in reverse order so that the most-derived type is handled first. 15160b57cec5SDimitry Andric ArrayRef<std::pair<Record*, SMRange>> Bases = Search->getSuperClasses(); 15170b57cec5SDimitry Andric for (const auto &Base : llvm::reverse(Bases)) { 15180b57cec5SDimitry Andric if ((Ptr = createArgument(Arg, Attr, Base.first))) 15190b57cec5SDimitry Andric break; 15200b57cec5SDimitry Andric } 15210b57cec5SDimitry Andric } 15220b57cec5SDimitry Andric 15230b57cec5SDimitry Andric if (Ptr && Arg.getValueAsBit("Optional")) 15240b57cec5SDimitry Andric Ptr->setOptional(true); 15250b57cec5SDimitry Andric 15260b57cec5SDimitry Andric if (Ptr && Arg.getValueAsBit("Fake")) 15270b57cec5SDimitry Andric Ptr->setFake(true); 15280b57cec5SDimitry Andric 15290b57cec5SDimitry Andric return Ptr; 15300b57cec5SDimitry Andric } 15310b57cec5SDimitry Andric 15320b57cec5SDimitry Andric static void writeAvailabilityValue(raw_ostream &OS) { 15330b57cec5SDimitry Andric OS << "\" << getPlatform()->getName();\n" 15340b57cec5SDimitry Andric << " if (getStrict()) OS << \", strict\";\n" 15350b57cec5SDimitry Andric << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" 15360b57cec5SDimitry Andric << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" 15370b57cec5SDimitry Andric << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" 15380b57cec5SDimitry Andric << " if (getUnavailable()) OS << \", unavailable\";\n" 15390b57cec5SDimitry Andric << " OS << \""; 15400b57cec5SDimitry Andric } 15410b57cec5SDimitry Andric 15420b57cec5SDimitry Andric static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) { 15430b57cec5SDimitry Andric OS << "\\\"\" << getMessage() << \"\\\"\";\n"; 15440b57cec5SDimitry Andric // Only GNU deprecated has an optional fixit argument at the second position. 15450b57cec5SDimitry Andric if (Variety == "GNU") 15460b57cec5SDimitry Andric OS << " if (!getReplacement().empty()) OS << \", \\\"\"" 15470b57cec5SDimitry Andric " << getReplacement() << \"\\\"\";\n"; 15480b57cec5SDimitry Andric OS << " OS << \""; 15490b57cec5SDimitry Andric } 15500b57cec5SDimitry Andric 15515ffd83dbSDimitry Andric static void writeGetSpellingFunction(const Record &R, raw_ostream &OS) { 15520b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); 15530b57cec5SDimitry Andric 15540b57cec5SDimitry Andric OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n"; 15550b57cec5SDimitry Andric if (Spellings.empty()) { 15560b57cec5SDimitry Andric OS << " return \"(No spelling)\";\n}\n\n"; 15570b57cec5SDimitry Andric return; 15580b57cec5SDimitry Andric } 15590b57cec5SDimitry Andric 1560a7dea167SDimitry Andric OS << " switch (getAttributeSpellingListIndex()) {\n" 15610b57cec5SDimitry Andric " default:\n" 15620b57cec5SDimitry Andric " llvm_unreachable(\"Unknown attribute spelling!\");\n" 15630b57cec5SDimitry Andric " return \"(No spelling)\";\n"; 15640b57cec5SDimitry Andric 15650b57cec5SDimitry Andric for (unsigned I = 0; I < Spellings.size(); ++I) 15660b57cec5SDimitry Andric OS << " case " << I << ":\n" 15670b57cec5SDimitry Andric " return \"" << Spellings[I].name() << "\";\n"; 15680b57cec5SDimitry Andric // End of the switch statement. 15690b57cec5SDimitry Andric OS << " }\n"; 15700b57cec5SDimitry Andric // End of the getSpelling function. 15710b57cec5SDimitry Andric OS << "}\n\n"; 15720b57cec5SDimitry Andric } 15730b57cec5SDimitry Andric 15740b57cec5SDimitry Andric static void 15755ffd83dbSDimitry Andric writePrettyPrintFunction(const Record &R, 15760b57cec5SDimitry Andric const std::vector<std::unique_ptr<Argument>> &Args, 15770b57cec5SDimitry Andric raw_ostream &OS) { 15780b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); 15790b57cec5SDimitry Andric 15800b57cec5SDimitry Andric OS << "void " << R.getName() << "Attr::printPretty(" 15810b57cec5SDimitry Andric << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n"; 15820b57cec5SDimitry Andric 15830b57cec5SDimitry Andric if (Spellings.empty()) { 15840b57cec5SDimitry Andric OS << "}\n\n"; 15850b57cec5SDimitry Andric return; 15860b57cec5SDimitry Andric } 15870b57cec5SDimitry Andric 1588fe6060f1SDimitry Andric OS << " bool IsFirstArgument = true; (void)IsFirstArgument;\n" 1589fe6060f1SDimitry Andric << " unsigned TrailingOmittedArgs = 0; (void)TrailingOmittedArgs;\n" 1590fe6060f1SDimitry Andric << " switch (getAttributeSpellingListIndex()) {\n" 1591fe6060f1SDimitry Andric << " default:\n" 1592fe6060f1SDimitry Andric << " llvm_unreachable(\"Unknown attribute spelling!\");\n" 1593fe6060f1SDimitry Andric << " break;\n"; 15940b57cec5SDimitry Andric 15950b57cec5SDimitry Andric for (unsigned I = 0; I < Spellings.size(); ++ I) { 15960b57cec5SDimitry Andric llvm::SmallString<16> Prefix; 15970b57cec5SDimitry Andric llvm::SmallString<8> Suffix; 15980b57cec5SDimitry Andric // The actual spelling of the name and namespace (if applicable) 15990b57cec5SDimitry Andric // of an attribute without considering prefix and suffix. 16000b57cec5SDimitry Andric llvm::SmallString<64> Spelling; 16010b57cec5SDimitry Andric std::string Name = Spellings[I].name(); 16020b57cec5SDimitry Andric std::string Variety = Spellings[I].variety(); 16030b57cec5SDimitry Andric 16040b57cec5SDimitry Andric if (Variety == "GNU") { 16050b57cec5SDimitry Andric Prefix = "__attribute__(("; 16060b57cec5SDimitry Andric Suffix = "))"; 16075f757f3fSDimitry Andric } else if (Variety == "CXX11" || Variety == "C23") { 16080b57cec5SDimitry Andric Prefix = "[["; 16090b57cec5SDimitry Andric Suffix = "]]"; 16100b57cec5SDimitry Andric std::string Namespace = Spellings[I].nameSpace(); 16110b57cec5SDimitry Andric if (!Namespace.empty()) { 16120b57cec5SDimitry Andric Spelling += Namespace; 16130b57cec5SDimitry Andric Spelling += "::"; 16140b57cec5SDimitry Andric } 16150b57cec5SDimitry Andric } else if (Variety == "Declspec") { 16160b57cec5SDimitry Andric Prefix = "__declspec("; 16170b57cec5SDimitry Andric Suffix = ")"; 16180b57cec5SDimitry Andric } else if (Variety == "Microsoft") { 16190b57cec5SDimitry Andric Prefix = "["; 16200b57cec5SDimitry Andric Suffix = "]"; 16210b57cec5SDimitry Andric } else if (Variety == "Keyword") { 16220b57cec5SDimitry Andric Prefix = ""; 16230b57cec5SDimitry Andric Suffix = ""; 16240b57cec5SDimitry Andric } else if (Variety == "Pragma") { 16250b57cec5SDimitry Andric Prefix = "#pragma "; 16260b57cec5SDimitry Andric Suffix = "\n"; 16270b57cec5SDimitry Andric std::string Namespace = Spellings[I].nameSpace(); 16280b57cec5SDimitry Andric if (!Namespace.empty()) { 16290b57cec5SDimitry Andric Spelling += Namespace; 16300b57cec5SDimitry Andric Spelling += " "; 16310b57cec5SDimitry Andric } 1632*0fca6ea1SDimitry Andric } else if (Variety == "HLSLAnnotation") { 163381ad6265SDimitry Andric Prefix = ":"; 163481ad6265SDimitry Andric Suffix = ""; 16350b57cec5SDimitry Andric } else { 16360b57cec5SDimitry Andric llvm_unreachable("Unknown attribute syntax variety!"); 16370b57cec5SDimitry Andric } 16380b57cec5SDimitry Andric 16390b57cec5SDimitry Andric Spelling += Name; 16400b57cec5SDimitry Andric 1641fe6060f1SDimitry Andric OS << " case " << I << " : {\n" 1642fe6060f1SDimitry Andric << " OS << \"" << Prefix << Spelling << "\";\n"; 16430b57cec5SDimitry Andric 16440b57cec5SDimitry Andric if (Variety == "Pragma") { 16450b57cec5SDimitry Andric OS << " printPrettyPragma(OS, Policy);\n"; 16460b57cec5SDimitry Andric OS << " OS << \"\\n\";"; 16470b57cec5SDimitry Andric OS << " break;\n"; 16480b57cec5SDimitry Andric OS << " }\n"; 16490b57cec5SDimitry Andric continue; 16500b57cec5SDimitry Andric } 16510b57cec5SDimitry Andric 16520b57cec5SDimitry Andric if (Spelling == "availability") { 1653fe6060f1SDimitry Andric OS << " OS << \"("; 16540b57cec5SDimitry Andric writeAvailabilityValue(OS); 1655fe6060f1SDimitry Andric OS << ")\";\n"; 16560b57cec5SDimitry Andric } else if (Spelling == "deprecated" || Spelling == "gnu::deprecated") { 1657fe6060f1SDimitry Andric OS << " OS << \"("; 16580b57cec5SDimitry Andric writeDeprecatedAttrValue(OS, Variety); 1659fe6060f1SDimitry Andric OS << ")\";\n"; 16600b57cec5SDimitry Andric } else { 16610b57cec5SDimitry Andric // To avoid printing parentheses around an empty argument list or 16620b57cec5SDimitry Andric // printing spurious commas at the end of an argument list, we need to 16630b57cec5SDimitry Andric // determine where the last provided non-fake argument is. 16640b57cec5SDimitry Andric bool FoundNonOptArg = false; 16650b57cec5SDimitry Andric for (const auto &arg : llvm::reverse(Args)) { 16660b57cec5SDimitry Andric if (arg->isFake()) 16670b57cec5SDimitry Andric continue; 16680b57cec5SDimitry Andric if (FoundNonOptArg) 16690b57cec5SDimitry Andric continue; 16700b57cec5SDimitry Andric // FIXME: arg->getIsOmitted() == "false" means we haven't implemented 16710b57cec5SDimitry Andric // any way to detect whether the argument was omitted. 16720b57cec5SDimitry Andric if (!arg->isOptional() || arg->getIsOmitted() == "false") { 16730b57cec5SDimitry Andric FoundNonOptArg = true; 16740b57cec5SDimitry Andric continue; 16750b57cec5SDimitry Andric } 16760b57cec5SDimitry Andric OS << " if (" << arg->getIsOmitted() << ")\n" 16770b57cec5SDimitry Andric << " ++TrailingOmittedArgs;\n"; 16780b57cec5SDimitry Andric } 16790b57cec5SDimitry Andric unsigned ArgIndex = 0; 16800b57cec5SDimitry Andric for (const auto &arg : Args) { 16810b57cec5SDimitry Andric if (arg->isFake()) 16820b57cec5SDimitry Andric continue; 16830b57cec5SDimitry Andric std::string IsOmitted = arg->getIsOmitted(); 16840b57cec5SDimitry Andric if (arg->isOptional() && IsOmitted != "false") 1685fe6060f1SDimitry Andric OS << " if (!(" << IsOmitted << ")) {\n"; 1686fe6060f1SDimitry Andric // Variadic arguments print their own leading comma. 1687fe6060f1SDimitry Andric if (!arg->isVariadic()) 1688fe6060f1SDimitry Andric OS << " DelimitAttributeArgument(OS, IsFirstArgument);\n"; 1689fe6060f1SDimitry Andric OS << " OS << \""; 16900b57cec5SDimitry Andric arg->writeValue(OS); 1691fe6060f1SDimitry Andric OS << "\";\n"; 16920b57cec5SDimitry Andric if (arg->isOptional() && IsOmitted != "false") 1693fe6060f1SDimitry Andric OS << " }\n"; 16940b57cec5SDimitry Andric ++ArgIndex; 16950b57cec5SDimitry Andric } 1696fe6060f1SDimitry Andric if (ArgIndex != 0) 1697fe6060f1SDimitry Andric OS << " if (!IsFirstArgument)\n" 1698fe6060f1SDimitry Andric << " OS << \")\";\n"; 16990b57cec5SDimitry Andric } 1700fe6060f1SDimitry Andric OS << " OS << \"" << Suffix << "\";\n" 1701fe6060f1SDimitry Andric << " break;\n" 1702fe6060f1SDimitry Andric << " }\n"; 17030b57cec5SDimitry Andric } 17040b57cec5SDimitry Andric 17050b57cec5SDimitry Andric // End of the switch statement. 17060b57cec5SDimitry Andric OS << "}\n"; 17070b57cec5SDimitry Andric // End of the print function. 17080b57cec5SDimitry Andric OS << "}\n\n"; 17090b57cec5SDimitry Andric } 17100b57cec5SDimitry Andric 17110b57cec5SDimitry Andric /// Return the index of a spelling in a spelling list. 17120b57cec5SDimitry Andric static unsigned 17130b57cec5SDimitry Andric getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList, 17140b57cec5SDimitry Andric const FlattenedSpelling &Spelling) { 17150b57cec5SDimitry Andric assert(!SpellingList.empty() && "Spelling list is empty!"); 17160b57cec5SDimitry Andric 17170b57cec5SDimitry Andric for (unsigned Index = 0; Index < SpellingList.size(); ++Index) { 17180b57cec5SDimitry Andric const FlattenedSpelling &S = SpellingList[Index]; 17190b57cec5SDimitry Andric if (S.variety() != Spelling.variety()) 17200b57cec5SDimitry Andric continue; 17210b57cec5SDimitry Andric if (S.nameSpace() != Spelling.nameSpace()) 17220b57cec5SDimitry Andric continue; 17230b57cec5SDimitry Andric if (S.name() != Spelling.name()) 17240b57cec5SDimitry Andric continue; 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric return Index; 17270b57cec5SDimitry Andric } 17280b57cec5SDimitry Andric 17290b57cec5SDimitry Andric llvm_unreachable("Unknown spelling!"); 17300b57cec5SDimitry Andric } 17310b57cec5SDimitry Andric 17320b57cec5SDimitry Andric static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { 17330b57cec5SDimitry Andric std::vector<Record*> Accessors = R.getValueAsListOfDefs("Accessors"); 17340b57cec5SDimitry Andric if (Accessors.empty()) 17350b57cec5SDimitry Andric return; 17360b57cec5SDimitry Andric 17370b57cec5SDimitry Andric const std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(R); 17380b57cec5SDimitry Andric assert(!SpellingList.empty() && 17390b57cec5SDimitry Andric "Attribute with empty spelling list can't have accessors!"); 17400b57cec5SDimitry Andric for (const auto *Accessor : Accessors) { 17410b57cec5SDimitry Andric const StringRef Name = Accessor->getValueAsString("Name"); 17420b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor); 17430b57cec5SDimitry Andric 1744a7dea167SDimitry Andric OS << " bool " << Name 1745a7dea167SDimitry Andric << "() const { return getAttributeSpellingListIndex() == "; 17460b57cec5SDimitry Andric for (unsigned Index = 0; Index < Spellings.size(); ++Index) { 17470b57cec5SDimitry Andric OS << getSpellingListIndex(SpellingList, Spellings[Index]); 17480b57cec5SDimitry Andric if (Index != Spellings.size() - 1) 1749a7dea167SDimitry Andric OS << " ||\n getAttributeSpellingListIndex() == "; 17500b57cec5SDimitry Andric else 17510b57cec5SDimitry Andric OS << "; }\n"; 17520b57cec5SDimitry Andric } 17530b57cec5SDimitry Andric } 17540b57cec5SDimitry Andric } 17550b57cec5SDimitry Andric 17560b57cec5SDimitry Andric static bool 17570b57cec5SDimitry Andric SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) { 17580b57cec5SDimitry Andric assert(!Spellings.empty() && "An empty list of spellings was provided"); 17595ffd83dbSDimitry Andric std::string FirstName = 17605ffd83dbSDimitry Andric std::string(NormalizeNameForSpellingComparison(Spellings.front().name())); 17617a6dacacSDimitry Andric for (const auto &Spelling : llvm::drop_begin(Spellings)) { 17625ffd83dbSDimitry Andric std::string Name = 17635ffd83dbSDimitry Andric std::string(NormalizeNameForSpellingComparison(Spelling.name())); 17640b57cec5SDimitry Andric if (Name != FirstName) 17650b57cec5SDimitry Andric return false; 17660b57cec5SDimitry Andric } 17670b57cec5SDimitry Andric return true; 17680b57cec5SDimitry Andric } 17690b57cec5SDimitry Andric 17700b57cec5SDimitry Andric typedef std::map<unsigned, std::string> SemanticSpellingMap; 17710b57cec5SDimitry Andric static std::string 17720b57cec5SDimitry Andric CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings, 17730b57cec5SDimitry Andric SemanticSpellingMap &Map) { 17740b57cec5SDimitry Andric // The enumerants are automatically generated based on the variety, 17750b57cec5SDimitry Andric // namespace (if present) and name for each attribute spelling. However, 17760b57cec5SDimitry Andric // care is taken to avoid trampling on the reserved namespace due to 17770b57cec5SDimitry Andric // underscores. 17780b57cec5SDimitry Andric std::string Ret(" enum Spelling {\n"); 17790b57cec5SDimitry Andric std::set<std::string> Uniques; 17800b57cec5SDimitry Andric unsigned Idx = 0; 1781a7dea167SDimitry Andric 1782a7dea167SDimitry Andric // If we have a need to have this many spellings we likely need to add an 1783a7dea167SDimitry Andric // extra bit to the SpellingIndex in AttributeCommonInfo, then increase the 1784a7dea167SDimitry Andric // value of SpellingNotCalculated there and here. 1785a7dea167SDimitry Andric assert(Spellings.size() < 15 && 1786a7dea167SDimitry Andric "Too many spellings, would step on SpellingNotCalculated in " 1787a7dea167SDimitry Andric "AttributeCommonInfo"); 17880b57cec5SDimitry Andric for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) { 17890b57cec5SDimitry Andric const FlattenedSpelling &S = *I; 17900b57cec5SDimitry Andric const std::string &Variety = S.variety(); 17910b57cec5SDimitry Andric const std::string &Spelling = S.name(); 17920b57cec5SDimitry Andric const std::string &Namespace = S.nameSpace(); 17930b57cec5SDimitry Andric std::string EnumName; 17940b57cec5SDimitry Andric 17950b57cec5SDimitry Andric EnumName += (Variety + "_"); 17960b57cec5SDimitry Andric if (!Namespace.empty()) 17970b57cec5SDimitry Andric EnumName += (NormalizeNameForSpellingComparison(Namespace).str() + 17980b57cec5SDimitry Andric "_"); 17990b57cec5SDimitry Andric EnumName += NormalizeNameForSpellingComparison(Spelling); 18000b57cec5SDimitry Andric 18010b57cec5SDimitry Andric // Even if the name is not unique, this spelling index corresponds to a 18020b57cec5SDimitry Andric // particular enumerant name that we've calculated. 18030b57cec5SDimitry Andric Map[Idx] = EnumName; 18040b57cec5SDimitry Andric 18050b57cec5SDimitry Andric // Since we have been stripping underscores to avoid trampling on the 18060b57cec5SDimitry Andric // reserved namespace, we may have inadvertently created duplicate 18070b57cec5SDimitry Andric // enumerant names. These duplicates are not considered part of the 18080b57cec5SDimitry Andric // semantic spelling, and can be elided. 18090b57cec5SDimitry Andric if (Uniques.find(EnumName) != Uniques.end()) 18100b57cec5SDimitry Andric continue; 18110b57cec5SDimitry Andric 18120b57cec5SDimitry Andric Uniques.insert(EnumName); 18130b57cec5SDimitry Andric if (I != Spellings.begin()) 18140b57cec5SDimitry Andric Ret += ",\n"; 18150b57cec5SDimitry Andric // Duplicate spellings are not considered part of the semantic spelling 18160b57cec5SDimitry Andric // enumeration, but the spelling index and semantic spelling values are 18170b57cec5SDimitry Andric // meant to be equivalent, so we must specify a concrete value for each 18180b57cec5SDimitry Andric // enumerator. 18190b57cec5SDimitry Andric Ret += " " + EnumName + " = " + llvm::utostr(Idx); 18200b57cec5SDimitry Andric } 1821a7dea167SDimitry Andric Ret += ",\n SpellingNotCalculated = 15\n"; 18220b57cec5SDimitry Andric Ret += "\n };\n\n"; 18230b57cec5SDimitry Andric return Ret; 18240b57cec5SDimitry Andric } 18250b57cec5SDimitry Andric 18260b57cec5SDimitry Andric void WriteSemanticSpellingSwitch(const std::string &VarName, 18270b57cec5SDimitry Andric const SemanticSpellingMap &Map, 18280b57cec5SDimitry Andric raw_ostream &OS) { 18290b57cec5SDimitry Andric OS << " switch (" << VarName << ") {\n default: " 18300b57cec5SDimitry Andric << "llvm_unreachable(\"Unknown spelling list index\");\n"; 18310b57cec5SDimitry Andric for (const auto &I : Map) 18320b57cec5SDimitry Andric OS << " case " << I.first << ": return " << I.second << ";\n"; 18330b57cec5SDimitry Andric OS << " }\n"; 18340b57cec5SDimitry Andric } 18350b57cec5SDimitry Andric 1836*0fca6ea1SDimitry Andric // Note: these values need to match the values used by LateAttrParseKind in 1837*0fca6ea1SDimitry Andric // `Attr.td` 1838*0fca6ea1SDimitry Andric enum class LateAttrParseKind { Never = 0, Standard = 1, ExperimentalExt = 2 }; 1839*0fca6ea1SDimitry Andric 1840*0fca6ea1SDimitry Andric static LateAttrParseKind getLateAttrParseKind(const Record *Attr) { 1841*0fca6ea1SDimitry Andric // This function basically does 1842*0fca6ea1SDimitry Andric // `Attr->getValueAsDef("LateParsed")->getValueAsInt("Kind")` but does a bunch 1843*0fca6ea1SDimitry Andric // of sanity checking to ensure that `LateAttrParseMode` in `Attr.td` is in 1844*0fca6ea1SDimitry Andric // sync with the `LateAttrParseKind` enum in this source file. 1845*0fca6ea1SDimitry Andric 1846*0fca6ea1SDimitry Andric static constexpr StringRef LateParsedStr = "LateParsed"; 1847*0fca6ea1SDimitry Andric static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind"; 1848*0fca6ea1SDimitry Andric static constexpr StringRef KindFieldStr = "Kind"; 1849*0fca6ea1SDimitry Andric 1850*0fca6ea1SDimitry Andric auto *LAPK = Attr->getValueAsDef(LateParsedStr); 1851*0fca6ea1SDimitry Andric 1852*0fca6ea1SDimitry Andric // Typecheck the `LateParsed` field. 1853*0fca6ea1SDimitry Andric SmallVector<Record *, 1> SuperClasses; 1854*0fca6ea1SDimitry Andric LAPK->getDirectSuperClasses(SuperClasses); 1855*0fca6ea1SDimitry Andric if (SuperClasses.size() != 1) 1856*0fca6ea1SDimitry Andric PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + 1857*0fca6ea1SDimitry Andric "`should only have one super class"); 1858*0fca6ea1SDimitry Andric 1859*0fca6ea1SDimitry Andric if (SuperClasses[0]->getName() != LateAttrParseKindStr) 1860*0fca6ea1SDimitry Andric PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + 1861*0fca6ea1SDimitry Andric "`should only have type `" + 1862*0fca6ea1SDimitry Andric llvm::Twine(LateAttrParseKindStr) + 1863*0fca6ea1SDimitry Andric "` but found type `" + 1864*0fca6ea1SDimitry Andric SuperClasses[0]->getName() + "`"); 1865*0fca6ea1SDimitry Andric 1866*0fca6ea1SDimitry Andric // Get Kind and verify the enum name matches the name in `Attr.td`. 1867*0fca6ea1SDimitry Andric unsigned Kind = LAPK->getValueAsInt(KindFieldStr); 1868*0fca6ea1SDimitry Andric switch (LateAttrParseKind(Kind)) { 1869*0fca6ea1SDimitry Andric #define CASE(X) \ 1870*0fca6ea1SDimitry Andric case LateAttrParseKind::X: \ 1871*0fca6ea1SDimitry Andric if (LAPK->getName().compare("LateAttrParse" #X) != 0) { \ 1872*0fca6ea1SDimitry Andric PrintFatalError(Attr, \ 1873*0fca6ea1SDimitry Andric "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + \ 1874*0fca6ea1SDimitry Andric LAPK->getName() + \ 1875*0fca6ea1SDimitry Andric "` but this converts to `LateAttrParseKind::" + \ 1876*0fca6ea1SDimitry Andric llvm::Twine(#X) + "`"); \ 1877*0fca6ea1SDimitry Andric } \ 1878*0fca6ea1SDimitry Andric return LateAttrParseKind::X; 1879*0fca6ea1SDimitry Andric 1880*0fca6ea1SDimitry Andric CASE(Never) 1881*0fca6ea1SDimitry Andric CASE(Standard) 1882*0fca6ea1SDimitry Andric CASE(ExperimentalExt) 1883*0fca6ea1SDimitry Andric #undef CASE 1884*0fca6ea1SDimitry Andric } 1885*0fca6ea1SDimitry Andric 1886*0fca6ea1SDimitry Andric // The Kind value is completely invalid 1887*0fca6ea1SDimitry Andric auto KindValueStr = llvm::utostr(Kind); 1888*0fca6ea1SDimitry Andric PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + 1889*0fca6ea1SDimitry Andric LAPK->getName() + "` has unexpected `" + 1890*0fca6ea1SDimitry Andric llvm::Twine(KindFieldStr) + "` value of " + 1891*0fca6ea1SDimitry Andric KindValueStr); 1892*0fca6ea1SDimitry Andric } 1893*0fca6ea1SDimitry Andric 18940b57cec5SDimitry Andric // Emits the LateParsed property for attributes. 1895*0fca6ea1SDimitry Andric static void emitClangAttrLateParsedListImpl(RecordKeeper &Records, 1896*0fca6ea1SDimitry Andric raw_ostream &OS, 1897*0fca6ea1SDimitry Andric LateAttrParseKind LateParseMode) { 18980b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 18990b57cec5SDimitry Andric 19000b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 1901*0fca6ea1SDimitry Andric if (LateAttrParseKind LateParsed = getLateAttrParseKind(Attr); 1902*0fca6ea1SDimitry Andric LateParsed != LateParseMode) 1903*0fca6ea1SDimitry Andric continue; 19040b57cec5SDimitry Andric 19050b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr); 19060b57cec5SDimitry Andric 19070b57cec5SDimitry Andric // FIXME: Handle non-GNU attributes 19080b57cec5SDimitry Andric for (const auto &I : Spellings) { 19090b57cec5SDimitry Andric if (I.variety() != "GNU") 19100b57cec5SDimitry Andric continue; 1911*0fca6ea1SDimitry Andric OS << ".Case(\"" << I.name() << "\", 1)\n"; 19120b57cec5SDimitry Andric } 19130b57cec5SDimitry Andric } 19140b57cec5SDimitry Andric } 1915*0fca6ea1SDimitry Andric 1916*0fca6ea1SDimitry Andric static void emitClangAttrLateParsedList(RecordKeeper &Records, 1917*0fca6ea1SDimitry Andric raw_ostream &OS) { 1918*0fca6ea1SDimitry Andric OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; 1919*0fca6ea1SDimitry Andric emitClangAttrLateParsedListImpl(Records, OS, LateAttrParseKind::Standard); 19200b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; 19210b57cec5SDimitry Andric } 19220b57cec5SDimitry Andric 1923*0fca6ea1SDimitry Andric static void emitClangAttrLateParsedExperimentalList(RecordKeeper &Records, 1924*0fca6ea1SDimitry Andric raw_ostream &OS) { 1925*0fca6ea1SDimitry Andric OS << "#if defined(CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST)\n"; 1926*0fca6ea1SDimitry Andric emitClangAttrLateParsedListImpl(Records, OS, 1927*0fca6ea1SDimitry Andric LateAttrParseKind::ExperimentalExt); 1928*0fca6ea1SDimitry Andric OS << "#endif // CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST\n\n"; 1929*0fca6ea1SDimitry Andric } 1930*0fca6ea1SDimitry Andric 19310b57cec5SDimitry Andric static bool hasGNUorCXX11Spelling(const Record &Attribute) { 19320b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); 19330b57cec5SDimitry Andric for (const auto &I : Spellings) { 19340b57cec5SDimitry Andric if (I.variety() == "GNU" || I.variety() == "CXX11") 19350b57cec5SDimitry Andric return true; 19360b57cec5SDimitry Andric } 19370b57cec5SDimitry Andric return false; 19380b57cec5SDimitry Andric } 19390b57cec5SDimitry Andric 19400b57cec5SDimitry Andric namespace { 19410b57cec5SDimitry Andric 19420b57cec5SDimitry Andric struct AttributeSubjectMatchRule { 19430b57cec5SDimitry Andric const Record *MetaSubject; 19440b57cec5SDimitry Andric const Record *Constraint; 19450b57cec5SDimitry Andric 19460b57cec5SDimitry Andric AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint) 19470b57cec5SDimitry Andric : MetaSubject(MetaSubject), Constraint(Constraint) { 19480b57cec5SDimitry Andric assert(MetaSubject && "Missing subject"); 19490b57cec5SDimitry Andric } 19500b57cec5SDimitry Andric 19510b57cec5SDimitry Andric bool isSubRule() const { return Constraint != nullptr; } 19520b57cec5SDimitry Andric 19530b57cec5SDimitry Andric std::vector<Record *> getSubjects() const { 19540b57cec5SDimitry Andric return (Constraint ? Constraint : MetaSubject) 19550b57cec5SDimitry Andric ->getValueAsListOfDefs("Subjects"); 19560b57cec5SDimitry Andric } 19570b57cec5SDimitry Andric 19580b57cec5SDimitry Andric std::vector<Record *> getLangOpts() const { 19590b57cec5SDimitry Andric if (Constraint) { 19600b57cec5SDimitry Andric // Lookup the options in the sub-rule first, in case the sub-rule 19610b57cec5SDimitry Andric // overrides the rules options. 19620b57cec5SDimitry Andric std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts"); 19630b57cec5SDimitry Andric if (!Opts.empty()) 19640b57cec5SDimitry Andric return Opts; 19650b57cec5SDimitry Andric } 19660b57cec5SDimitry Andric return MetaSubject->getValueAsListOfDefs("LangOpts"); 19670b57cec5SDimitry Andric } 19680b57cec5SDimitry Andric 19690b57cec5SDimitry Andric // Abstract rules are used only for sub-rules 19700b57cec5SDimitry Andric bool isAbstractRule() const { return getSubjects().empty(); } 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric StringRef getName() const { 19730b57cec5SDimitry Andric return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name"); 19740b57cec5SDimitry Andric } 19750b57cec5SDimitry Andric 19760b57cec5SDimitry Andric bool isNegatedSubRule() const { 19770b57cec5SDimitry Andric assert(isSubRule() && "Not a sub-rule"); 19780b57cec5SDimitry Andric return Constraint->getValueAsBit("Negated"); 19790b57cec5SDimitry Andric } 19800b57cec5SDimitry Andric 19810b57cec5SDimitry Andric std::string getSpelling() const { 19825ffd83dbSDimitry Andric std::string Result = std::string(MetaSubject->getValueAsString("Name")); 19830b57cec5SDimitry Andric if (isSubRule()) { 19840b57cec5SDimitry Andric Result += '('; 19850b57cec5SDimitry Andric if (isNegatedSubRule()) 19860b57cec5SDimitry Andric Result += "unless("; 19870b57cec5SDimitry Andric Result += getName(); 19880b57cec5SDimitry Andric if (isNegatedSubRule()) 19890b57cec5SDimitry Andric Result += ')'; 19900b57cec5SDimitry Andric Result += ')'; 19910b57cec5SDimitry Andric } 19920b57cec5SDimitry Andric return Result; 19930b57cec5SDimitry Andric } 19940b57cec5SDimitry Andric 19950b57cec5SDimitry Andric std::string getEnumValueName() const { 19960b57cec5SDimitry Andric SmallString<128> Result; 19970b57cec5SDimitry Andric Result += "SubjectMatchRule_"; 19980b57cec5SDimitry Andric Result += MetaSubject->getValueAsString("Name"); 19990b57cec5SDimitry Andric if (isSubRule()) { 20000b57cec5SDimitry Andric Result += "_"; 20010b57cec5SDimitry Andric if (isNegatedSubRule()) 20020b57cec5SDimitry Andric Result += "not_"; 20030b57cec5SDimitry Andric Result += Constraint->getValueAsString("Name"); 20040b57cec5SDimitry Andric } 20050b57cec5SDimitry Andric if (isAbstractRule()) 20060b57cec5SDimitry Andric Result += "_abstract"; 20077a6dacacSDimitry Andric return std::string(Result); 20080b57cec5SDimitry Andric } 20090b57cec5SDimitry Andric 20100b57cec5SDimitry Andric std::string getEnumValue() const { return "attr::" + getEnumValueName(); } 20110b57cec5SDimitry Andric 20120b57cec5SDimitry Andric static const char *EnumName; 20130b57cec5SDimitry Andric }; 20140b57cec5SDimitry Andric 20150b57cec5SDimitry Andric const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule"; 20160b57cec5SDimitry Andric 20170b57cec5SDimitry Andric struct PragmaClangAttributeSupport { 20180b57cec5SDimitry Andric std::vector<AttributeSubjectMatchRule> Rules; 20190b57cec5SDimitry Andric 20200b57cec5SDimitry Andric class RuleOrAggregateRuleSet { 20210b57cec5SDimitry Andric std::vector<AttributeSubjectMatchRule> Rules; 20220b57cec5SDimitry Andric bool IsRule; 20230b57cec5SDimitry Andric RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules, 20240b57cec5SDimitry Andric bool IsRule) 20250b57cec5SDimitry Andric : Rules(Rules), IsRule(IsRule) {} 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric public: 20280b57cec5SDimitry Andric bool isRule() const { return IsRule; } 20290b57cec5SDimitry Andric 20300b57cec5SDimitry Andric const AttributeSubjectMatchRule &getRule() const { 20310b57cec5SDimitry Andric assert(IsRule && "not a rule!"); 20320b57cec5SDimitry Andric return Rules[0]; 20330b57cec5SDimitry Andric } 20340b57cec5SDimitry Andric 20350b57cec5SDimitry Andric ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const { 20360b57cec5SDimitry Andric return Rules; 20370b57cec5SDimitry Andric } 20380b57cec5SDimitry Andric 20390b57cec5SDimitry Andric static RuleOrAggregateRuleSet 20400b57cec5SDimitry Andric getRule(const AttributeSubjectMatchRule &Rule) { 20410b57cec5SDimitry Andric return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true); 20420b57cec5SDimitry Andric } 20430b57cec5SDimitry Andric static RuleOrAggregateRuleSet 20440b57cec5SDimitry Andric getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) { 20450b57cec5SDimitry Andric return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false); 20460b57cec5SDimitry Andric } 20470b57cec5SDimitry Andric }; 20480b57cec5SDimitry Andric llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules; 20490b57cec5SDimitry Andric 20500b57cec5SDimitry Andric PragmaClangAttributeSupport(RecordKeeper &Records); 20510b57cec5SDimitry Andric 20520b57cec5SDimitry Andric bool isAttributedSupported(const Record &Attribute); 20530b57cec5SDimitry Andric 20540b57cec5SDimitry Andric void emitMatchRuleList(raw_ostream &OS); 20550b57cec5SDimitry Andric 20565ffd83dbSDimitry Andric void generateStrictConformsTo(const Record &Attr, raw_ostream &OS); 20570b57cec5SDimitry Andric 20580b57cec5SDimitry Andric void generateParsingHelpers(raw_ostream &OS); 20590b57cec5SDimitry Andric }; 20600b57cec5SDimitry Andric 20610b57cec5SDimitry Andric } // end anonymous namespace 20620b57cec5SDimitry Andric 2063fe6060f1SDimitry Andric static bool isSupportedPragmaClangAttributeSubject(const Record &Subject) { 2064fe6060f1SDimitry Andric // FIXME: #pragma clang attribute does not currently support statement 2065fe6060f1SDimitry Andric // attributes, so test whether the subject is one that appertains to a 2066fe6060f1SDimitry Andric // declaration node. However, it may be reasonable for support for statement 2067fe6060f1SDimitry Andric // attributes to be added. 2068fe6060f1SDimitry Andric if (Subject.isSubClassOf("DeclNode") || Subject.isSubClassOf("DeclBase") || 2069fe6060f1SDimitry Andric Subject.getName() == "DeclBase") 2070fe6060f1SDimitry Andric return true; 2071fe6060f1SDimitry Andric 2072fe6060f1SDimitry Andric if (Subject.isSubClassOf("SubsetSubject")) 2073fe6060f1SDimitry Andric return isSupportedPragmaClangAttributeSubject( 2074fe6060f1SDimitry Andric *Subject.getValueAsDef("Base")); 2075fe6060f1SDimitry Andric 2076fe6060f1SDimitry Andric return false; 2077fe6060f1SDimitry Andric } 2078fe6060f1SDimitry Andric 20790b57cec5SDimitry Andric static bool doesDeclDeriveFrom(const Record *D, const Record *Base) { 2080480093f4SDimitry Andric const Record *CurrentBase = D->getValueAsOptionalDef(BaseFieldName); 20810b57cec5SDimitry Andric if (!CurrentBase) 20820b57cec5SDimitry Andric return false; 20830b57cec5SDimitry Andric if (CurrentBase == Base) 20840b57cec5SDimitry Andric return true; 20850b57cec5SDimitry Andric return doesDeclDeriveFrom(CurrentBase, Base); 20860b57cec5SDimitry Andric } 20870b57cec5SDimitry Andric 20880b57cec5SDimitry Andric PragmaClangAttributeSupport::PragmaClangAttributeSupport( 20890b57cec5SDimitry Andric RecordKeeper &Records) { 20900b57cec5SDimitry Andric std::vector<Record *> MetaSubjects = 20910b57cec5SDimitry Andric Records.getAllDerivedDefinitions("AttrSubjectMatcherRule"); 20920b57cec5SDimitry Andric auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, 20930b57cec5SDimitry Andric const Record *MetaSubject, 20940b57cec5SDimitry Andric const Record *Constraint) { 20950b57cec5SDimitry Andric Rules.emplace_back(MetaSubject, Constraint); 20960b57cec5SDimitry Andric std::vector<Record *> ApplicableSubjects = 20970b57cec5SDimitry Andric SubjectContainer->getValueAsListOfDefs("Subjects"); 20980b57cec5SDimitry Andric for (const auto *Subject : ApplicableSubjects) { 20990b57cec5SDimitry Andric bool Inserted = 21000b57cec5SDimitry Andric SubjectsToRules 21010b57cec5SDimitry Andric .try_emplace(Subject, RuleOrAggregateRuleSet::getRule( 21020b57cec5SDimitry Andric AttributeSubjectMatchRule(MetaSubject, 21030b57cec5SDimitry Andric Constraint))) 21040b57cec5SDimitry Andric .second; 21050b57cec5SDimitry Andric if (!Inserted) { 21060b57cec5SDimitry Andric PrintFatalError("Attribute subject match rules should not represent" 21070b57cec5SDimitry Andric "same attribute subjects."); 21080b57cec5SDimitry Andric } 21090b57cec5SDimitry Andric } 21100b57cec5SDimitry Andric }; 21110b57cec5SDimitry Andric for (const auto *MetaSubject : MetaSubjects) { 21120b57cec5SDimitry Andric MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr); 21130b57cec5SDimitry Andric std::vector<Record *> Constraints = 21140b57cec5SDimitry Andric MetaSubject->getValueAsListOfDefs("Constraints"); 21150b57cec5SDimitry Andric for (const auto *Constraint : Constraints) 21160b57cec5SDimitry Andric MapFromSubjectsToRules(Constraint, MetaSubject, Constraint); 21170b57cec5SDimitry Andric } 21180b57cec5SDimitry Andric 21190b57cec5SDimitry Andric std::vector<Record *> Aggregates = 21200b57cec5SDimitry Andric Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule"); 2121480093f4SDimitry Andric std::vector<Record *> DeclNodes = 2122480093f4SDimitry Andric Records.getAllDerivedDefinitions(DeclNodeClassName); 21230b57cec5SDimitry Andric for (const auto *Aggregate : Aggregates) { 21240b57cec5SDimitry Andric Record *SubjectDecl = Aggregate->getValueAsDef("Subject"); 21250b57cec5SDimitry Andric 21260b57cec5SDimitry Andric // Gather sub-classes of the aggregate subject that act as attribute 21270b57cec5SDimitry Andric // subject rules. 21280b57cec5SDimitry Andric std::vector<AttributeSubjectMatchRule> Rules; 21290b57cec5SDimitry Andric for (const auto *D : DeclNodes) { 21300b57cec5SDimitry Andric if (doesDeclDeriveFrom(D, SubjectDecl)) { 21310b57cec5SDimitry Andric auto It = SubjectsToRules.find(D); 21320b57cec5SDimitry Andric if (It == SubjectsToRules.end()) 21330b57cec5SDimitry Andric continue; 21340b57cec5SDimitry Andric if (!It->second.isRule() || It->second.getRule().isSubRule()) 21350b57cec5SDimitry Andric continue; // Assume that the rule will be included as well. 21360b57cec5SDimitry Andric Rules.push_back(It->second.getRule()); 21370b57cec5SDimitry Andric } 21380b57cec5SDimitry Andric } 21390b57cec5SDimitry Andric 21400b57cec5SDimitry Andric bool Inserted = 21410b57cec5SDimitry Andric SubjectsToRules 21420b57cec5SDimitry Andric .try_emplace(SubjectDecl, 21430b57cec5SDimitry Andric RuleOrAggregateRuleSet::getAggregateRuleSet(Rules)) 21440b57cec5SDimitry Andric .second; 21450b57cec5SDimitry Andric if (!Inserted) { 21460b57cec5SDimitry Andric PrintFatalError("Attribute subject match rules should not represent" 21470b57cec5SDimitry Andric "same attribute subjects."); 21480b57cec5SDimitry Andric } 21490b57cec5SDimitry Andric } 21500b57cec5SDimitry Andric } 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric static PragmaClangAttributeSupport & 21530b57cec5SDimitry Andric getPragmaAttributeSupport(RecordKeeper &Records) { 21540b57cec5SDimitry Andric static PragmaClangAttributeSupport Instance(Records); 21550b57cec5SDimitry Andric return Instance; 21560b57cec5SDimitry Andric } 21570b57cec5SDimitry Andric 21580b57cec5SDimitry Andric void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) { 21590b57cec5SDimitry Andric OS << "#ifndef ATTR_MATCH_SUB_RULE\n"; 21600b57cec5SDimitry Andric OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, " 21610b57cec5SDimitry Andric "IsNegated) " 21620b57cec5SDimitry Andric << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n"; 21630b57cec5SDimitry Andric OS << "#endif\n"; 21640b57cec5SDimitry Andric for (const auto &Rule : Rules) { 21650b57cec5SDimitry Andric OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '('; 21660b57cec5SDimitry Andric OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", " 21670b57cec5SDimitry Andric << Rule.isAbstractRule(); 21680b57cec5SDimitry Andric if (Rule.isSubRule()) 21690b57cec5SDimitry Andric OS << ", " 21700b57cec5SDimitry Andric << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue() 21710b57cec5SDimitry Andric << ", " << Rule.isNegatedSubRule(); 21720b57cec5SDimitry Andric OS << ")\n"; 21730b57cec5SDimitry Andric } 21740b57cec5SDimitry Andric OS << "#undef ATTR_MATCH_SUB_RULE\n"; 21750b57cec5SDimitry Andric } 21760b57cec5SDimitry Andric 21770b57cec5SDimitry Andric bool PragmaClangAttributeSupport::isAttributedSupported( 21780b57cec5SDimitry Andric const Record &Attribute) { 21790b57cec5SDimitry Andric // If the attribute explicitly specified whether to support #pragma clang 21800b57cec5SDimitry Andric // attribute, use that setting. 21810b57cec5SDimitry Andric bool Unset; 21820b57cec5SDimitry Andric bool SpecifiedResult = 21830b57cec5SDimitry Andric Attribute.getValueAsBitOrUnset("PragmaAttributeSupport", Unset); 21840b57cec5SDimitry Andric if (!Unset) 21850b57cec5SDimitry Andric return SpecifiedResult; 21860b57cec5SDimitry Andric 21870b57cec5SDimitry Andric // Opt-out rules: 2188*0fca6ea1SDimitry Andric 2189*0fca6ea1SDimitry Andric // An attribute requires delayed parsing (LateParsed is on). 2190*0fca6ea1SDimitry Andric switch (getLateAttrParseKind(&Attribute)) { 2191*0fca6ea1SDimitry Andric case LateAttrParseKind::Never: 2192*0fca6ea1SDimitry Andric break; 2193*0fca6ea1SDimitry Andric case LateAttrParseKind::Standard: 21940b57cec5SDimitry Andric return false; 2195*0fca6ea1SDimitry Andric case LateAttrParseKind::ExperimentalExt: 2196*0fca6ea1SDimitry Andric // This is only late parsed in certain parsing contexts when 2197*0fca6ea1SDimitry Andric // `LangOpts.ExperimentalLateParseAttributes` is true. Information about the 2198*0fca6ea1SDimitry Andric // parsing context and `LangOpts` is not available in this method so just 2199*0fca6ea1SDimitry Andric // opt this attribute out. 2200*0fca6ea1SDimitry Andric return false; 2201*0fca6ea1SDimitry Andric } 2202*0fca6ea1SDimitry Andric 22030b57cec5SDimitry Andric // An attribute has no GNU/CXX11 spelling 22040b57cec5SDimitry Andric if (!hasGNUorCXX11Spelling(Attribute)) 22050b57cec5SDimitry Andric return false; 22060b57cec5SDimitry Andric // An attribute subject list has a subject that isn't covered by one of the 22070b57cec5SDimitry Andric // subject match rules or has no subjects at all. 22080b57cec5SDimitry Andric if (Attribute.isValueUnset("Subjects")) 22090b57cec5SDimitry Andric return false; 22100b57cec5SDimitry Andric const Record *SubjectObj = Attribute.getValueAsDef("Subjects"); 22110b57cec5SDimitry Andric std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); 2212fe6060f1SDimitry Andric bool HasAtLeastOneValidSubject = false; 22130b57cec5SDimitry Andric for (const auto *Subject : Subjects) { 2214fe6060f1SDimitry Andric if (!isSupportedPragmaClangAttributeSubject(*Subject)) 2215fe6060f1SDimitry Andric continue; 221606c3fb27SDimitry Andric if (!SubjectsToRules.contains(Subject)) 22170b57cec5SDimitry Andric return false; 2218fe6060f1SDimitry Andric HasAtLeastOneValidSubject = true; 22190b57cec5SDimitry Andric } 2220fe6060f1SDimitry Andric return HasAtLeastOneValidSubject; 22210b57cec5SDimitry Andric } 22220b57cec5SDimitry Andric 22230b57cec5SDimitry Andric static std::string GenerateTestExpression(ArrayRef<Record *> LangOpts) { 22240b57cec5SDimitry Andric std::string Test; 22250b57cec5SDimitry Andric 22260b57cec5SDimitry Andric for (auto *E : LangOpts) { 22270b57cec5SDimitry Andric if (!Test.empty()) 22280b57cec5SDimitry Andric Test += " || "; 22290b57cec5SDimitry Andric 22300b57cec5SDimitry Andric const StringRef Code = E->getValueAsString("CustomCode"); 22310b57cec5SDimitry Andric if (!Code.empty()) { 22320b57cec5SDimitry Andric Test += "("; 22330b57cec5SDimitry Andric Test += Code; 22340b57cec5SDimitry Andric Test += ")"; 22355ffd83dbSDimitry Andric if (!E->getValueAsString("Name").empty()) { 22365ffd83dbSDimitry Andric PrintWarning( 22375ffd83dbSDimitry Andric E->getLoc(), 22385ffd83dbSDimitry Andric "non-empty 'Name' field ignored because 'CustomCode' was supplied"); 22395ffd83dbSDimitry Andric } 22400b57cec5SDimitry Andric } else { 22410b57cec5SDimitry Andric Test += "LangOpts."; 22420b57cec5SDimitry Andric Test += E->getValueAsString("Name"); 22430b57cec5SDimitry Andric } 22440b57cec5SDimitry Andric } 22450b57cec5SDimitry Andric 22460b57cec5SDimitry Andric if (Test.empty()) 22470b57cec5SDimitry Andric return "true"; 22480b57cec5SDimitry Andric 22490b57cec5SDimitry Andric return Test; 22500b57cec5SDimitry Andric } 22510b57cec5SDimitry Andric 22525ffd83dbSDimitry Andric void 22530b57cec5SDimitry Andric PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, 22540b57cec5SDimitry Andric raw_ostream &OS) { 22555ffd83dbSDimitry Andric if (!isAttributedSupported(Attr) || Attr.isValueUnset("Subjects")) 22565ffd83dbSDimitry Andric return; 22570b57cec5SDimitry Andric // Generate a function that constructs a set of matching rules that describe 22580b57cec5SDimitry Andric // to which declarations the attribute should apply to. 22595ffd83dbSDimitry Andric OS << "void getPragmaAttributeMatchRules(" 22605ffd83dbSDimitry Andric << "llvm::SmallVectorImpl<std::pair<" 22610b57cec5SDimitry Andric << AttributeSubjectMatchRule::EnumName 22625ffd83dbSDimitry Andric << ", bool>> &MatchRules, const LangOptions &LangOpts) const override {\n"; 22630b57cec5SDimitry Andric const Record *SubjectObj = Attr.getValueAsDef("Subjects"); 22640b57cec5SDimitry Andric std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); 22650b57cec5SDimitry Andric for (const auto *Subject : Subjects) { 2266fe6060f1SDimitry Andric if (!isSupportedPragmaClangAttributeSubject(*Subject)) 2267fe6060f1SDimitry Andric continue; 22680b57cec5SDimitry Andric auto It = SubjectsToRules.find(Subject); 22690b57cec5SDimitry Andric assert(It != SubjectsToRules.end() && 22700b57cec5SDimitry Andric "This attribute is unsupported by #pragma clang attribute"); 22710b57cec5SDimitry Andric for (const auto &Rule : It->getSecond().getAggregateRuleSet()) { 22720b57cec5SDimitry Andric // The rule might be language specific, so only subtract it from the given 22730b57cec5SDimitry Andric // rules if the specific language options are specified. 22740b57cec5SDimitry Andric std::vector<Record *> LangOpts = Rule.getLangOpts(); 22750b57cec5SDimitry Andric OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() 22760b57cec5SDimitry Andric << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) 22770b57cec5SDimitry Andric << "));\n"; 22780b57cec5SDimitry Andric } 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric OS << "}\n\n"; 22810b57cec5SDimitry Andric } 22820b57cec5SDimitry Andric 22830b57cec5SDimitry Andric void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { 22840b57cec5SDimitry Andric // Generate routines that check the names of sub-rules. 2285bdd1243dSDimitry Andric OS << "std::optional<attr::SubjectMatchRule> " 22860b57cec5SDimitry Andric "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n"; 2287bdd1243dSDimitry Andric OS << " return std::nullopt;\n"; 22880b57cec5SDimitry Andric OS << "}\n\n"; 22890b57cec5SDimitry Andric 2290349cc55cSDimitry Andric llvm::MapVector<const Record *, std::vector<AttributeSubjectMatchRule>> 22910b57cec5SDimitry Andric SubMatchRules; 22920b57cec5SDimitry Andric for (const auto &Rule : Rules) { 22930b57cec5SDimitry Andric if (!Rule.isSubRule()) 22940b57cec5SDimitry Andric continue; 22950b57cec5SDimitry Andric SubMatchRules[Rule.MetaSubject].push_back(Rule); 22960b57cec5SDimitry Andric } 22970b57cec5SDimitry Andric 22980b57cec5SDimitry Andric for (const auto &SubMatchRule : SubMatchRules) { 2299bdd1243dSDimitry Andric OS << "std::optional<attr::SubjectMatchRule> " 2300bdd1243dSDimitry Andric "isAttributeSubjectMatchSubRuleFor_" 23010b57cec5SDimitry Andric << SubMatchRule.first->getValueAsString("Name") 23020b57cec5SDimitry Andric << "(StringRef Name, bool IsUnless) {\n"; 23030b57cec5SDimitry Andric OS << " if (IsUnless)\n"; 23040b57cec5SDimitry Andric OS << " return " 2305bdd1243dSDimitry Andric "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n"; 23060b57cec5SDimitry Andric for (const auto &Rule : SubMatchRule.second) { 23070b57cec5SDimitry Andric if (Rule.isNegatedSubRule()) 23080b57cec5SDimitry Andric OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() 23090b57cec5SDimitry Andric << ").\n"; 23100b57cec5SDimitry Andric } 2311bdd1243dSDimitry Andric OS << " Default(std::nullopt);\n"; 23120b57cec5SDimitry Andric OS << " return " 2313bdd1243dSDimitry Andric "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n"; 23140b57cec5SDimitry Andric for (const auto &Rule : SubMatchRule.second) { 23150b57cec5SDimitry Andric if (!Rule.isNegatedSubRule()) 23160b57cec5SDimitry Andric OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() 23170b57cec5SDimitry Andric << ").\n"; 23180b57cec5SDimitry Andric } 2319bdd1243dSDimitry Andric OS << " Default(std::nullopt);\n"; 23200b57cec5SDimitry Andric OS << "}\n\n"; 23210b57cec5SDimitry Andric } 23220b57cec5SDimitry Andric 23230b57cec5SDimitry Andric // Generate the function that checks for the top-level rules. 2324bdd1243dSDimitry Andric OS << "std::pair<std::optional<attr::SubjectMatchRule>, " 2325bdd1243dSDimitry Andric "std::optional<attr::SubjectMatchRule> (*)(StringRef, " 23260b57cec5SDimitry Andric "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n"; 23270b57cec5SDimitry Andric OS << " return " 2328bdd1243dSDimitry Andric "llvm::StringSwitch<std::pair<std::optional<attr::SubjectMatchRule>, " 2329bdd1243dSDimitry Andric "std::optional<attr::SubjectMatchRule> (*) (StringRef, " 23300b57cec5SDimitry Andric "bool)>>(Name).\n"; 23310b57cec5SDimitry Andric for (const auto &Rule : Rules) { 23320b57cec5SDimitry Andric if (Rule.isSubRule()) 23330b57cec5SDimitry Andric continue; 23340b57cec5SDimitry Andric std::string SubRuleFunction; 23350b57cec5SDimitry Andric if (SubMatchRules.count(Rule.MetaSubject)) 23360b57cec5SDimitry Andric SubRuleFunction = 23370b57cec5SDimitry Andric ("isAttributeSubjectMatchSubRuleFor_" + Rule.getName()).str(); 23380b57cec5SDimitry Andric else 23390b57cec5SDimitry Andric SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor"; 23400b57cec5SDimitry Andric OS << " Case(\"" << Rule.getName() << "\", std::make_pair(" 23410b57cec5SDimitry Andric << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n"; 23420b57cec5SDimitry Andric } 2343bdd1243dSDimitry Andric OS << " Default(std::make_pair(std::nullopt, " 23440b57cec5SDimitry Andric "defaultIsAttributeSubjectMatchSubRuleFor));\n"; 23450b57cec5SDimitry Andric OS << "}\n\n"; 23460b57cec5SDimitry Andric 23470b57cec5SDimitry Andric // Generate the function that checks for the submatch rules. 23480b57cec5SDimitry Andric OS << "const char *validAttributeSubjectMatchSubRules(" 23490b57cec5SDimitry Andric << AttributeSubjectMatchRule::EnumName << " Rule) {\n"; 23500b57cec5SDimitry Andric OS << " switch (Rule) {\n"; 23510b57cec5SDimitry Andric for (const auto &SubMatchRule : SubMatchRules) { 23520b57cec5SDimitry Andric OS << " case " 23530b57cec5SDimitry Andric << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue() 23540b57cec5SDimitry Andric << ":\n"; 23550b57cec5SDimitry Andric OS << " return \"'"; 23560b57cec5SDimitry Andric bool IsFirst = true; 23570b57cec5SDimitry Andric for (const auto &Rule : SubMatchRule.second) { 23580b57cec5SDimitry Andric if (!IsFirst) 23590b57cec5SDimitry Andric OS << ", '"; 23600b57cec5SDimitry Andric IsFirst = false; 23610b57cec5SDimitry Andric if (Rule.isNegatedSubRule()) 23620b57cec5SDimitry Andric OS << "unless("; 23630b57cec5SDimitry Andric OS << Rule.getName(); 23640b57cec5SDimitry Andric if (Rule.isNegatedSubRule()) 23650b57cec5SDimitry Andric OS << ')'; 23660b57cec5SDimitry Andric OS << "'"; 23670b57cec5SDimitry Andric } 23680b57cec5SDimitry Andric OS << "\";\n"; 23690b57cec5SDimitry Andric } 23700b57cec5SDimitry Andric OS << " default: return nullptr;\n"; 23710b57cec5SDimitry Andric OS << " }\n"; 23720b57cec5SDimitry Andric OS << "}\n\n"; 23730b57cec5SDimitry Andric } 23740b57cec5SDimitry Andric 23750b57cec5SDimitry Andric template <typename Fn> 23760b57cec5SDimitry Andric static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { 23770b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); 23780b57cec5SDimitry Andric SmallDenseSet<StringRef, 8> Seen; 23790b57cec5SDimitry Andric for (const FlattenedSpelling &S : Spellings) { 23800b57cec5SDimitry Andric if (Seen.insert(S.name()).second) 23810b57cec5SDimitry Andric F(S); 23820b57cec5SDimitry Andric } 23830b57cec5SDimitry Andric } 23840b57cec5SDimitry Andric 238581ad6265SDimitry Andric static bool isTypeArgument(const Record *Arg) { 238681ad6265SDimitry Andric return !Arg->getSuperClasses().empty() && 238781ad6265SDimitry Andric Arg->getSuperClasses().back().first->getName() == "TypeArgument"; 238881ad6265SDimitry Andric } 238981ad6265SDimitry Andric 23900b57cec5SDimitry Andric /// Emits the first-argument-is-type property for attributes. 23910b57cec5SDimitry Andric static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) { 23920b57cec5SDimitry Andric OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n"; 23930b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 23940b57cec5SDimitry Andric 23950b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 23960b57cec5SDimitry Andric // Determine whether the first argument is a type. 23970b57cec5SDimitry Andric std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args"); 23980b57cec5SDimitry Andric if (Args.empty()) 23990b57cec5SDimitry Andric continue; 24000b57cec5SDimitry Andric 240181ad6265SDimitry Andric if (!isTypeArgument(Args[0])) 24020b57cec5SDimitry Andric continue; 24030b57cec5SDimitry Andric 24040b57cec5SDimitry Andric // All these spellings take a single type argument. 24050b57cec5SDimitry Andric forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { 24060b57cec5SDimitry Andric OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; 24070b57cec5SDimitry Andric }); 24080b57cec5SDimitry Andric } 24090b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n"; 24100b57cec5SDimitry Andric } 24110b57cec5SDimitry Andric 24120b57cec5SDimitry Andric /// Emits the parse-arguments-in-unevaluated-context property for 24130b57cec5SDimitry Andric /// attributes. 24140b57cec5SDimitry Andric static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) { 24150b57cec5SDimitry Andric OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n"; 24160b57cec5SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records); 24170b57cec5SDimitry Andric for (const auto &I : Attrs) { 24180b57cec5SDimitry Andric const Record &Attr = *I.second; 24190b57cec5SDimitry Andric 24200b57cec5SDimitry Andric if (!Attr.getValueAsBit("ParseArgumentsAsUnevaluated")) 24210b57cec5SDimitry Andric continue; 24220b57cec5SDimitry Andric 24230b57cec5SDimitry Andric // All these spellings take are parsed unevaluated. 24240b57cec5SDimitry Andric forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { 24250b57cec5SDimitry Andric OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; 24260b57cec5SDimitry Andric }); 24270b57cec5SDimitry Andric } 24280b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n"; 24290b57cec5SDimitry Andric } 24300b57cec5SDimitry Andric 243181ad6265SDimitry Andric static bool isIdentifierArgument(const Record *Arg) { 24320b57cec5SDimitry Andric return !Arg->getSuperClasses().empty() && 24330b57cec5SDimitry Andric llvm::StringSwitch<bool>(Arg->getSuperClasses().back().first->getName()) 24340b57cec5SDimitry Andric .Case("IdentifierArgument", true) 24350b57cec5SDimitry Andric .Case("EnumArgument", true) 24360b57cec5SDimitry Andric .Case("VariadicEnumArgument", true) 24370b57cec5SDimitry Andric .Default(false); 24380b57cec5SDimitry Andric } 24390b57cec5SDimitry Andric 244081ad6265SDimitry Andric static bool isVariadicIdentifierArgument(const Record *Arg) { 24410b57cec5SDimitry Andric return !Arg->getSuperClasses().empty() && 24420b57cec5SDimitry Andric llvm::StringSwitch<bool>( 24430b57cec5SDimitry Andric Arg->getSuperClasses().back().first->getName()) 24440b57cec5SDimitry Andric .Case("VariadicIdentifierArgument", true) 24450b57cec5SDimitry Andric .Case("VariadicParamOrParamIdxArgument", true) 24460b57cec5SDimitry Andric .Default(false); 24470b57cec5SDimitry Andric } 24480b57cec5SDimitry Andric 244981ad6265SDimitry Andric static bool isVariadicExprArgument(const Record *Arg) { 245081ad6265SDimitry Andric return !Arg->getSuperClasses().empty() && 245181ad6265SDimitry Andric llvm::StringSwitch<bool>( 245281ad6265SDimitry Andric Arg->getSuperClasses().back().first->getName()) 245381ad6265SDimitry Andric .Case("VariadicExprArgument", true) 245481ad6265SDimitry Andric .Default(false); 245581ad6265SDimitry Andric } 245681ad6265SDimitry Andric 24575f757f3fSDimitry Andric static bool isStringLiteralArgument(const Record *Arg) { 2458*0fca6ea1SDimitry Andric if (Arg->getSuperClasses().empty()) 2459*0fca6ea1SDimitry Andric return false; 2460*0fca6ea1SDimitry Andric StringRef ArgKind = Arg->getSuperClasses().back().first->getName(); 2461*0fca6ea1SDimitry Andric if (ArgKind == "EnumArgument") 2462*0fca6ea1SDimitry Andric return Arg->getValueAsBit("IsString"); 2463*0fca6ea1SDimitry Andric return ArgKind == "StringArgument"; 24645f757f3fSDimitry Andric } 24655f757f3fSDimitry Andric 24665f757f3fSDimitry Andric static bool isVariadicStringLiteralArgument(const Record *Arg) { 2467*0fca6ea1SDimitry Andric if (Arg->getSuperClasses().empty()) 2468*0fca6ea1SDimitry Andric return false; 2469*0fca6ea1SDimitry Andric StringRef ArgKind = Arg->getSuperClasses().back().first->getName(); 2470*0fca6ea1SDimitry Andric if (ArgKind == "VariadicEnumArgument") 2471*0fca6ea1SDimitry Andric return Arg->getValueAsBit("IsString"); 2472*0fca6ea1SDimitry Andric return ArgKind == "VariadicStringArgument"; 24735f757f3fSDimitry Andric } 24745f757f3fSDimitry Andric 24750b57cec5SDimitry Andric static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records, 24760b57cec5SDimitry Andric raw_ostream &OS) { 24770b57cec5SDimitry Andric OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n"; 24780b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 24790b57cec5SDimitry Andric for (const auto *A : Attrs) { 24800b57cec5SDimitry Andric // Determine whether the first argument is a variadic identifier. 24810b57cec5SDimitry Andric std::vector<Record *> Args = A->getValueAsListOfDefs("Args"); 24820b57cec5SDimitry Andric if (Args.empty() || !isVariadicIdentifierArgument(Args[0])) 24830b57cec5SDimitry Andric continue; 24840b57cec5SDimitry Andric 24850b57cec5SDimitry Andric // All these spellings take an identifier argument. 24860b57cec5SDimitry Andric forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) { 24870b57cec5SDimitry Andric OS << ".Case(\"" << S.name() << "\", " 24880b57cec5SDimitry Andric << "true" 24890b57cec5SDimitry Andric << ")\n"; 24900b57cec5SDimitry Andric }); 24910b57cec5SDimitry Andric } 24920b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n"; 24930b57cec5SDimitry Andric } 24940b57cec5SDimitry Andric 2495*0fca6ea1SDimitry Andric static bool GenerateTargetSpecificAttrChecks(const Record *R, 2496*0fca6ea1SDimitry Andric std::vector<StringRef> &Arches, 2497*0fca6ea1SDimitry Andric std::string &Test, 2498*0fca6ea1SDimitry Andric std::string *FnName); 2499*0fca6ea1SDimitry Andric 25005f757f3fSDimitry Andric // Emits the list of arguments that should be parsed as unevaluated string 25015f757f3fSDimitry Andric // literals for each attribute. 25025f757f3fSDimitry Andric static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records, 25035f757f3fSDimitry Andric raw_ostream &OS) { 25045f757f3fSDimitry Andric OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n"; 2505*0fca6ea1SDimitry Andric 2506*0fca6ea1SDimitry Andric auto MakeMask = [](ArrayRef<Record *> Args) { 25075f757f3fSDimitry Andric uint32_t Bits = 0; 25085f757f3fSDimitry Andric assert(Args.size() <= 32 && "unsupported number of arguments in attribute"); 25095f757f3fSDimitry Andric for (uint32_t N = 0; N < Args.size(); ++N) { 25105f757f3fSDimitry Andric Bits |= (isStringLiteralArgument(Args[N]) << N); 25115f757f3fSDimitry Andric // If we have a variadic string argument, set all the remaining bits to 1 25125f757f3fSDimitry Andric if (isVariadicStringLiteralArgument(Args[N])) { 25135f757f3fSDimitry Andric Bits |= maskTrailingZeros<decltype(Bits)>(N); 25145f757f3fSDimitry Andric break; 25155f757f3fSDimitry Andric } 25165f757f3fSDimitry Andric } 2517*0fca6ea1SDimitry Andric return Bits; 2518*0fca6ea1SDimitry Andric }; 2519*0fca6ea1SDimitry Andric 2520*0fca6ea1SDimitry Andric auto AddMaskWithTargetCheck = [](const Record *Attr, uint32_t Mask, 2521*0fca6ea1SDimitry Andric std::string &MaskStr) { 2522*0fca6ea1SDimitry Andric const Record *T = Attr->getValueAsDef("Target"); 2523*0fca6ea1SDimitry Andric std::vector<StringRef> Arches = T->getValueAsListOfStrings("Arches"); 2524*0fca6ea1SDimitry Andric std::string Test; 2525*0fca6ea1SDimitry Andric GenerateTargetSpecificAttrChecks(T, Arches, Test, nullptr); 2526*0fca6ea1SDimitry Andric MaskStr.append(Test + " ? " + std::to_string(Mask) + " : "); 2527*0fca6ea1SDimitry Andric }; 2528*0fca6ea1SDimitry Andric 2529*0fca6ea1SDimitry Andric ParsedAttrMap Dupes; 2530*0fca6ea1SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes, /*SemaOnly=*/false); 2531*0fca6ea1SDimitry Andric for (const auto &[AttrName, Attr] : Attrs) { 2532*0fca6ea1SDimitry Andric std::string MaskStr; 2533*0fca6ea1SDimitry Andric if (Attr->isSubClassOf("TargetSpecificAttr") && 2534*0fca6ea1SDimitry Andric !Attr->isValueUnset("ParseKind")) { 2535*0fca6ea1SDimitry Andric if (uint32_t Mask = MakeMask(Attr->getValueAsListOfDefs("Args"))) 2536*0fca6ea1SDimitry Andric AddMaskWithTargetCheck(Attr, Mask, MaskStr); 2537*0fca6ea1SDimitry Andric StringRef ParseKind = Attr->getValueAsString("ParseKind"); 2538*0fca6ea1SDimitry Andric for (const auto &[DupeParseKind, DupAttr] : Dupes) { 2539*0fca6ea1SDimitry Andric if (DupeParseKind != ParseKind) 25405f757f3fSDimitry Andric continue; 2541*0fca6ea1SDimitry Andric if (uint32_t Mask = MakeMask(DupAttr->getValueAsListOfDefs("Args"))) 2542*0fca6ea1SDimitry Andric AddMaskWithTargetCheck(DupAttr, Mask, MaskStr); 2543*0fca6ea1SDimitry Andric } 2544*0fca6ea1SDimitry Andric if (!MaskStr.empty()) 2545*0fca6ea1SDimitry Andric MaskStr.append("0"); 2546*0fca6ea1SDimitry Andric } else { 2547*0fca6ea1SDimitry Andric if (uint32_t Mask = MakeMask(Attr->getValueAsListOfDefs("Args"))) 2548*0fca6ea1SDimitry Andric MaskStr = std::to_string(Mask); 2549*0fca6ea1SDimitry Andric } 2550*0fca6ea1SDimitry Andric 2551*0fca6ea1SDimitry Andric if (MaskStr.empty()) 2552*0fca6ea1SDimitry Andric continue; 2553*0fca6ea1SDimitry Andric 25545f757f3fSDimitry Andric // All these spellings have at least one string literal has argument. 25555f757f3fSDimitry Andric forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { 2556*0fca6ea1SDimitry Andric OS << ".Case(\"" << S.name() << "\", " << MaskStr << ")\n"; 25575f757f3fSDimitry Andric }); 25585f757f3fSDimitry Andric } 25595f757f3fSDimitry Andric OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n"; 25605f757f3fSDimitry Andric } 25615f757f3fSDimitry Andric 25620b57cec5SDimitry Andric // Emits the first-argument-is-identifier property for attributes. 25630b57cec5SDimitry Andric static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) { 25640b57cec5SDimitry Andric OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n"; 25650b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 25660b57cec5SDimitry Andric 25670b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 25680b57cec5SDimitry Andric // Determine whether the first argument is an identifier. 25690b57cec5SDimitry Andric std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args"); 25700b57cec5SDimitry Andric if (Args.empty() || !isIdentifierArgument(Args[0])) 25710b57cec5SDimitry Andric continue; 25720b57cec5SDimitry Andric 25730b57cec5SDimitry Andric // All these spellings take an identifier argument. 25740b57cec5SDimitry Andric forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { 25750b57cec5SDimitry Andric OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; 25760b57cec5SDimitry Andric }); 25770b57cec5SDimitry Andric } 25780b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n"; 25790b57cec5SDimitry Andric } 25800b57cec5SDimitry Andric 2581*0fca6ea1SDimitry Andric // Emits the indexed-argument-is-identifier property for attributes. 2582*0fca6ea1SDimitry Andric static void emitClangAttrStrictIdentifierArgAtIndexList(RecordKeeper &Records, 2583*0fca6ea1SDimitry Andric raw_ostream &OS) { 2584*0fca6ea1SDimitry Andric OS << "#if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST)\n"; 2585*0fca6ea1SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 2586*0fca6ea1SDimitry Andric 2587*0fca6ea1SDimitry Andric for (const auto *Attr : Attrs) { 2588*0fca6ea1SDimitry Andric if (!Attr->getValueAsBit("StrictEnumParameters")) 2589*0fca6ea1SDimitry Andric continue; 2590*0fca6ea1SDimitry Andric // Determine whether the first argument is an identifier. 2591*0fca6ea1SDimitry Andric std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args"); 2592*0fca6ea1SDimitry Andric uint64_t enumAtIndex = 0; 2593*0fca6ea1SDimitry Andric for (size_t i = 0; i < Args.size(); i++) { 2594*0fca6ea1SDimitry Andric enumAtIndex |= ((uint64_t)isIdentifierArgument(Args[0])) << i; 2595*0fca6ea1SDimitry Andric } 2596*0fca6ea1SDimitry Andric if (!enumAtIndex) 2597*0fca6ea1SDimitry Andric continue; 2598*0fca6ea1SDimitry Andric 2599*0fca6ea1SDimitry Andric // All these spellings take an identifier argument. 2600*0fca6ea1SDimitry Andric forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { 2601*0fca6ea1SDimitry Andric OS << ".Case(\"" << S.name() << "\", " << enumAtIndex << "ull)\n"; 2602*0fca6ea1SDimitry Andric }); 2603*0fca6ea1SDimitry Andric } 2604*0fca6ea1SDimitry Andric OS << "#endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST\n\n"; 2605*0fca6ea1SDimitry Andric } 2606*0fca6ea1SDimitry Andric 26070b57cec5SDimitry Andric static bool keywordThisIsaIdentifierInArgument(const Record *Arg) { 26080b57cec5SDimitry Andric return !Arg->getSuperClasses().empty() && 26090b57cec5SDimitry Andric llvm::StringSwitch<bool>( 26100b57cec5SDimitry Andric Arg->getSuperClasses().back().first->getName()) 26110b57cec5SDimitry Andric .Case("VariadicParamOrParamIdxArgument", true) 26120b57cec5SDimitry Andric .Default(false); 26130b57cec5SDimitry Andric } 26140b57cec5SDimitry Andric 26150b57cec5SDimitry Andric static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records, 26160b57cec5SDimitry Andric raw_ostream &OS) { 26170b57cec5SDimitry Andric OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n"; 26180b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 26190b57cec5SDimitry Andric for (const auto *A : Attrs) { 26200b57cec5SDimitry Andric // Determine whether the first argument is a variadic identifier. 26210b57cec5SDimitry Andric std::vector<Record *> Args = A->getValueAsListOfDefs("Args"); 26220b57cec5SDimitry Andric if (Args.empty() || !keywordThisIsaIdentifierInArgument(Args[0])) 26230b57cec5SDimitry Andric continue; 26240b57cec5SDimitry Andric 26250b57cec5SDimitry Andric // All these spellings take an identifier argument. 26260b57cec5SDimitry Andric forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) { 26270b57cec5SDimitry Andric OS << ".Case(\"" << S.name() << "\", " 26280b57cec5SDimitry Andric << "true" 26290b57cec5SDimitry Andric << ")\n"; 26300b57cec5SDimitry Andric }); 26310b57cec5SDimitry Andric } 26320b57cec5SDimitry Andric OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n"; 26330b57cec5SDimitry Andric } 26340b57cec5SDimitry Andric 263581ad6265SDimitry Andric static void emitClangAttrAcceptsExprPack(RecordKeeper &Records, 263681ad6265SDimitry Andric raw_ostream &OS) { 263781ad6265SDimitry Andric OS << "#if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK)\n"; 263881ad6265SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records); 263981ad6265SDimitry Andric for (const auto &I : Attrs) { 264081ad6265SDimitry Andric const Record &Attr = *I.second; 264181ad6265SDimitry Andric 264281ad6265SDimitry Andric if (!Attr.getValueAsBit("AcceptsExprPack")) 264381ad6265SDimitry Andric continue; 264481ad6265SDimitry Andric 264581ad6265SDimitry Andric forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { 264681ad6265SDimitry Andric OS << ".Case(\"" << S.name() << "\", true)\n"; 264781ad6265SDimitry Andric }); 264881ad6265SDimitry Andric } 264981ad6265SDimitry Andric OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n"; 265081ad6265SDimitry Andric } 265181ad6265SDimitry Andric 265206c3fb27SDimitry Andric static bool isRegularKeywordAttribute(const FlattenedSpelling &S) { 265306c3fb27SDimitry Andric return (S.variety() == "Keyword" && 265406c3fb27SDimitry Andric !S.getSpellingRecord().getValueAsBit("HasOwnParseRules")); 265506c3fb27SDimitry Andric } 265606c3fb27SDimitry Andric 265706c3fb27SDimitry Andric static void emitFormInitializer(raw_ostream &OS, 265806c3fb27SDimitry Andric const FlattenedSpelling &Spelling, 265906c3fb27SDimitry Andric StringRef SpellingIndex) { 266006c3fb27SDimitry Andric bool IsAlignas = 266106c3fb27SDimitry Andric (Spelling.variety() == "Keyword" && Spelling.name() == "alignas"); 266206c3fb27SDimitry Andric OS << "{AttributeCommonInfo::AS_" << Spelling.variety() << ", " 266306c3fb27SDimitry Andric << SpellingIndex << ", " << (IsAlignas ? "true" : "false") 266406c3fb27SDimitry Andric << " /*IsAlignas*/, " 266506c3fb27SDimitry Andric << (isRegularKeywordAttribute(Spelling) ? "true" : "false") 266606c3fb27SDimitry Andric << " /*IsRegularKeywordAttribute*/}"; 266706c3fb27SDimitry Andric } 266806c3fb27SDimitry Andric 26695ffd83dbSDimitry Andric static void emitAttributes(RecordKeeper &Records, raw_ostream &OS, 26705ffd83dbSDimitry Andric bool Header) { 26710b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 2672a7dea167SDimitry Andric ParsedAttrMap AttrMap = getParsedAttrList(Records); 26730b57cec5SDimitry Andric 2674fe6060f1SDimitry Andric // Helper to print the starting character of an attribute argument. If there 2675fe6060f1SDimitry Andric // hasn't been an argument yet, it prints an opening parenthese; otherwise it 2676fe6060f1SDimitry Andric // prints a comma. 2677fe6060f1SDimitry Andric OS << "static inline void DelimitAttributeArgument(" 2678fe6060f1SDimitry Andric << "raw_ostream& OS, bool& IsFirst) {\n" 2679fe6060f1SDimitry Andric << " if (IsFirst) {\n" 2680fe6060f1SDimitry Andric << " IsFirst = false;\n" 2681fe6060f1SDimitry Andric << " OS << \"(\";\n" 2682fe6060f1SDimitry Andric << " } else\n" 2683fe6060f1SDimitry Andric << " OS << \", \";\n" 2684fe6060f1SDimitry Andric << "}\n"; 2685fe6060f1SDimitry Andric 26860b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 26870b57cec5SDimitry Andric const Record &R = *Attr; 26880b57cec5SDimitry Andric 26890b57cec5SDimitry Andric // FIXME: Currently, documentation is generated as-needed due to the fact 26900b57cec5SDimitry Andric // that there is no way to allow a generated project "reach into" the docs 26910b57cec5SDimitry Andric // directory (for instance, it may be an out-of-tree build). However, we want 26920b57cec5SDimitry Andric // to ensure that every attribute has a Documentation field, and produce an 26930b57cec5SDimitry Andric // error if it has been neglected. Otherwise, the on-demand generation which 26940b57cec5SDimitry Andric // happens server-side will fail. This code is ensuring that functionality, 26950b57cec5SDimitry Andric // even though this Emitter doesn't technically need the documentation. 26960b57cec5SDimitry Andric // When attribute documentation can be generated as part of the build 26970b57cec5SDimitry Andric // itself, this code can be removed. 26980b57cec5SDimitry Andric (void)R.getValueAsListOfDefs("Documentation"); 26990b57cec5SDimitry Andric 27000b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 27010b57cec5SDimitry Andric continue; 27020b57cec5SDimitry Andric 27030b57cec5SDimitry Andric ArrayRef<std::pair<Record *, SMRange>> Supers = R.getSuperClasses(); 27040b57cec5SDimitry Andric assert(!Supers.empty() && "Forgot to specify a superclass for the attr"); 27050b57cec5SDimitry Andric std::string SuperName; 27060b57cec5SDimitry Andric bool Inheritable = false; 27070b57cec5SDimitry Andric for (const auto &Super : llvm::reverse(Supers)) { 27080b57cec5SDimitry Andric const Record *R = Super.first; 27090b57cec5SDimitry Andric if (R->getName() != "TargetSpecificAttr" && 27100b57cec5SDimitry Andric R->getName() != "DeclOrTypeAttr" && SuperName.empty()) 27115ffd83dbSDimitry Andric SuperName = std::string(R->getName()); 27120b57cec5SDimitry Andric if (R->getName() == "InheritableAttr") 27130b57cec5SDimitry Andric Inheritable = true; 27140b57cec5SDimitry Andric } 27150b57cec5SDimitry Andric 27165ffd83dbSDimitry Andric if (Header) 27170b57cec5SDimitry Andric OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; 27185ffd83dbSDimitry Andric else 27195ffd83dbSDimitry Andric OS << "\n// " << R.getName() << "Attr implementation\n\n"; 27200b57cec5SDimitry Andric 27210b57cec5SDimitry Andric std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 27220b57cec5SDimitry Andric std::vector<std::unique_ptr<Argument>> Args; 27230b57cec5SDimitry Andric Args.reserve(ArgRecords.size()); 27240b57cec5SDimitry Andric 272581ad6265SDimitry Andric bool AttrAcceptsExprPack = Attr->getValueAsBit("AcceptsExprPack"); 272681ad6265SDimitry Andric if (AttrAcceptsExprPack) { 272781ad6265SDimitry Andric for (size_t I = 0; I < ArgRecords.size(); ++I) { 272881ad6265SDimitry Andric const Record *ArgR = ArgRecords[I]; 272981ad6265SDimitry Andric if (isIdentifierArgument(ArgR) || isVariadicIdentifierArgument(ArgR) || 273081ad6265SDimitry Andric isTypeArgument(ArgR)) 273181ad6265SDimitry Andric PrintFatalError(Attr->getLoc(), 273281ad6265SDimitry Andric "Attributes accepting packs cannot also " 273381ad6265SDimitry Andric "have identifier or type arguments."); 273481ad6265SDimitry Andric // When trying to determine if value-dependent expressions can populate 273581ad6265SDimitry Andric // the attribute without prior instantiation, the decision is made based 273681ad6265SDimitry Andric // on the assumption that only the last argument is ever variadic. 273781ad6265SDimitry Andric if (I < (ArgRecords.size() - 1) && isVariadicExprArgument(ArgR)) 273881ad6265SDimitry Andric PrintFatalError(Attr->getLoc(), 273981ad6265SDimitry Andric "Attributes accepting packs can only have the last " 274081ad6265SDimitry Andric "argument be variadic."); 274181ad6265SDimitry Andric } 274281ad6265SDimitry Andric } 274381ad6265SDimitry Andric 27440b57cec5SDimitry Andric bool HasOptArg = false; 27450b57cec5SDimitry Andric bool HasFakeArg = false; 27460b57cec5SDimitry Andric for (const auto *ArgRecord : ArgRecords) { 27470b57cec5SDimitry Andric Args.emplace_back(createArgument(*ArgRecord, R.getName())); 27485ffd83dbSDimitry Andric if (Header) { 27490b57cec5SDimitry Andric Args.back()->writeDeclarations(OS); 27500b57cec5SDimitry Andric OS << "\n\n"; 27515ffd83dbSDimitry Andric } 27520b57cec5SDimitry Andric 27530b57cec5SDimitry Andric // For these purposes, fake takes priority over optional. 27540b57cec5SDimitry Andric if (Args.back()->isFake()) { 27550b57cec5SDimitry Andric HasFakeArg = true; 27560b57cec5SDimitry Andric } else if (Args.back()->isOptional()) { 27570b57cec5SDimitry Andric HasOptArg = true; 27580b57cec5SDimitry Andric } 27590b57cec5SDimitry Andric } 27600b57cec5SDimitry Andric 276181ad6265SDimitry Andric std::unique_ptr<VariadicExprArgument> DelayedArgs = nullptr; 276281ad6265SDimitry Andric if (AttrAcceptsExprPack) { 276381ad6265SDimitry Andric DelayedArgs = 276481ad6265SDimitry Andric std::make_unique<VariadicExprArgument>("DelayedArgs", R.getName()); 276581ad6265SDimitry Andric if (Header) { 276681ad6265SDimitry Andric DelayedArgs->writeDeclarations(OS); 276781ad6265SDimitry Andric OS << "\n\n"; 276881ad6265SDimitry Andric } 276981ad6265SDimitry Andric } 277081ad6265SDimitry Andric 27715ffd83dbSDimitry Andric if (Header) 27720b57cec5SDimitry Andric OS << "public:\n"; 27730b57cec5SDimitry Andric 27740b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); 27750b57cec5SDimitry Andric 27760b57cec5SDimitry Andric // If there are zero or one spellings, all spelling-related functionality 27770b57cec5SDimitry Andric // can be elided. If all of the spellings share the same name, the spelling 27780b57cec5SDimitry Andric // functionality can also be elided. 27790b57cec5SDimitry Andric bool ElideSpelling = (Spellings.size() <= 1) || 27800b57cec5SDimitry Andric SpellingNamesAreCommon(Spellings); 27810b57cec5SDimitry Andric 27820b57cec5SDimitry Andric // This maps spelling index values to semantic Spelling enumerants. 27830b57cec5SDimitry Andric SemanticSpellingMap SemanticToSyntacticMap; 27840b57cec5SDimitry Andric 27855ffd83dbSDimitry Andric std::string SpellingEnum; 27865ffd83dbSDimitry Andric if (Spellings.size() > 1) 27875ffd83dbSDimitry Andric SpellingEnum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); 27885ffd83dbSDimitry Andric if (Header) 27895ffd83dbSDimitry Andric OS << SpellingEnum; 27900b57cec5SDimitry Andric 2791a7dea167SDimitry Andric const auto &ParsedAttrSpellingItr = llvm::find_if( 2792a7dea167SDimitry Andric AttrMap, [R](const std::pair<std::string, const Record *> &P) { 2793a7dea167SDimitry Andric return &R == P.second; 2794a7dea167SDimitry Andric }); 2795a7dea167SDimitry Andric 27960b57cec5SDimitry Andric // Emit CreateImplicit factory methods. 279781ad6265SDimitry Andric auto emitCreate = [&](bool Implicit, bool DelayedArgsOnly, bool emitFake) { 27985ffd83dbSDimitry Andric if (Header) 27995ffd83dbSDimitry Andric OS << " static "; 28005ffd83dbSDimitry Andric OS << R.getName() << "Attr *"; 28015ffd83dbSDimitry Andric if (!Header) 28025ffd83dbSDimitry Andric OS << R.getName() << "Attr::"; 28035ffd83dbSDimitry Andric OS << "Create"; 2804a7dea167SDimitry Andric if (Implicit) 2805a7dea167SDimitry Andric OS << "Implicit"; 280681ad6265SDimitry Andric if (DelayedArgsOnly) 280781ad6265SDimitry Andric OS << "WithDelayedArgs"; 2808a7dea167SDimitry Andric OS << "("; 28090b57cec5SDimitry Andric OS << "ASTContext &Ctx"; 281081ad6265SDimitry Andric if (!DelayedArgsOnly) { 28110b57cec5SDimitry Andric for (auto const &ai : Args) { 281281ad6265SDimitry Andric if (ai->isFake() && !emitFake) 281381ad6265SDimitry Andric continue; 28140b57cec5SDimitry Andric OS << ", "; 28150b57cec5SDimitry Andric ai->writeCtorParameters(OS); 28160b57cec5SDimitry Andric } 281781ad6265SDimitry Andric } else { 281881ad6265SDimitry Andric OS << ", "; 281981ad6265SDimitry Andric DelayedArgs->writeCtorParameters(OS); 282081ad6265SDimitry Andric } 28215ffd83dbSDimitry Andric OS << ", const AttributeCommonInfo &CommonInfo"; 28225ffd83dbSDimitry Andric OS << ")"; 28235ffd83dbSDimitry Andric if (Header) { 28245ffd83dbSDimitry Andric OS << ";\n"; 28255ffd83dbSDimitry Andric return; 28265ffd83dbSDimitry Andric } 28275ffd83dbSDimitry Andric 28285ffd83dbSDimitry Andric OS << " {\n"; 28290b57cec5SDimitry Andric OS << " auto *A = new (Ctx) " << R.getName(); 2830a7dea167SDimitry Andric OS << "Attr(Ctx, CommonInfo"; 283106c3fb27SDimitry Andric 283281ad6265SDimitry Andric if (!DelayedArgsOnly) { 28330b57cec5SDimitry Andric for (auto const &ai : Args) { 283481ad6265SDimitry Andric if (ai->isFake() && !emitFake) 283581ad6265SDimitry Andric continue; 28360b57cec5SDimitry Andric OS << ", "; 2837a7dea167SDimitry Andric ai->writeImplicitCtorArgs(OS); 28380b57cec5SDimitry Andric } 283981ad6265SDimitry Andric } 2840a7dea167SDimitry Andric OS << ");\n"; 2841a7dea167SDimitry Andric if (Implicit) { 28420b57cec5SDimitry Andric OS << " A->setImplicit(true);\n"; 2843a7dea167SDimitry Andric } 2844a7dea167SDimitry Andric if (Implicit || ElideSpelling) { 2845a7dea167SDimitry Andric OS << " if (!A->isAttributeSpellingListCalculated() && " 2846a7dea167SDimitry Andric "!A->getAttrName())\n"; 2847a7dea167SDimitry Andric OS << " A->setAttributeSpellingListIndex(0);\n"; 2848a7dea167SDimitry Andric } 284981ad6265SDimitry Andric if (DelayedArgsOnly) { 285081ad6265SDimitry Andric OS << " A->setDelayedArgs(Ctx, "; 285181ad6265SDimitry Andric DelayedArgs->writeImplicitCtorArgs(OS); 285281ad6265SDimitry Andric OS << ");\n"; 285381ad6265SDimitry Andric } 28540b57cec5SDimitry Andric OS << " return A;\n}\n\n"; 28550b57cec5SDimitry Andric }; 28560b57cec5SDimitry Andric 285781ad6265SDimitry Andric auto emitCreateNoCI = [&](bool Implicit, bool DelayedArgsOnly, 285881ad6265SDimitry Andric bool emitFake) { 28595ffd83dbSDimitry Andric if (Header) 28605ffd83dbSDimitry Andric OS << " static "; 28615ffd83dbSDimitry Andric OS << R.getName() << "Attr *"; 28625ffd83dbSDimitry Andric if (!Header) 28635ffd83dbSDimitry Andric OS << R.getName() << "Attr::"; 28645ffd83dbSDimitry Andric OS << "Create"; 2865a7dea167SDimitry Andric if (Implicit) 2866a7dea167SDimitry Andric OS << "Implicit"; 286781ad6265SDimitry Andric if (DelayedArgsOnly) 286881ad6265SDimitry Andric OS << "WithDelayedArgs"; 2869a7dea167SDimitry Andric OS << "("; 2870a7dea167SDimitry Andric OS << "ASTContext &Ctx"; 287181ad6265SDimitry Andric if (!DelayedArgsOnly) { 2872a7dea167SDimitry Andric for (auto const &ai : Args) { 287381ad6265SDimitry Andric if (ai->isFake() && !emitFake) 287481ad6265SDimitry Andric continue; 2875a7dea167SDimitry Andric OS << ", "; 2876a7dea167SDimitry Andric ai->writeCtorParameters(OS); 2877a7dea167SDimitry Andric } 287881ad6265SDimitry Andric } else { 287981ad6265SDimitry Andric OS << ", "; 288081ad6265SDimitry Andric DelayedArgs->writeCtorParameters(OS); 288181ad6265SDimitry Andric } 288206c3fb27SDimitry Andric OS << ", SourceRange Range"; 28835ffd83dbSDimitry Andric if (Header) 288406c3fb27SDimitry Andric OS << " = {}"; 288506c3fb27SDimitry Andric if (Spellings.size() > 1) { 288606c3fb27SDimitry Andric OS << ", Spelling S"; 288706c3fb27SDimitry Andric if (Header) 288806c3fb27SDimitry Andric OS << " = " << SemanticToSyntacticMap[0]; 28895ffd83dbSDimitry Andric } 28905ffd83dbSDimitry Andric OS << ")"; 28915ffd83dbSDimitry Andric if (Header) { 28925ffd83dbSDimitry Andric OS << ";\n"; 28935ffd83dbSDimitry Andric return; 28945ffd83dbSDimitry Andric } 28955ffd83dbSDimitry Andric 28965ffd83dbSDimitry Andric OS << " {\n"; 2897a7dea167SDimitry Andric OS << " AttributeCommonInfo I(Range, "; 2898a7dea167SDimitry Andric 2899a7dea167SDimitry Andric if (ParsedAttrSpellingItr != std::end(AttrMap)) 2900a7dea167SDimitry Andric OS << "AT_" << ParsedAttrSpellingItr->first; 2901a7dea167SDimitry Andric else 2902a7dea167SDimitry Andric OS << "NoSemaHandlerAttribute"; 2903a7dea167SDimitry Andric 290406c3fb27SDimitry Andric if (Spellings.size() == 0) { 290506c3fb27SDimitry Andric OS << ", AttributeCommonInfo::Form::Implicit()"; 290606c3fb27SDimitry Andric } else if (Spellings.size() == 1) { 290706c3fb27SDimitry Andric OS << ", "; 290806c3fb27SDimitry Andric emitFormInitializer(OS, Spellings[0], "0"); 290906c3fb27SDimitry Andric } else { 2910bdb86d1aSDimitry Andric OS << ", [&]() {\n"; 2911bdb86d1aSDimitry Andric OS << " switch (S) {\n"; 291206c3fb27SDimitry Andric std::set<std::string> Uniques; 291306c3fb27SDimitry Andric unsigned Idx = 0; 291406c3fb27SDimitry Andric for (auto I = Spellings.begin(), E = Spellings.end(); I != E; 291506c3fb27SDimitry Andric ++I, ++Idx) { 291606c3fb27SDimitry Andric const FlattenedSpelling &S = *I; 291706c3fb27SDimitry Andric const auto &Name = SemanticToSyntacticMap[Idx]; 291806c3fb27SDimitry Andric if (Uniques.insert(Name).second) { 2919bdb86d1aSDimitry Andric OS << " case " << Name << ":\n"; 2920bdb86d1aSDimitry Andric OS << " return AttributeCommonInfo::Form"; 292106c3fb27SDimitry Andric emitFormInitializer(OS, S, Name); 2922bdb86d1aSDimitry Andric OS << ";\n"; 292306c3fb27SDimitry Andric } 292406c3fb27SDimitry Andric } 2925bdb86d1aSDimitry Andric OS << " default:\n"; 2926bdb86d1aSDimitry Andric OS << " llvm_unreachable(\"Unknown attribute spelling!\");\n" 2927bdb86d1aSDimitry Andric << " return AttributeCommonInfo::Form"; 292806c3fb27SDimitry Andric emitFormInitializer(OS, Spellings[0], "0"); 2929bdb86d1aSDimitry Andric OS << ";\n" 2930bdb86d1aSDimitry Andric << " }\n" 2931bdb86d1aSDimitry Andric << " }()"; 293206c3fb27SDimitry Andric } 293306c3fb27SDimitry Andric 2934a7dea167SDimitry Andric OS << ");\n"; 2935a7dea167SDimitry Andric OS << " return Create"; 2936a7dea167SDimitry Andric if (Implicit) 2937a7dea167SDimitry Andric OS << "Implicit"; 293881ad6265SDimitry Andric if (DelayedArgsOnly) 293981ad6265SDimitry Andric OS << "WithDelayedArgs"; 2940a7dea167SDimitry Andric OS << "(Ctx"; 294181ad6265SDimitry Andric if (!DelayedArgsOnly) { 2942a7dea167SDimitry Andric for (auto const &ai : Args) { 294381ad6265SDimitry Andric if (ai->isFake() && !emitFake) 294481ad6265SDimitry Andric continue; 2945a7dea167SDimitry Andric OS << ", "; 2946a7dea167SDimitry Andric ai->writeImplicitCtorArgs(OS); 2947a7dea167SDimitry Andric } 294881ad6265SDimitry Andric } else { 294981ad6265SDimitry Andric OS << ", "; 295081ad6265SDimitry Andric DelayedArgs->writeImplicitCtorArgs(OS); 295181ad6265SDimitry Andric } 2952a7dea167SDimitry Andric OS << ", I);\n"; 29535ffd83dbSDimitry Andric OS << "}\n\n"; 2954a7dea167SDimitry Andric }; 2955a7dea167SDimitry Andric 295681ad6265SDimitry Andric auto emitCreates = [&](bool DelayedArgsOnly, bool emitFake) { 295781ad6265SDimitry Andric emitCreate(true, DelayedArgsOnly, emitFake); 295881ad6265SDimitry Andric emitCreate(false, DelayedArgsOnly, emitFake); 295981ad6265SDimitry Andric emitCreateNoCI(true, DelayedArgsOnly, emitFake); 296081ad6265SDimitry Andric emitCreateNoCI(false, DelayedArgsOnly, emitFake); 2961a7dea167SDimitry Andric }; 2962a7dea167SDimitry Andric 29635ffd83dbSDimitry Andric if (Header) 29645ffd83dbSDimitry Andric OS << " // Factory methods\n"; 29655ffd83dbSDimitry Andric 29660b57cec5SDimitry Andric // Emit a CreateImplicit that takes all the arguments. 296781ad6265SDimitry Andric emitCreates(false, true); 29680b57cec5SDimitry Andric 29690b57cec5SDimitry Andric // Emit a CreateImplicit that takes all the non-fake arguments. 2970a7dea167SDimitry Andric if (HasFakeArg) 297181ad6265SDimitry Andric emitCreates(false, false); 297281ad6265SDimitry Andric 297381ad6265SDimitry Andric // Emit a CreateWithDelayedArgs that takes only the dependent argument 297481ad6265SDimitry Andric // expressions. 297581ad6265SDimitry Andric if (DelayedArgs) 297681ad6265SDimitry Andric emitCreates(true, false); 29770b57cec5SDimitry Andric 29780b57cec5SDimitry Andric // Emit constructors. 297981ad6265SDimitry Andric auto emitCtor = [&](bool emitOpt, bool emitFake, bool emitNoArgs) { 29800b57cec5SDimitry Andric auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) { 298181ad6265SDimitry Andric if (emitNoArgs) 298281ad6265SDimitry Andric return false; 298381ad6265SDimitry Andric if (arg->isFake()) 298481ad6265SDimitry Andric return emitFake; 298581ad6265SDimitry Andric if (arg->isOptional()) 298681ad6265SDimitry Andric return emitOpt; 29870b57cec5SDimitry Andric return true; 29880b57cec5SDimitry Andric }; 29895ffd83dbSDimitry Andric if (Header) 29905ffd83dbSDimitry Andric OS << " "; 29915ffd83dbSDimitry Andric else 29925ffd83dbSDimitry Andric OS << R.getName() << "Attr::"; 29935ffd83dbSDimitry Andric OS << R.getName() 2994a7dea167SDimitry Andric << "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo"; 2995a7dea167SDimitry Andric OS << '\n'; 29960b57cec5SDimitry Andric for (auto const &ai : Args) { 299781ad6265SDimitry Andric if (!shouldEmitArg(ai)) 299881ad6265SDimitry Andric continue; 29990b57cec5SDimitry Andric OS << " , "; 30000b57cec5SDimitry Andric ai->writeCtorParameters(OS); 30010b57cec5SDimitry Andric OS << "\n"; 30020b57cec5SDimitry Andric } 30030b57cec5SDimitry Andric 30045ffd83dbSDimitry Andric OS << " )"; 30055ffd83dbSDimitry Andric if (Header) { 30065ffd83dbSDimitry Andric OS << ";\n"; 30075ffd83dbSDimitry Andric return; 30085ffd83dbSDimitry Andric } 30095ffd83dbSDimitry Andric OS << "\n : " << SuperName << "(Ctx, CommonInfo, "; 3010*0fca6ea1SDimitry Andric OS << "attr::" << R.getName() << ", "; 3011*0fca6ea1SDimitry Andric 3012*0fca6ea1SDimitry Andric // Handle different late parsing modes. 3013*0fca6ea1SDimitry Andric OS << "/*IsLateParsed=*/"; 3014*0fca6ea1SDimitry Andric switch (getLateAttrParseKind(&R)) { 3015*0fca6ea1SDimitry Andric case LateAttrParseKind::Never: 3016*0fca6ea1SDimitry Andric OS << "false"; 3017*0fca6ea1SDimitry Andric break; 3018*0fca6ea1SDimitry Andric case LateAttrParseKind::ExperimentalExt: 3019*0fca6ea1SDimitry Andric // Currently no clients need to know the distinction between `Standard` 3020*0fca6ea1SDimitry Andric // and `ExperimentalExt` so treat `ExperimentalExt` just like 3021*0fca6ea1SDimitry Andric // `Standard` for now. 3022*0fca6ea1SDimitry Andric case LateAttrParseKind::Standard: 3023*0fca6ea1SDimitry Andric // Note: This is misleading. `IsLateParsed` doesn't mean the 3024*0fca6ea1SDimitry Andric // attribute was actually late parsed. Instead it means the attribute in 3025*0fca6ea1SDimitry Andric // `Attr.td` is marked as being late parsed. Maybe it should be called 3026*0fca6ea1SDimitry Andric // `IsLateParseable`? 3027*0fca6ea1SDimitry Andric OS << "true"; 3028*0fca6ea1SDimitry Andric break; 3029*0fca6ea1SDimitry Andric } 3030*0fca6ea1SDimitry Andric 30310b57cec5SDimitry Andric if (Inheritable) { 30320b57cec5SDimitry Andric OS << ", " 30330b57cec5SDimitry Andric << (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true" 30340b57cec5SDimitry Andric : "false"); 30350b57cec5SDimitry Andric } 30360b57cec5SDimitry Andric OS << ")\n"; 30370b57cec5SDimitry Andric 30380b57cec5SDimitry Andric for (auto const &ai : Args) { 30390b57cec5SDimitry Andric OS << " , "; 30400b57cec5SDimitry Andric if (!shouldEmitArg(ai)) { 30410b57cec5SDimitry Andric ai->writeCtorDefaultInitializers(OS); 30420b57cec5SDimitry Andric } else { 30430b57cec5SDimitry Andric ai->writeCtorInitializers(OS); 30440b57cec5SDimitry Andric } 30450b57cec5SDimitry Andric OS << "\n"; 30460b57cec5SDimitry Andric } 304781ad6265SDimitry Andric if (DelayedArgs) { 304881ad6265SDimitry Andric OS << " , "; 304981ad6265SDimitry Andric DelayedArgs->writeCtorDefaultInitializers(OS); 305081ad6265SDimitry Andric OS << "\n"; 305181ad6265SDimitry Andric } 30520b57cec5SDimitry Andric 30530b57cec5SDimitry Andric OS << " {\n"; 30540b57cec5SDimitry Andric 30550b57cec5SDimitry Andric for (auto const &ai : Args) { 305681ad6265SDimitry Andric if (!shouldEmitArg(ai)) 305781ad6265SDimitry Andric continue; 30580b57cec5SDimitry Andric ai->writeCtorBody(OS); 30590b57cec5SDimitry Andric } 30600b57cec5SDimitry Andric OS << "}\n\n"; 30610b57cec5SDimitry Andric }; 30620b57cec5SDimitry Andric 30635ffd83dbSDimitry Andric if (Header) 30645ffd83dbSDimitry Andric OS << "\n // Constructors\n"; 30655ffd83dbSDimitry Andric 30660b57cec5SDimitry Andric // Emit a constructor that includes all the arguments. 30670b57cec5SDimitry Andric // This is necessary for cloning. 306881ad6265SDimitry Andric emitCtor(true, true, false); 30690b57cec5SDimitry Andric 30700b57cec5SDimitry Andric // Emit a constructor that takes all the non-fake arguments. 3071a7dea167SDimitry Andric if (HasFakeArg) 307281ad6265SDimitry Andric emitCtor(true, false, false); 30730b57cec5SDimitry Andric 30740b57cec5SDimitry Andric // Emit a constructor that takes all the non-fake, non-optional arguments. 3075a7dea167SDimitry Andric if (HasOptArg) 307681ad6265SDimitry Andric emitCtor(false, false, false); 307781ad6265SDimitry Andric 307881ad6265SDimitry Andric // Emit constructors that takes no arguments if none already exists. 307981ad6265SDimitry Andric // This is used for delaying arguments. 3080bdd1243dSDimitry Andric bool HasRequiredArgs = 3081bdd1243dSDimitry Andric llvm::count_if(Args, [=](const std::unique_ptr<Argument> &arg) { 308281ad6265SDimitry Andric return !arg->isFake() && !arg->isOptional(); 308381ad6265SDimitry Andric }); 308481ad6265SDimitry Andric if (DelayedArgs && HasRequiredArgs) 308581ad6265SDimitry Andric emitCtor(false, false, true); 30860b57cec5SDimitry Andric 30875ffd83dbSDimitry Andric if (Header) { 30885ffd83dbSDimitry Andric OS << '\n'; 30890b57cec5SDimitry Andric OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n"; 30900b57cec5SDimitry Andric OS << " void printPretty(raw_ostream &OS,\n" 30910b57cec5SDimitry Andric << " const PrintingPolicy &Policy) const;\n"; 30920b57cec5SDimitry Andric OS << " const char *getSpelling() const;\n"; 30935ffd83dbSDimitry Andric } 30940b57cec5SDimitry Andric 30950b57cec5SDimitry Andric if (!ElideSpelling) { 30960b57cec5SDimitry Andric assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list"); 30975ffd83dbSDimitry Andric if (Header) 30985ffd83dbSDimitry Andric OS << " Spelling getSemanticSpelling() const;\n"; 30995ffd83dbSDimitry Andric else { 31005ffd83dbSDimitry Andric OS << R.getName() << "Attr::Spelling " << R.getName() 31015ffd83dbSDimitry Andric << "Attr::getSemanticSpelling() const {\n"; 3102a7dea167SDimitry Andric WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()", 3103a7dea167SDimitry Andric SemanticToSyntacticMap, OS); 31040b57cec5SDimitry Andric OS << "}\n"; 31050b57cec5SDimitry Andric } 31065ffd83dbSDimitry Andric } 31070b57cec5SDimitry Andric 31085ffd83dbSDimitry Andric if (Header) 31090b57cec5SDimitry Andric writeAttrAccessorDefinition(R, OS); 31100b57cec5SDimitry Andric 31110b57cec5SDimitry Andric for (auto const &ai : Args) { 31125ffd83dbSDimitry Andric if (Header) { 31130b57cec5SDimitry Andric ai->writeAccessors(OS); 31145ffd83dbSDimitry Andric } else { 31155ffd83dbSDimitry Andric ai->writeAccessorDefinitions(OS); 31165ffd83dbSDimitry Andric } 31170b57cec5SDimitry Andric OS << "\n\n"; 31180b57cec5SDimitry Andric 31190b57cec5SDimitry Andric // Don't write conversion routines for fake arguments. 31200b57cec5SDimitry Andric if (ai->isFake()) continue; 31210b57cec5SDimitry Andric 31220b57cec5SDimitry Andric if (ai->isEnumArg()) 31235ffd83dbSDimitry Andric static_cast<const EnumArgument *>(ai.get())->writeConversion(OS, 31245ffd83dbSDimitry Andric Header); 31250b57cec5SDimitry Andric else if (ai->isVariadicEnumArg()) 31265ffd83dbSDimitry Andric static_cast<const VariadicEnumArgument *>(ai.get())->writeConversion( 31275ffd83dbSDimitry Andric OS, Header); 31280b57cec5SDimitry Andric } 31290b57cec5SDimitry Andric 31305ffd83dbSDimitry Andric if (Header) { 313181ad6265SDimitry Andric if (DelayedArgs) { 313281ad6265SDimitry Andric DelayedArgs->writeAccessors(OS); 313381ad6265SDimitry Andric DelayedArgs->writeSetter(OS); 313481ad6265SDimitry Andric } 313581ad6265SDimitry Andric 31360b57cec5SDimitry Andric OS << R.getValueAsString("AdditionalMembers"); 31370b57cec5SDimitry Andric OS << "\n\n"; 31380b57cec5SDimitry Andric 31390b57cec5SDimitry Andric OS << " static bool classof(const Attr *A) { return A->getKind() == " 31400b57cec5SDimitry Andric << "attr::" << R.getName() << "; }\n"; 31410b57cec5SDimitry Andric 31420b57cec5SDimitry Andric OS << "};\n\n"; 31435ffd83dbSDimitry Andric } else { 314481ad6265SDimitry Andric if (DelayedArgs) 314581ad6265SDimitry Andric DelayedArgs->writeAccessorDefinitions(OS); 314681ad6265SDimitry Andric 31470b57cec5SDimitry Andric OS << R.getName() << "Attr *" << R.getName() 31480b57cec5SDimitry Andric << "Attr::clone(ASTContext &C) const {\n"; 3149a7dea167SDimitry Andric OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this"; 31500b57cec5SDimitry Andric for (auto const &ai : Args) { 31510b57cec5SDimitry Andric OS << ", "; 31520b57cec5SDimitry Andric ai->writeCloneArgs(OS); 31530b57cec5SDimitry Andric } 3154a7dea167SDimitry Andric OS << ");\n"; 31550b57cec5SDimitry Andric OS << " A->Inherited = Inherited;\n"; 31560b57cec5SDimitry Andric OS << " A->IsPackExpansion = IsPackExpansion;\n"; 3157a7dea167SDimitry Andric OS << " A->setImplicit(Implicit);\n"; 315881ad6265SDimitry Andric if (DelayedArgs) { 315981ad6265SDimitry Andric OS << " A->setDelayedArgs(C, "; 316081ad6265SDimitry Andric DelayedArgs->writeCloneArgs(OS); 316181ad6265SDimitry Andric OS << ");\n"; 316281ad6265SDimitry Andric } 31630b57cec5SDimitry Andric OS << " return A;\n}\n\n"; 31640b57cec5SDimitry Andric 31650b57cec5SDimitry Andric writePrettyPrintFunction(R, Args, OS); 31660b57cec5SDimitry Andric writeGetSpellingFunction(R, OS); 31670b57cec5SDimitry Andric } 31685ffd83dbSDimitry Andric } 31695ffd83dbSDimitry Andric } 31705ffd83dbSDimitry Andric // Emits the class definitions for attributes. 31715ffd83dbSDimitry Andric void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { 31725f757f3fSDimitry Andric emitSourceFileHeader("Attribute classes' definitions", OS, Records); 31735ffd83dbSDimitry Andric 31745ffd83dbSDimitry Andric OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n"; 31755ffd83dbSDimitry Andric OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n"; 31765ffd83dbSDimitry Andric 31775ffd83dbSDimitry Andric emitAttributes(Records, OS, true); 31785ffd83dbSDimitry Andric 31795ffd83dbSDimitry Andric OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n"; 31805ffd83dbSDimitry Andric } 31815ffd83dbSDimitry Andric 31825ffd83dbSDimitry Andric // Emits the class method definitions for attributes. 31835ffd83dbSDimitry Andric void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { 31845f757f3fSDimitry Andric emitSourceFileHeader("Attribute classes' member function definitions", OS, 31855f757f3fSDimitry Andric Records); 31865ffd83dbSDimitry Andric 31875ffd83dbSDimitry Andric emitAttributes(Records, OS, false); 31885ffd83dbSDimitry Andric 31895ffd83dbSDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 31900b57cec5SDimitry Andric 31910b57cec5SDimitry Andric // Instead of relying on virtual dispatch we just create a huge dispatch 31920b57cec5SDimitry Andric // switch. This is both smaller and faster than virtual functions. 31930b57cec5SDimitry Andric auto EmitFunc = [&](const char *Method) { 31940b57cec5SDimitry Andric OS << " switch (getKind()) {\n"; 31950b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 31960b57cec5SDimitry Andric const Record &R = *Attr; 31970b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 31980b57cec5SDimitry Andric continue; 31990b57cec5SDimitry Andric 32000b57cec5SDimitry Andric OS << " case attr::" << R.getName() << ":\n"; 32010b57cec5SDimitry Andric OS << " return cast<" << R.getName() << "Attr>(this)->" << Method 32020b57cec5SDimitry Andric << ";\n"; 32030b57cec5SDimitry Andric } 32040b57cec5SDimitry Andric OS << " }\n"; 32050b57cec5SDimitry Andric OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n"; 32060b57cec5SDimitry Andric OS << "}\n\n"; 32070b57cec5SDimitry Andric }; 32080b57cec5SDimitry Andric 32090b57cec5SDimitry Andric OS << "const char *Attr::getSpelling() const {\n"; 32100b57cec5SDimitry Andric EmitFunc("getSpelling()"); 32110b57cec5SDimitry Andric 32120b57cec5SDimitry Andric OS << "Attr *Attr::clone(ASTContext &C) const {\n"; 32130b57cec5SDimitry Andric EmitFunc("clone(C)"); 32140b57cec5SDimitry Andric 32150b57cec5SDimitry Andric OS << "void Attr::printPretty(raw_ostream &OS, " 32160b57cec5SDimitry Andric "const PrintingPolicy &Policy) const {\n"; 32170b57cec5SDimitry Andric EmitFunc("printPretty(OS, Policy)"); 32180b57cec5SDimitry Andric } 32190b57cec5SDimitry Andric 32200b57cec5SDimitry Andric static void emitAttrList(raw_ostream &OS, StringRef Class, 32210b57cec5SDimitry Andric const std::vector<Record*> &AttrList) { 32220b57cec5SDimitry Andric for (auto Cur : AttrList) { 32230b57cec5SDimitry Andric OS << Class << "(" << Cur->getName() << ")\n"; 32240b57cec5SDimitry Andric } 32250b57cec5SDimitry Andric } 32260b57cec5SDimitry Andric 32270b57cec5SDimitry Andric // Determines if an attribute has a Pragma spelling. 32280b57cec5SDimitry Andric static bool AttrHasPragmaSpelling(const Record *R) { 32290b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R); 3230349cc55cSDimitry Andric return llvm::any_of(Spellings, [](const FlattenedSpelling &S) { 32310b57cec5SDimitry Andric return S.variety() == "Pragma"; 3232349cc55cSDimitry Andric }); 32330b57cec5SDimitry Andric } 32340b57cec5SDimitry Andric 32350b57cec5SDimitry Andric namespace { 32360b57cec5SDimitry Andric 32370b57cec5SDimitry Andric struct AttrClassDescriptor { 32380b57cec5SDimitry Andric const char * const MacroName; 32390b57cec5SDimitry Andric const char * const TableGenName; 32400b57cec5SDimitry Andric }; 32410b57cec5SDimitry Andric 32420b57cec5SDimitry Andric } // end anonymous namespace 32430b57cec5SDimitry Andric 32440b57cec5SDimitry Andric static const AttrClassDescriptor AttrClassDescriptors[] = { 32450b57cec5SDimitry Andric { "ATTR", "Attr" }, 32460b57cec5SDimitry Andric { "TYPE_ATTR", "TypeAttr" }, 32470b57cec5SDimitry Andric { "STMT_ATTR", "StmtAttr" }, 3248e8d8bef9SDimitry Andric { "DECL_OR_STMT_ATTR", "DeclOrStmtAttr" }, 32490b57cec5SDimitry Andric { "INHERITABLE_ATTR", "InheritableAttr" }, 32500b57cec5SDimitry Andric { "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" }, 32510b57cec5SDimitry Andric { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }, 3252bdd1243dSDimitry Andric { "PARAMETER_ABI_ATTR", "ParameterABIAttr" }, 3253bdd1243dSDimitry Andric { "HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"} 32540b57cec5SDimitry Andric }; 32550b57cec5SDimitry Andric 32560b57cec5SDimitry Andric static void emitDefaultDefine(raw_ostream &OS, StringRef name, 32570b57cec5SDimitry Andric const char *superName) { 32580b57cec5SDimitry Andric OS << "#ifndef " << name << "\n"; 32590b57cec5SDimitry Andric OS << "#define " << name << "(NAME) "; 32600b57cec5SDimitry Andric if (superName) OS << superName << "(NAME)"; 32610b57cec5SDimitry Andric OS << "\n#endif\n\n"; 32620b57cec5SDimitry Andric } 32630b57cec5SDimitry Andric 32640b57cec5SDimitry Andric namespace { 32650b57cec5SDimitry Andric 32660b57cec5SDimitry Andric /// A class of attributes. 32670b57cec5SDimitry Andric struct AttrClass { 32680b57cec5SDimitry Andric const AttrClassDescriptor &Descriptor; 32690b57cec5SDimitry Andric Record *TheRecord; 32700b57cec5SDimitry Andric AttrClass *SuperClass = nullptr; 32710b57cec5SDimitry Andric std::vector<AttrClass*> SubClasses; 32720b57cec5SDimitry Andric std::vector<Record*> Attrs; 32730b57cec5SDimitry Andric 32740b57cec5SDimitry Andric AttrClass(const AttrClassDescriptor &Descriptor, Record *R) 32750b57cec5SDimitry Andric : Descriptor(Descriptor), TheRecord(R) {} 32760b57cec5SDimitry Andric 32770b57cec5SDimitry Andric void emitDefaultDefines(raw_ostream &OS) const { 32780b57cec5SDimitry Andric // Default the macro unless this is a root class (i.e. Attr). 32790b57cec5SDimitry Andric if (SuperClass) { 32800b57cec5SDimitry Andric emitDefaultDefine(OS, Descriptor.MacroName, 32810b57cec5SDimitry Andric SuperClass->Descriptor.MacroName); 32820b57cec5SDimitry Andric } 32830b57cec5SDimitry Andric } 32840b57cec5SDimitry Andric 32850b57cec5SDimitry Andric void emitUndefs(raw_ostream &OS) const { 32860b57cec5SDimitry Andric OS << "#undef " << Descriptor.MacroName << "\n"; 32870b57cec5SDimitry Andric } 32880b57cec5SDimitry Andric 32890b57cec5SDimitry Andric void emitAttrList(raw_ostream &OS) const { 32900b57cec5SDimitry Andric for (auto SubClass : SubClasses) { 32910b57cec5SDimitry Andric SubClass->emitAttrList(OS); 32920b57cec5SDimitry Andric } 32930b57cec5SDimitry Andric 32940b57cec5SDimitry Andric ::emitAttrList(OS, Descriptor.MacroName, Attrs); 32950b57cec5SDimitry Andric } 32960b57cec5SDimitry Andric 32970b57cec5SDimitry Andric void classifyAttrOnRoot(Record *Attr) { 32980b57cec5SDimitry Andric bool result = classifyAttr(Attr); 32990b57cec5SDimitry Andric assert(result && "failed to classify on root"); (void) result; 33000b57cec5SDimitry Andric } 33010b57cec5SDimitry Andric 33020b57cec5SDimitry Andric void emitAttrRange(raw_ostream &OS) const { 33030b57cec5SDimitry Andric OS << "ATTR_RANGE(" << Descriptor.TableGenName 33040b57cec5SDimitry Andric << ", " << getFirstAttr()->getName() 33050b57cec5SDimitry Andric << ", " << getLastAttr()->getName() << ")\n"; 33060b57cec5SDimitry Andric } 33070b57cec5SDimitry Andric 33080b57cec5SDimitry Andric private: 33090b57cec5SDimitry Andric bool classifyAttr(Record *Attr) { 33100b57cec5SDimitry Andric // Check all the subclasses. 33110b57cec5SDimitry Andric for (auto SubClass : SubClasses) { 33120b57cec5SDimitry Andric if (SubClass->classifyAttr(Attr)) 33130b57cec5SDimitry Andric return true; 33140b57cec5SDimitry Andric } 33150b57cec5SDimitry Andric 33160b57cec5SDimitry Andric // It's not more specific than this class, but it might still belong here. 33170b57cec5SDimitry Andric if (Attr->isSubClassOf(TheRecord)) { 33180b57cec5SDimitry Andric Attrs.push_back(Attr); 33190b57cec5SDimitry Andric return true; 33200b57cec5SDimitry Andric } 33210b57cec5SDimitry Andric 33220b57cec5SDimitry Andric return false; 33230b57cec5SDimitry Andric } 33240b57cec5SDimitry Andric 33250b57cec5SDimitry Andric Record *getFirstAttr() const { 33260b57cec5SDimitry Andric if (!SubClasses.empty()) 33270b57cec5SDimitry Andric return SubClasses.front()->getFirstAttr(); 33280b57cec5SDimitry Andric return Attrs.front(); 33290b57cec5SDimitry Andric } 33300b57cec5SDimitry Andric 33310b57cec5SDimitry Andric Record *getLastAttr() const { 33320b57cec5SDimitry Andric if (!Attrs.empty()) 33330b57cec5SDimitry Andric return Attrs.back(); 33340b57cec5SDimitry Andric return SubClasses.back()->getLastAttr(); 33350b57cec5SDimitry Andric } 33360b57cec5SDimitry Andric }; 33370b57cec5SDimitry Andric 33380b57cec5SDimitry Andric /// The entire hierarchy of attribute classes. 33390b57cec5SDimitry Andric class AttrClassHierarchy { 33400b57cec5SDimitry Andric std::vector<std::unique_ptr<AttrClass>> Classes; 33410b57cec5SDimitry Andric 33420b57cec5SDimitry Andric public: 33430b57cec5SDimitry Andric AttrClassHierarchy(RecordKeeper &Records) { 33440b57cec5SDimitry Andric // Find records for all the classes. 33450b57cec5SDimitry Andric for (auto &Descriptor : AttrClassDescriptors) { 33460b57cec5SDimitry Andric Record *ClassRecord = Records.getClass(Descriptor.TableGenName); 33470b57cec5SDimitry Andric AttrClass *Class = new AttrClass(Descriptor, ClassRecord); 33480b57cec5SDimitry Andric Classes.emplace_back(Class); 33490b57cec5SDimitry Andric } 33500b57cec5SDimitry Andric 33510b57cec5SDimitry Andric // Link up the hierarchy. 33520b57cec5SDimitry Andric for (auto &Class : Classes) { 33530b57cec5SDimitry Andric if (AttrClass *SuperClass = findSuperClass(Class->TheRecord)) { 33540b57cec5SDimitry Andric Class->SuperClass = SuperClass; 33550b57cec5SDimitry Andric SuperClass->SubClasses.push_back(Class.get()); 33560b57cec5SDimitry Andric } 33570b57cec5SDimitry Andric } 33580b57cec5SDimitry Andric 33590b57cec5SDimitry Andric #ifndef NDEBUG 33600b57cec5SDimitry Andric for (auto i = Classes.begin(), e = Classes.end(); i != e; ++i) { 33610b57cec5SDimitry Andric assert((i == Classes.begin()) == ((*i)->SuperClass == nullptr) && 33620b57cec5SDimitry Andric "only the first class should be a root class!"); 33630b57cec5SDimitry Andric } 33640b57cec5SDimitry Andric #endif 33650b57cec5SDimitry Andric } 33660b57cec5SDimitry Andric 33670b57cec5SDimitry Andric void emitDefaultDefines(raw_ostream &OS) const { 33680b57cec5SDimitry Andric for (auto &Class : Classes) { 33690b57cec5SDimitry Andric Class->emitDefaultDefines(OS); 33700b57cec5SDimitry Andric } 33710b57cec5SDimitry Andric } 33720b57cec5SDimitry Andric 33730b57cec5SDimitry Andric void emitUndefs(raw_ostream &OS) const { 33740b57cec5SDimitry Andric for (auto &Class : Classes) { 33750b57cec5SDimitry Andric Class->emitUndefs(OS); 33760b57cec5SDimitry Andric } 33770b57cec5SDimitry Andric } 33780b57cec5SDimitry Andric 33790b57cec5SDimitry Andric void emitAttrLists(raw_ostream &OS) const { 33800b57cec5SDimitry Andric // Just start from the root class. 33810b57cec5SDimitry Andric Classes[0]->emitAttrList(OS); 33820b57cec5SDimitry Andric } 33830b57cec5SDimitry Andric 33840b57cec5SDimitry Andric void emitAttrRanges(raw_ostream &OS) const { 33850b57cec5SDimitry Andric for (auto &Class : Classes) 33860b57cec5SDimitry Andric Class->emitAttrRange(OS); 33870b57cec5SDimitry Andric } 33880b57cec5SDimitry Andric 33890b57cec5SDimitry Andric void classifyAttr(Record *Attr) { 33900b57cec5SDimitry Andric // Add the attribute to the root class. 33910b57cec5SDimitry Andric Classes[0]->classifyAttrOnRoot(Attr); 33920b57cec5SDimitry Andric } 33930b57cec5SDimitry Andric 33940b57cec5SDimitry Andric private: 33950b57cec5SDimitry Andric AttrClass *findClassByRecord(Record *R) const { 33960b57cec5SDimitry Andric for (auto &Class : Classes) { 33970b57cec5SDimitry Andric if (Class->TheRecord == R) 33980b57cec5SDimitry Andric return Class.get(); 33990b57cec5SDimitry Andric } 34000b57cec5SDimitry Andric return nullptr; 34010b57cec5SDimitry Andric } 34020b57cec5SDimitry Andric 34030b57cec5SDimitry Andric AttrClass *findSuperClass(Record *R) const { 34040b57cec5SDimitry Andric // TableGen flattens the superclass list, so we just need to walk it 34050b57cec5SDimitry Andric // in reverse. 34060b57cec5SDimitry Andric auto SuperClasses = R->getSuperClasses(); 34070b57cec5SDimitry Andric for (signed i = 0, e = SuperClasses.size(); i != e; ++i) { 34080b57cec5SDimitry Andric auto SuperClass = findClassByRecord(SuperClasses[e - i - 1].first); 34090b57cec5SDimitry Andric if (SuperClass) return SuperClass; 34100b57cec5SDimitry Andric } 34110b57cec5SDimitry Andric return nullptr; 34120b57cec5SDimitry Andric } 34130b57cec5SDimitry Andric }; 34140b57cec5SDimitry Andric 34150b57cec5SDimitry Andric } // end anonymous namespace 34160b57cec5SDimitry Andric 34170b57cec5SDimitry Andric namespace clang { 34180b57cec5SDimitry Andric 34190b57cec5SDimitry Andric // Emits the enumeration list for attributes. 34200b57cec5SDimitry Andric void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { 34215f757f3fSDimitry Andric emitSourceFileHeader("List of all attributes that Clang recognizes", OS, 34225f757f3fSDimitry Andric Records); 34230b57cec5SDimitry Andric 34240b57cec5SDimitry Andric AttrClassHierarchy Hierarchy(Records); 34250b57cec5SDimitry Andric 34260b57cec5SDimitry Andric // Add defaulting macro definitions. 34270b57cec5SDimitry Andric Hierarchy.emitDefaultDefines(OS); 34280b57cec5SDimitry Andric emitDefaultDefine(OS, "PRAGMA_SPELLING_ATTR", nullptr); 34290b57cec5SDimitry Andric 34300b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 34310b57cec5SDimitry Andric std::vector<Record *> PragmaAttrs; 34320b57cec5SDimitry Andric for (auto *Attr : Attrs) { 34330b57cec5SDimitry Andric if (!Attr->getValueAsBit("ASTNode")) 34340b57cec5SDimitry Andric continue; 34350b57cec5SDimitry Andric 34360b57cec5SDimitry Andric // Add the attribute to the ad-hoc groups. 34370b57cec5SDimitry Andric if (AttrHasPragmaSpelling(Attr)) 34380b57cec5SDimitry Andric PragmaAttrs.push_back(Attr); 34390b57cec5SDimitry Andric 34400b57cec5SDimitry Andric // Place it in the hierarchy. 34410b57cec5SDimitry Andric Hierarchy.classifyAttr(Attr); 34420b57cec5SDimitry Andric } 34430b57cec5SDimitry Andric 34440b57cec5SDimitry Andric // Emit the main attribute list. 34450b57cec5SDimitry Andric Hierarchy.emitAttrLists(OS); 34460b57cec5SDimitry Andric 34470b57cec5SDimitry Andric // Emit the ad hoc groups. 34480b57cec5SDimitry Andric emitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs); 34490b57cec5SDimitry Andric 34500b57cec5SDimitry Andric // Emit the attribute ranges. 34510b57cec5SDimitry Andric OS << "#ifdef ATTR_RANGE\n"; 34520b57cec5SDimitry Andric Hierarchy.emitAttrRanges(OS); 34530b57cec5SDimitry Andric OS << "#undef ATTR_RANGE\n"; 34540b57cec5SDimitry Andric OS << "#endif\n"; 34550b57cec5SDimitry Andric 34560b57cec5SDimitry Andric Hierarchy.emitUndefs(OS); 34570b57cec5SDimitry Andric OS << "#undef PRAGMA_SPELLING_ATTR\n"; 34580b57cec5SDimitry Andric } 34590b57cec5SDimitry Andric 34600b57cec5SDimitry Andric // Emits the enumeration list for attributes. 34610b57cec5SDimitry Andric void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) { 34620b57cec5SDimitry Andric emitSourceFileHeader( 34635f757f3fSDimitry Andric "List of all attribute subject matching rules that Clang recognizes", OS, 34645f757f3fSDimitry Andric Records); 34650b57cec5SDimitry Andric PragmaClangAttributeSupport &PragmaAttributeSupport = 34660b57cec5SDimitry Andric getPragmaAttributeSupport(Records); 34670b57cec5SDimitry Andric emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr); 34680b57cec5SDimitry Andric PragmaAttributeSupport.emitMatchRuleList(OS); 34690b57cec5SDimitry Andric OS << "#undef ATTR_MATCH_RULE\n"; 34700b57cec5SDimitry Andric } 34710b57cec5SDimitry Andric 34720b57cec5SDimitry Andric // Emits the code to read an attribute from a precompiled header. 34730b57cec5SDimitry Andric void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) { 34745f757f3fSDimitry Andric emitSourceFileHeader("Attribute deserialization code", OS, Records); 34750b57cec5SDimitry Andric 34760b57cec5SDimitry Andric Record *InhClass = Records.getClass("InheritableAttr"); 34770b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), 34780b57cec5SDimitry Andric ArgRecords; 34790b57cec5SDimitry Andric std::vector<std::unique_ptr<Argument>> Args; 348081ad6265SDimitry Andric std::unique_ptr<VariadicExprArgument> DelayedArgs; 34810b57cec5SDimitry Andric 34820b57cec5SDimitry Andric OS << " switch (Kind) {\n"; 34830b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 34840b57cec5SDimitry Andric const Record &R = *Attr; 34850b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 34860b57cec5SDimitry Andric continue; 34870b57cec5SDimitry Andric 34880b57cec5SDimitry Andric OS << " case attr::" << R.getName() << ": {\n"; 34890b57cec5SDimitry Andric if (R.isSubClassOf(InhClass)) 34900b57cec5SDimitry Andric OS << " bool isInherited = Record.readInt();\n"; 34910b57cec5SDimitry Andric OS << " bool isImplicit = Record.readInt();\n"; 3492e837bb5cSDimitry Andric OS << " bool isPackExpansion = Record.readInt();\n"; 349381ad6265SDimitry Andric DelayedArgs = nullptr; 349481ad6265SDimitry Andric if (Attr->getValueAsBit("AcceptsExprPack")) { 349581ad6265SDimitry Andric DelayedArgs = 349681ad6265SDimitry Andric std::make_unique<VariadicExprArgument>("DelayedArgs", R.getName()); 349781ad6265SDimitry Andric DelayedArgs->writePCHReadDecls(OS); 349881ad6265SDimitry Andric } 34990b57cec5SDimitry Andric ArgRecords = R.getValueAsListOfDefs("Args"); 35000b57cec5SDimitry Andric Args.clear(); 35010b57cec5SDimitry Andric for (const auto *Arg : ArgRecords) { 35020b57cec5SDimitry Andric Args.emplace_back(createArgument(*Arg, R.getName())); 35030b57cec5SDimitry Andric Args.back()->writePCHReadDecls(OS); 35040b57cec5SDimitry Andric } 3505a7dea167SDimitry Andric OS << " New = new (Context) " << R.getName() << "Attr(Context, Info"; 35060b57cec5SDimitry Andric for (auto const &ri : Args) { 35070b57cec5SDimitry Andric OS << ", "; 35080b57cec5SDimitry Andric ri->writePCHReadArgs(OS); 35090b57cec5SDimitry Andric } 3510a7dea167SDimitry Andric OS << ");\n"; 35110b57cec5SDimitry Andric if (R.isSubClassOf(InhClass)) 35120b57cec5SDimitry Andric OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n"; 35130b57cec5SDimitry Andric OS << " New->setImplicit(isImplicit);\n"; 3514e837bb5cSDimitry Andric OS << " New->setPackExpansion(isPackExpansion);\n"; 351581ad6265SDimitry Andric if (DelayedArgs) { 351681ad6265SDimitry Andric OS << " cast<" << R.getName() 351781ad6265SDimitry Andric << "Attr>(New)->setDelayedArgs(Context, "; 351881ad6265SDimitry Andric DelayedArgs->writePCHReadArgs(OS); 351981ad6265SDimitry Andric OS << ");\n"; 352081ad6265SDimitry Andric } 35210b57cec5SDimitry Andric OS << " break;\n"; 35220b57cec5SDimitry Andric OS << " }\n"; 35230b57cec5SDimitry Andric } 35240b57cec5SDimitry Andric OS << " }\n"; 35250b57cec5SDimitry Andric } 35260b57cec5SDimitry Andric 35270b57cec5SDimitry Andric // Emits the code to write an attribute to a precompiled header. 35280b57cec5SDimitry Andric void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { 35295f757f3fSDimitry Andric emitSourceFileHeader("Attribute serialization code", OS, Records); 35300b57cec5SDimitry Andric 35310b57cec5SDimitry Andric Record *InhClass = Records.getClass("InheritableAttr"); 35320b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; 35330b57cec5SDimitry Andric 35340b57cec5SDimitry Andric OS << " switch (A->getKind()) {\n"; 35350b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 35360b57cec5SDimitry Andric const Record &R = *Attr; 35370b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 35380b57cec5SDimitry Andric continue; 35390b57cec5SDimitry Andric OS << " case attr::" << R.getName() << ": {\n"; 35400b57cec5SDimitry Andric Args = R.getValueAsListOfDefs("Args"); 35410b57cec5SDimitry Andric if (R.isSubClassOf(InhClass) || !Args.empty()) 35420b57cec5SDimitry Andric OS << " const auto *SA = cast<" << R.getName() 35430b57cec5SDimitry Andric << "Attr>(A);\n"; 35440b57cec5SDimitry Andric if (R.isSubClassOf(InhClass)) 35450b57cec5SDimitry Andric OS << " Record.push_back(SA->isInherited());\n"; 35460b57cec5SDimitry Andric OS << " Record.push_back(A->isImplicit());\n"; 3547e837bb5cSDimitry Andric OS << " Record.push_back(A->isPackExpansion());\n"; 354881ad6265SDimitry Andric if (Attr->getValueAsBit("AcceptsExprPack")) 354981ad6265SDimitry Andric VariadicExprArgument("DelayedArgs", R.getName()).writePCHWrite(OS); 35500b57cec5SDimitry Andric 35510b57cec5SDimitry Andric for (const auto *Arg : Args) 35520b57cec5SDimitry Andric createArgument(*Arg, R.getName())->writePCHWrite(OS); 35530b57cec5SDimitry Andric OS << " break;\n"; 35540b57cec5SDimitry Andric OS << " }\n"; 35550b57cec5SDimitry Andric } 35560b57cec5SDimitry Andric OS << " }\n"; 35570b57cec5SDimitry Andric } 35580b57cec5SDimitry Andric 3559*0fca6ea1SDimitry Andric } // namespace clang 3560*0fca6ea1SDimitry Andric 35610b57cec5SDimitry Andric // Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test' 35620b57cec5SDimitry Andric // parameter with only a single check type, if applicable. 35630b57cec5SDimitry Andric static bool GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test, 35640b57cec5SDimitry Andric std::string *FnName, 35650b57cec5SDimitry Andric StringRef ListName, 35660b57cec5SDimitry Andric StringRef CheckAgainst, 35670b57cec5SDimitry Andric StringRef Scope) { 35680b57cec5SDimitry Andric if (!R->isValueUnset(ListName)) { 35690b57cec5SDimitry Andric Test += " && ("; 35700b57cec5SDimitry Andric std::vector<StringRef> Items = R->getValueAsListOfStrings(ListName); 35710b57cec5SDimitry Andric for (auto I = Items.begin(), E = Items.end(); I != E; ++I) { 35720b57cec5SDimitry Andric StringRef Part = *I; 35730b57cec5SDimitry Andric Test += CheckAgainst; 35740b57cec5SDimitry Andric Test += " == "; 35750b57cec5SDimitry Andric Test += Scope; 35760b57cec5SDimitry Andric Test += Part; 35770b57cec5SDimitry Andric if (I + 1 != E) 35780b57cec5SDimitry Andric Test += " || "; 35790b57cec5SDimitry Andric if (FnName) 35800b57cec5SDimitry Andric *FnName += Part; 35810b57cec5SDimitry Andric } 35820b57cec5SDimitry Andric Test += ")"; 35830b57cec5SDimitry Andric return true; 35840b57cec5SDimitry Andric } 35850b57cec5SDimitry Andric return false; 35860b57cec5SDimitry Andric } 35870b57cec5SDimitry Andric 35880b57cec5SDimitry Andric // Generate a conditional expression to check if the current target satisfies 35890b57cec5SDimitry Andric // the conditions for a TargetSpecificAttr record, and append the code for 35900b57cec5SDimitry Andric // those checks to the Test string. If the FnName string pointer is non-null, 35910b57cec5SDimitry Andric // append a unique suffix to distinguish this set of target checks from other 35920b57cec5SDimitry Andric // TargetSpecificAttr records. 35930b57cec5SDimitry Andric static bool GenerateTargetSpecificAttrChecks(const Record *R, 35940b57cec5SDimitry Andric std::vector<StringRef> &Arches, 35950b57cec5SDimitry Andric std::string &Test, 35960b57cec5SDimitry Andric std::string *FnName) { 35970b57cec5SDimitry Andric bool AnyTargetChecks = false; 35980b57cec5SDimitry Andric 35990b57cec5SDimitry Andric // It is assumed that there will be an llvm::Triple object 36000b57cec5SDimitry Andric // named "T" and a TargetInfo object named "Target" within 36010b57cec5SDimitry Andric // scope that can be used to determine whether the attribute exists in 36020b57cec5SDimitry Andric // a given target. 36030b57cec5SDimitry Andric Test += "true"; 36040b57cec5SDimitry Andric // If one or more architectures is specified, check those. Arches are handled 36050b57cec5SDimitry Andric // differently because GenerateTargetRequirements needs to combine the list 36060b57cec5SDimitry Andric // with ParseKind. 36070b57cec5SDimitry Andric if (!Arches.empty()) { 36080b57cec5SDimitry Andric AnyTargetChecks = true; 36090b57cec5SDimitry Andric Test += " && ("; 36100b57cec5SDimitry Andric for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { 36110b57cec5SDimitry Andric StringRef Part = *I; 36120b57cec5SDimitry Andric Test += "T.getArch() == llvm::Triple::"; 36130b57cec5SDimitry Andric Test += Part; 36140b57cec5SDimitry Andric if (I + 1 != E) 36150b57cec5SDimitry Andric Test += " || "; 36160b57cec5SDimitry Andric if (FnName) 36170b57cec5SDimitry Andric *FnName += Part; 36180b57cec5SDimitry Andric } 36190b57cec5SDimitry Andric Test += ")"; 36200b57cec5SDimitry Andric } 36210b57cec5SDimitry Andric 36220b57cec5SDimitry Andric // If the attribute is specific to particular OSes, check those. 36230b57cec5SDimitry Andric AnyTargetChecks |= GenerateTargetSpecificAttrCheck( 36240b57cec5SDimitry Andric R, Test, FnName, "OSes", "T.getOS()", "llvm::Triple::"); 36250b57cec5SDimitry Andric 36260b57cec5SDimitry Andric // If one or more object formats is specified, check those. 36270b57cec5SDimitry Andric AnyTargetChecks |= 36280b57cec5SDimitry Andric GenerateTargetSpecificAttrCheck(R, Test, FnName, "ObjectFormats", 36290b57cec5SDimitry Andric "T.getObjectFormat()", "llvm::Triple::"); 36300b57cec5SDimitry Andric 36310b57cec5SDimitry Andric // If custom code is specified, emit it. 36320b57cec5SDimitry Andric StringRef Code = R->getValueAsString("CustomCode"); 36330b57cec5SDimitry Andric if (!Code.empty()) { 36340b57cec5SDimitry Andric AnyTargetChecks = true; 36350b57cec5SDimitry Andric Test += " && ("; 36360b57cec5SDimitry Andric Test += Code; 36370b57cec5SDimitry Andric Test += ")"; 36380b57cec5SDimitry Andric } 36390b57cec5SDimitry Andric 36400b57cec5SDimitry Andric return AnyTargetChecks; 36410b57cec5SDimitry Andric } 36420b57cec5SDimitry Andric 36430b57cec5SDimitry Andric static void GenerateHasAttrSpellingStringSwitch( 36445f757f3fSDimitry Andric const std::vector<std::pair<const Record *, FlattenedSpelling>> &Attrs, 36455f757f3fSDimitry Andric raw_ostream &OS, const std::string &Variety, 36465f757f3fSDimitry Andric const std::string &Scope = "") { 36475f757f3fSDimitry Andric for (const auto &[Attr, Spelling] : Attrs) { 36480b57cec5SDimitry Andric // C++11-style attributes have specific version information associated with 36490b57cec5SDimitry Andric // them. If the attribute has no scope, the version information must not 36500b57cec5SDimitry Andric // have the default value (1), as that's incorrect. Instead, the unscoped 36510b57cec5SDimitry Andric // attribute version information should be taken from the SD-6 standing 36520b57cec5SDimitry Andric // document, which can be found at: 36530b57cec5SDimitry Andric // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations 3654e8d8bef9SDimitry Andric // 36555f757f3fSDimitry Andric // C23-style attributes have the same kind of version information 3656e8d8bef9SDimitry Andric // associated with them. The unscoped attribute version information should 3657e8d8bef9SDimitry Andric // be taken from the specification of the attribute in the C Standard. 365806c3fb27SDimitry Andric // 365906c3fb27SDimitry Andric // Clang-specific attributes have the same kind of version information 366006c3fb27SDimitry Andric // associated with them. This version is typically the default value (1). 366106c3fb27SDimitry Andric // These version values are clang-specific and should typically be 366206c3fb27SDimitry Andric // incremented once the attribute changes its syntax and/or semantics in a 366306c3fb27SDimitry Andric // a way that is impactful to the end user. 36640b57cec5SDimitry Andric int Version = 1; 36650b57cec5SDimitry Andric 36665f757f3fSDimitry Andric assert(Spelling.variety() == Variety); 36675f757f3fSDimitry Andric std::string Name = ""; 36685f757f3fSDimitry Andric if (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace()) { 36695f757f3fSDimitry Andric Name = Spelling.name(); 367006c3fb27SDimitry Andric Version = static_cast<int>( 367106c3fb27SDimitry Andric Spelling.getSpellingRecord().getValueAsInt("Version")); 36725f757f3fSDimitry Andric // Verify that explicitly specified CXX11 and C23 spellings (i.e. 367306c3fb27SDimitry Andric // not inferred from Clang/GCC spellings) have a version that's 36745f757f3fSDimitry Andric // different from the default (1). 367506c3fb27SDimitry Andric bool RequiresValidVersion = 36765f757f3fSDimitry Andric (Variety == "CXX11" || Variety == "C23") && 367706c3fb27SDimitry Andric Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; 367806c3fb27SDimitry Andric if (RequiresValidVersion && Scope.empty() && Version == 1) 367906c3fb27SDimitry Andric PrintError(Spelling.getSpellingRecord().getLoc(), 368006c3fb27SDimitry Andric "Standard attributes must have " 3681e8d8bef9SDimitry Andric "valid version information."); 36820b57cec5SDimitry Andric } 36830b57cec5SDimitry Andric 36840b57cec5SDimitry Andric std::string Test; 36850b57cec5SDimitry Andric if (Attr->isSubClassOf("TargetSpecificAttr")) { 36860b57cec5SDimitry Andric const Record *R = Attr->getValueAsDef("Target"); 36870b57cec5SDimitry Andric std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches"); 36880b57cec5SDimitry Andric GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr); 36895f757f3fSDimitry Andric } else if (!Attr->getValueAsListOfDefs("TargetSpecificSpellings").empty()) { 36905f757f3fSDimitry Andric // Add target checks if this spelling is target-specific. 36915f757f3fSDimitry Andric const std::vector<Record *> TargetSpellings = 36925f757f3fSDimitry Andric Attr->getValueAsListOfDefs("TargetSpecificSpellings"); 36935f757f3fSDimitry Andric for (const auto &TargetSpelling : TargetSpellings) { 36945f757f3fSDimitry Andric // Find spelling that matches current scope and name. 36955f757f3fSDimitry Andric for (const auto &Spelling : GetFlattenedSpellings(*TargetSpelling)) { 36965f757f3fSDimitry Andric if (Scope == Spelling.nameSpace() && Name == Spelling.name()) { 36975f757f3fSDimitry Andric const Record *Target = TargetSpelling->getValueAsDef("Target"); 36985f757f3fSDimitry Andric std::vector<StringRef> Arches = 36995f757f3fSDimitry Andric Target->getValueAsListOfStrings("Arches"); 37005f757f3fSDimitry Andric GenerateTargetSpecificAttrChecks(Target, Arches, Test, 37015f757f3fSDimitry Andric /*FnName=*/nullptr); 37025f757f3fSDimitry Andric break; 37035f757f3fSDimitry Andric } 37045f757f3fSDimitry Andric } 37055f757f3fSDimitry Andric } 3706*0fca6ea1SDimitry Andric } 37070b57cec5SDimitry Andric 370806c3fb27SDimitry Andric std::string TestStr = !Test.empty() 370906c3fb27SDimitry Andric ? Test + " ? " + llvm::itostr(Version) + " : 0" 371006c3fb27SDimitry Andric : llvm::itostr(Version); 37115f757f3fSDimitry Andric if (Scope.empty() || Scope == Spelling.nameSpace()) 37125f757f3fSDimitry Andric OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n"; 37130b57cec5SDimitry Andric } 37140b57cec5SDimitry Andric OS << " .Default(0);\n"; 37150b57cec5SDimitry Andric } 37160b57cec5SDimitry Andric 3717*0fca6ea1SDimitry Andric namespace clang { 3718*0fca6ea1SDimitry Andric 37197a6dacacSDimitry Andric // Emits list of regular keyword attributes with info about their arguments. 37207a6dacacSDimitry Andric void EmitClangRegularKeywordAttributeInfo(RecordKeeper &Records, 37217a6dacacSDimitry Andric raw_ostream &OS) { 37227a6dacacSDimitry Andric emitSourceFileHeader( 37237a6dacacSDimitry Andric "A list of regular keyword attributes generated from the attribute" 372406c3fb27SDimitry Andric " definitions", 372506c3fb27SDimitry Andric OS); 372606c3fb27SDimitry Andric // Assume for now that the same token is not used in multiple regular 372706c3fb27SDimitry Andric // keyword attributes. 372806c3fb27SDimitry Andric for (auto *R : Records.getAllDerivedDefinitions("Attr")) 37297a6dacacSDimitry Andric for (const auto &S : GetFlattenedSpellings(*R)) { 37307a6dacacSDimitry Andric if (!isRegularKeywordAttribute(S)) 37317a6dacacSDimitry Andric continue; 37327a6dacacSDimitry Andric std::vector<Record *> Args = R->getValueAsListOfDefs("Args"); 37337a6dacacSDimitry Andric bool HasArgs = llvm::any_of( 37347a6dacacSDimitry Andric Args, [](const Record *Arg) { return !Arg->getValueAsBit("Fake"); }); 37357a6dacacSDimitry Andric 373606c3fb27SDimitry Andric OS << "KEYWORD_ATTRIBUTE(" 37377a6dacacSDimitry Andric << S.getSpellingRecord().getValueAsString("Name") << ", " 37387a6dacacSDimitry Andric << (HasArgs ? "true" : "false") << ", )\n"; 373906c3fb27SDimitry Andric } 374006c3fb27SDimitry Andric OS << "#undef KEYWORD_ATTRIBUTE\n"; 374106c3fb27SDimitry Andric } 374206c3fb27SDimitry Andric 37430b57cec5SDimitry Andric // Emits the list of spellings for attributes. 37440b57cec5SDimitry Andric void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { 37455f757f3fSDimitry Andric emitSourceFileHeader("Code to implement the __has_attribute logic", OS, 37465f757f3fSDimitry Andric Records); 37470b57cec5SDimitry Andric 37480b57cec5SDimitry Andric // Separate all of the attributes out into four group: generic, C++11, GNU, 37490b57cec5SDimitry Andric // and declspecs. Then generate a big switch statement for each of them. 37500b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 37515f757f3fSDimitry Andric std::vector<std::pair<const Record *, FlattenedSpelling>> Declspec, Microsoft, 3752*0fca6ea1SDimitry Andric GNU, Pragma, HLSLAnnotation; 37535f757f3fSDimitry Andric std::map<std::string, 37545f757f3fSDimitry Andric std::vector<std::pair<const Record *, FlattenedSpelling>>> 37555f757f3fSDimitry Andric CXX, C23; 37560b57cec5SDimitry Andric 37570b57cec5SDimitry Andric // Walk over the list of all attributes, and split them out based on the 37580b57cec5SDimitry Andric // spelling variety. 37590b57cec5SDimitry Andric for (auto *R : Attrs) { 37600b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R); 37610b57cec5SDimitry Andric for (const auto &SI : Spellings) { 37620b57cec5SDimitry Andric const std::string &Variety = SI.variety(); 37630b57cec5SDimitry Andric if (Variety == "GNU") 37645f757f3fSDimitry Andric GNU.emplace_back(R, SI); 37650b57cec5SDimitry Andric else if (Variety == "Declspec") 37665f757f3fSDimitry Andric Declspec.emplace_back(R, SI); 37670b57cec5SDimitry Andric else if (Variety == "Microsoft") 37685f757f3fSDimitry Andric Microsoft.emplace_back(R, SI); 37690b57cec5SDimitry Andric else if (Variety == "CXX11") 37705f757f3fSDimitry Andric CXX[SI.nameSpace()].emplace_back(R, SI); 37715f757f3fSDimitry Andric else if (Variety == "C23") 37725f757f3fSDimitry Andric C23[SI.nameSpace()].emplace_back(R, SI); 37730b57cec5SDimitry Andric else if (Variety == "Pragma") 37745f757f3fSDimitry Andric Pragma.emplace_back(R, SI); 3775*0fca6ea1SDimitry Andric else if (Variety == "HLSLAnnotation") 3776*0fca6ea1SDimitry Andric HLSLAnnotation.emplace_back(R, SI); 37770b57cec5SDimitry Andric } 37780b57cec5SDimitry Andric } 37790b57cec5SDimitry Andric 37800b57cec5SDimitry Andric OS << "const llvm::Triple &T = Target.getTriple();\n"; 37810b57cec5SDimitry Andric OS << "switch (Syntax) {\n"; 378281ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_GNU:\n"; 37830b57cec5SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 37840b57cec5SDimitry Andric GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU"); 378581ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_Declspec:\n"; 37860b57cec5SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 37870b57cec5SDimitry Andric GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec"); 378881ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_Microsoft:\n"; 37890b57cec5SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 37900b57cec5SDimitry Andric GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft"); 379181ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_Pragma:\n"; 37920b57cec5SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 37930b57cec5SDimitry Andric GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); 3794*0fca6ea1SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_HLSLAnnotation:\n"; 379581ad6265SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 3796*0fca6ea1SDimitry Andric GenerateHasAttrSpellingStringSwitch(HLSLAnnotation, OS, "HLSLAnnotation"); 379781ad6265SDimitry Andric auto fn = [&OS](const char *Spelling, 37985f757f3fSDimitry Andric const std::map< 37995f757f3fSDimitry Andric std::string, 38005f757f3fSDimitry Andric std::vector<std::pair<const Record *, FlattenedSpelling>>> 38015f757f3fSDimitry Andric &List) { 380281ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n"; 38030b57cec5SDimitry Andric // C++11-style attributes are further split out based on the Scope. 38040b57cec5SDimitry Andric for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { 38050b57cec5SDimitry Andric if (I != List.cbegin()) 38060b57cec5SDimitry Andric OS << " else "; 38070b57cec5SDimitry Andric if (I->first.empty()) 38080b57cec5SDimitry Andric OS << "if (ScopeName == \"\") {\n"; 38090b57cec5SDimitry Andric else 38100b57cec5SDimitry Andric OS << "if (ScopeName == \"" << I->first << "\") {\n"; 38110b57cec5SDimitry Andric OS << " return llvm::StringSwitch<int>(Name)\n"; 38120b57cec5SDimitry Andric GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); 38130b57cec5SDimitry Andric OS << "}"; 38140b57cec5SDimitry Andric } 38150b57cec5SDimitry Andric OS << "\n} break;\n"; 38160b57cec5SDimitry Andric }; 381781ad6265SDimitry Andric fn("CXX11", CXX); 38185f757f3fSDimitry Andric fn("C23", C23); 381981ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_Keyword:\n"; 382081ad6265SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_ContextSensitiveKeyword:\n"; 382181ad6265SDimitry Andric OS << " llvm_unreachable(\"hasAttribute not supported for keyword\");\n"; 382281ad6265SDimitry Andric OS << " return 0;\n"; 382306c3fb27SDimitry Andric OS << "case AttributeCommonInfo::Syntax::AS_Implicit:\n"; 382406c3fb27SDimitry Andric OS << " llvm_unreachable (\"hasAttribute not supported for " 382506c3fb27SDimitry Andric "AS_Implicit\");\n"; 382606c3fb27SDimitry Andric OS << " return 0;\n"; 382781ad6265SDimitry Andric 38280b57cec5SDimitry Andric OS << "}\n"; 38290b57cec5SDimitry Andric } 38300b57cec5SDimitry Andric 38310b57cec5SDimitry Andric void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { 38325f757f3fSDimitry Andric emitSourceFileHeader("Code to translate different attribute spellings into " 38335f757f3fSDimitry Andric "internal identifiers", 38345f757f3fSDimitry Andric OS, Records); 38350b57cec5SDimitry Andric 3836a7dea167SDimitry Andric OS << " switch (getParsedKind()) {\n"; 3837a7dea167SDimitry Andric OS << " case IgnoredAttribute:\n"; 3838a7dea167SDimitry Andric OS << " case UnknownAttribute:\n"; 3839a7dea167SDimitry Andric OS << " case NoSemaHandlerAttribute:\n"; 3840a7dea167SDimitry Andric OS << " llvm_unreachable(\"Ignored/unknown shouldn't get here\");\n"; 38410b57cec5SDimitry Andric 38420b57cec5SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records); 38430b57cec5SDimitry Andric for (const auto &I : Attrs) { 38440b57cec5SDimitry Andric const Record &R = *I.second; 38450b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); 38460b57cec5SDimitry Andric OS << " case AT_" << I.first << ": {\n"; 38470b57cec5SDimitry Andric for (unsigned I = 0; I < Spellings.size(); ++ I) { 38480b57cec5SDimitry Andric OS << " if (Name == \"" << Spellings[I].name() << "\" && " 3849a7dea167SDimitry Andric << "getSyntax() == AttributeCommonInfo::AS_" << Spellings[I].variety() 38500b57cec5SDimitry Andric << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" 38510b57cec5SDimitry Andric << " return " << I << ";\n"; 38520b57cec5SDimitry Andric } 38530b57cec5SDimitry Andric 38540b57cec5SDimitry Andric OS << " break;\n"; 38550b57cec5SDimitry Andric OS << " }\n"; 38560b57cec5SDimitry Andric } 38570b57cec5SDimitry Andric 38580b57cec5SDimitry Andric OS << " }\n"; 38590b57cec5SDimitry Andric OS << " return 0;\n"; 38600b57cec5SDimitry Andric } 38610b57cec5SDimitry Andric 38620b57cec5SDimitry Andric // Emits code used by RecursiveASTVisitor to visit attributes 38630b57cec5SDimitry Andric void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) { 38645f757f3fSDimitry Andric emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS, 38655f757f3fSDimitry Andric Records); 38660b57cec5SDimitry Andric 38670b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 38680b57cec5SDimitry Andric 38690b57cec5SDimitry Andric // Write method declarations for Traverse* methods. 38700b57cec5SDimitry Andric // We emit this here because we only generate methods for attributes that 38710b57cec5SDimitry Andric // are declared as ASTNodes. 38720b57cec5SDimitry Andric OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n"; 38730b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 38740b57cec5SDimitry Andric const Record &R = *Attr; 38750b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 38760b57cec5SDimitry Andric continue; 38770b57cec5SDimitry Andric OS << " bool Traverse" 38780b57cec5SDimitry Andric << R.getName() << "Attr(" << R.getName() << "Attr *A);\n"; 38790b57cec5SDimitry Andric OS << " bool Visit" 38800b57cec5SDimitry Andric << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" 38810b57cec5SDimitry Andric << " return true; \n" 38820b57cec5SDimitry Andric << " }\n"; 38830b57cec5SDimitry Andric } 38840b57cec5SDimitry Andric OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n"; 38850b57cec5SDimitry Andric 38860b57cec5SDimitry Andric // Write individual Traverse* methods for each attribute class. 38870b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 38880b57cec5SDimitry Andric const Record &R = *Attr; 38890b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 38900b57cec5SDimitry Andric continue; 38910b57cec5SDimitry Andric 38920b57cec5SDimitry Andric OS << "template <typename Derived>\n" 38930b57cec5SDimitry Andric << "bool VISITORCLASS<Derived>::Traverse" 38940b57cec5SDimitry Andric << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" 38950b57cec5SDimitry Andric << " if (!getDerived().VisitAttr(A))\n" 38960b57cec5SDimitry Andric << " return false;\n" 38970b57cec5SDimitry Andric << " if (!getDerived().Visit" << R.getName() << "Attr(A))\n" 38980b57cec5SDimitry Andric << " return false;\n"; 38990b57cec5SDimitry Andric 39000b57cec5SDimitry Andric std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 39010b57cec5SDimitry Andric for (const auto *Arg : ArgRecords) 39020b57cec5SDimitry Andric createArgument(*Arg, R.getName())->writeASTVisitorTraversal(OS); 39030b57cec5SDimitry Andric 390481ad6265SDimitry Andric if (Attr->getValueAsBit("AcceptsExprPack")) 390581ad6265SDimitry Andric VariadicExprArgument("DelayedArgs", R.getName()) 390681ad6265SDimitry Andric .writeASTVisitorTraversal(OS); 390781ad6265SDimitry Andric 39080b57cec5SDimitry Andric OS << " return true;\n"; 39090b57cec5SDimitry Andric OS << "}\n\n"; 39100b57cec5SDimitry Andric } 39110b57cec5SDimitry Andric 39120b57cec5SDimitry Andric // Write generic Traverse routine 39130b57cec5SDimitry Andric OS << "template <typename Derived>\n" 39140b57cec5SDimitry Andric << "bool VISITORCLASS<Derived>::TraverseAttr(Attr *A) {\n" 39150b57cec5SDimitry Andric << " if (!A)\n" 39160b57cec5SDimitry Andric << " return true;\n" 39170b57cec5SDimitry Andric << "\n" 39180b57cec5SDimitry Andric << " switch (A->getKind()) {\n"; 39190b57cec5SDimitry Andric 39200b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 39210b57cec5SDimitry Andric const Record &R = *Attr; 39220b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 39230b57cec5SDimitry Andric continue; 39240b57cec5SDimitry Andric 39250b57cec5SDimitry Andric OS << " case attr::" << R.getName() << ":\n" 39260b57cec5SDimitry Andric << " return getDerived().Traverse" << R.getName() << "Attr(" 39270b57cec5SDimitry Andric << "cast<" << R.getName() << "Attr>(A));\n"; 39280b57cec5SDimitry Andric } 39290b57cec5SDimitry Andric OS << " }\n"; // end switch 39300b57cec5SDimitry Andric OS << " llvm_unreachable(\"bad attribute kind\");\n"; 39310b57cec5SDimitry Andric OS << "}\n"; // end function 39320b57cec5SDimitry Andric OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n"; 39330b57cec5SDimitry Andric } 39340b57cec5SDimitry Andric 39350b57cec5SDimitry Andric void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs, 39360b57cec5SDimitry Andric raw_ostream &OS, 39370b57cec5SDimitry Andric bool AppliesToDecl) { 39380b57cec5SDimitry Andric 39390b57cec5SDimitry Andric OS << " switch (At->getKind()) {\n"; 39400b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 39410b57cec5SDimitry Andric const Record &R = *Attr; 39420b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 39430b57cec5SDimitry Andric continue; 39440b57cec5SDimitry Andric OS << " case attr::" << R.getName() << ": {\n"; 39450b57cec5SDimitry Andric bool ShouldClone = R.getValueAsBit("Clone") && 39460b57cec5SDimitry Andric (!AppliesToDecl || 39470b57cec5SDimitry Andric R.getValueAsBit("MeaningfulToClassTemplateDefinition")); 39480b57cec5SDimitry Andric 39490b57cec5SDimitry Andric if (!ShouldClone) { 39500b57cec5SDimitry Andric OS << " return nullptr;\n"; 39510b57cec5SDimitry Andric OS << " }\n"; 39520b57cec5SDimitry Andric continue; 39530b57cec5SDimitry Andric } 39540b57cec5SDimitry Andric 39550b57cec5SDimitry Andric OS << " const auto *A = cast<" 39560b57cec5SDimitry Andric << R.getName() << "Attr>(At);\n"; 39570b57cec5SDimitry Andric bool TDependent = R.getValueAsBit("TemplateDependent"); 39580b57cec5SDimitry Andric 39590b57cec5SDimitry Andric if (!TDependent) { 39600b57cec5SDimitry Andric OS << " return A->clone(C);\n"; 39610b57cec5SDimitry Andric OS << " }\n"; 39620b57cec5SDimitry Andric continue; 39630b57cec5SDimitry Andric } 39640b57cec5SDimitry Andric 39650b57cec5SDimitry Andric std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 39660b57cec5SDimitry Andric std::vector<std::unique_ptr<Argument>> Args; 39670b57cec5SDimitry Andric Args.reserve(ArgRecords.size()); 39680b57cec5SDimitry Andric 39690b57cec5SDimitry Andric for (const auto *ArgRecord : ArgRecords) 39700b57cec5SDimitry Andric Args.emplace_back(createArgument(*ArgRecord, R.getName())); 39710b57cec5SDimitry Andric 39720b57cec5SDimitry Andric for (auto const &ai : Args) 39730b57cec5SDimitry Andric ai->writeTemplateInstantiation(OS); 39740b57cec5SDimitry Andric 3975a7dea167SDimitry Andric OS << " return new (C) " << R.getName() << "Attr(C, *A"; 39760b57cec5SDimitry Andric for (auto const &ai : Args) { 39770b57cec5SDimitry Andric OS << ", "; 39780b57cec5SDimitry Andric ai->writeTemplateInstantiationArgs(OS); 39790b57cec5SDimitry Andric } 3980e8d8bef9SDimitry Andric OS << ");\n" 3981e8d8bef9SDimitry Andric << " }\n"; 39820b57cec5SDimitry Andric } 39830b57cec5SDimitry Andric OS << " } // end switch\n" 39840b57cec5SDimitry Andric << " llvm_unreachable(\"Unknown attribute!\");\n" 39850b57cec5SDimitry Andric << " return nullptr;\n"; 39860b57cec5SDimitry Andric } 39870b57cec5SDimitry Andric 39880b57cec5SDimitry Andric // Emits code to instantiate dependent attributes on templates. 39890b57cec5SDimitry Andric void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { 39905f757f3fSDimitry Andric emitSourceFileHeader("Template instantiation code for attributes", OS, 39915f757f3fSDimitry Andric Records); 39920b57cec5SDimitry Andric 39930b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 39940b57cec5SDimitry Andric 39950b57cec5SDimitry Andric OS << "namespace clang {\n" 39960b57cec5SDimitry Andric << "namespace sema {\n\n" 39970b57cec5SDimitry Andric << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " 39980b57cec5SDimitry Andric << "Sema &S,\n" 39990b57cec5SDimitry Andric << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; 40000b57cec5SDimitry Andric EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false); 40010b57cec5SDimitry Andric OS << "}\n\n" 40020b57cec5SDimitry Andric << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" 40030b57cec5SDimitry Andric << " ASTContext &C, Sema &S,\n" 40040b57cec5SDimitry Andric << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; 40050b57cec5SDimitry Andric EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true); 40060b57cec5SDimitry Andric OS << "}\n\n" 40070b57cec5SDimitry Andric << "} // end namespace sema\n" 40080b57cec5SDimitry Andric << "} // end namespace clang\n"; 40090b57cec5SDimitry Andric } 40100b57cec5SDimitry Andric 40110b57cec5SDimitry Andric // Emits the list of parsed attributes. 40120b57cec5SDimitry Andric void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { 40135f757f3fSDimitry Andric emitSourceFileHeader("List of all attributes that Clang recognizes", OS, 40145f757f3fSDimitry Andric Records); 40150b57cec5SDimitry Andric 40160b57cec5SDimitry Andric OS << "#ifndef PARSED_ATTR\n"; 40170b57cec5SDimitry Andric OS << "#define PARSED_ATTR(NAME) NAME\n"; 40180b57cec5SDimitry Andric OS << "#endif\n\n"; 40190b57cec5SDimitry Andric 40200b57cec5SDimitry Andric ParsedAttrMap Names = getParsedAttrList(Records); 40210b57cec5SDimitry Andric for (const auto &I : Names) { 40220b57cec5SDimitry Andric OS << "PARSED_ATTR(" << I.first << ")\n"; 40230b57cec5SDimitry Andric } 40240b57cec5SDimitry Andric } 40250b57cec5SDimitry Andric 40260b57cec5SDimitry Andric static bool isArgVariadic(const Record &R, StringRef AttrName) { 40270b57cec5SDimitry Andric return createArgument(R, AttrName)->isVariadic(); 40280b57cec5SDimitry Andric } 40290b57cec5SDimitry Andric 40300b57cec5SDimitry Andric static void emitArgInfo(const Record &R, raw_ostream &OS) { 40310b57cec5SDimitry Andric // This function will count the number of arguments specified for the 40320b57cec5SDimitry Andric // attribute and emit the number of required arguments followed by the 40330b57cec5SDimitry Andric // number of optional arguments. 40340b57cec5SDimitry Andric std::vector<Record *> Args = R.getValueAsListOfDefs("Args"); 403581ad6265SDimitry Andric unsigned ArgCount = 0, OptCount = 0, ArgMemberCount = 0; 40360b57cec5SDimitry Andric bool HasVariadic = false; 40370b57cec5SDimitry Andric for (const auto *Arg : Args) { 40380b57cec5SDimitry Andric // If the arg is fake, it's the user's job to supply it: general parsing 40390b57cec5SDimitry Andric // logic shouldn't need to know anything about it. 40400b57cec5SDimitry Andric if (Arg->getValueAsBit("Fake")) 40410b57cec5SDimitry Andric continue; 40420b57cec5SDimitry Andric Arg->getValueAsBit("Optional") ? ++OptCount : ++ArgCount; 404381ad6265SDimitry Andric ++ArgMemberCount; 40440b57cec5SDimitry Andric if (!HasVariadic && isArgVariadic(*Arg, R.getName())) 40450b57cec5SDimitry Andric HasVariadic = true; 40460b57cec5SDimitry Andric } 40470b57cec5SDimitry Andric 40480b57cec5SDimitry Andric // If there is a variadic argument, we will set the optional argument count 40490b57cec5SDimitry Andric // to its largest value. Since it's currently a 4-bit number, we set it to 15. 405081ad6265SDimitry Andric OS << " /*NumArgs=*/" << ArgCount << ",\n"; 405181ad6265SDimitry Andric OS << " /*OptArgs=*/" << (HasVariadic ? 15 : OptCount) << ",\n"; 405281ad6265SDimitry Andric OS << " /*NumArgMembers=*/" << ArgMemberCount << ",\n"; 40530b57cec5SDimitry Andric } 40540b57cec5SDimitry Andric 40550b57cec5SDimitry Andric static std::string GetDiagnosticSpelling(const Record &R) { 40565ffd83dbSDimitry Andric std::string Ret = std::string(R.getValueAsString("DiagSpelling")); 40570b57cec5SDimitry Andric if (!Ret.empty()) 40580b57cec5SDimitry Andric return Ret; 40590b57cec5SDimitry Andric 40600b57cec5SDimitry Andric // If we couldn't find the DiagSpelling in this object, we can check to see 40610b57cec5SDimitry Andric // if the object is one that has a base, and if it is, loop up to the Base 40620b57cec5SDimitry Andric // member recursively. 4063480093f4SDimitry Andric if (auto Base = R.getValueAsOptionalDef(BaseFieldName)) 4064480093f4SDimitry Andric return GetDiagnosticSpelling(*Base); 40650b57cec5SDimitry Andric 40660b57cec5SDimitry Andric return ""; 40670b57cec5SDimitry Andric } 40680b57cec5SDimitry Andric 40690b57cec5SDimitry Andric static std::string CalculateDiagnostic(const Record &S) { 40700b57cec5SDimitry Andric // If the SubjectList object has a custom diagnostic associated with it, 40710b57cec5SDimitry Andric // return that directly. 40720b57cec5SDimitry Andric const StringRef CustomDiag = S.getValueAsString("CustomDiag"); 40730b57cec5SDimitry Andric if (!CustomDiag.empty()) 40740b57cec5SDimitry Andric return ("\"" + Twine(CustomDiag) + "\"").str(); 40750b57cec5SDimitry Andric 40760b57cec5SDimitry Andric std::vector<std::string> DiagList; 40770b57cec5SDimitry Andric std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects"); 40780b57cec5SDimitry Andric for (const auto *Subject : Subjects) { 40790b57cec5SDimitry Andric const Record &R = *Subject; 40800b57cec5SDimitry Andric // Get the diagnostic text from the Decl or Stmt node given. 40810b57cec5SDimitry Andric std::string V = GetDiagnosticSpelling(R); 40820b57cec5SDimitry Andric if (V.empty()) { 40830b57cec5SDimitry Andric PrintError(R.getLoc(), 40840b57cec5SDimitry Andric "Could not determine diagnostic spelling for the node: " + 40850b57cec5SDimitry Andric R.getName() + "; please add one to DeclNodes.td"); 40860b57cec5SDimitry Andric } else { 40870b57cec5SDimitry Andric // The node may contain a list of elements itself, so split the elements 40880b57cec5SDimitry Andric // by a comma, and trim any whitespace. 40890b57cec5SDimitry Andric SmallVector<StringRef, 2> Frags; 40900b57cec5SDimitry Andric llvm::SplitString(V, Frags, ","); 40910b57cec5SDimitry Andric for (auto Str : Frags) { 40925ffd83dbSDimitry Andric DiagList.push_back(std::string(Str.trim())); 40930b57cec5SDimitry Andric } 40940b57cec5SDimitry Andric } 40950b57cec5SDimitry Andric } 40960b57cec5SDimitry Andric 40970b57cec5SDimitry Andric if (DiagList.empty()) { 40980b57cec5SDimitry Andric PrintFatalError(S.getLoc(), 40990b57cec5SDimitry Andric "Could not deduce diagnostic argument for Attr subjects"); 41000b57cec5SDimitry Andric return ""; 41010b57cec5SDimitry Andric } 41020b57cec5SDimitry Andric 41030b57cec5SDimitry Andric // FIXME: this is not particularly good for localization purposes and ideally 41040b57cec5SDimitry Andric // should be part of the diagnostics engine itself with some sort of list 41050b57cec5SDimitry Andric // specifier. 41060b57cec5SDimitry Andric 41070b57cec5SDimitry Andric // A single member of the list can be returned directly. 41080b57cec5SDimitry Andric if (DiagList.size() == 1) 41090b57cec5SDimitry Andric return '"' + DiagList.front() + '"'; 41100b57cec5SDimitry Andric 41110b57cec5SDimitry Andric if (DiagList.size() == 2) 41120b57cec5SDimitry Andric return '"' + DiagList[0] + " and " + DiagList[1] + '"'; 41130b57cec5SDimitry Andric 41140b57cec5SDimitry Andric // If there are more than two in the list, we serialize the first N - 1 41150b57cec5SDimitry Andric // elements with a comma. This leaves the string in the state: foo, bar, 41160b57cec5SDimitry Andric // baz (but misses quux). We can then add ", and " for the last element 41170b57cec5SDimitry Andric // manually. 41180b57cec5SDimitry Andric std::string Diag = llvm::join(DiagList.begin(), DiagList.end() - 1, ", "); 41190b57cec5SDimitry Andric return '"' + Diag + ", and " + *(DiagList.end() - 1) + '"'; 41200b57cec5SDimitry Andric } 41210b57cec5SDimitry Andric 41220b57cec5SDimitry Andric static std::string GetSubjectWithSuffix(const Record *R) { 41235ffd83dbSDimitry Andric const std::string &B = std::string(R->getName()); 41240b57cec5SDimitry Andric if (B == "DeclBase") 41250b57cec5SDimitry Andric return "Decl"; 41260b57cec5SDimitry Andric return B + "Decl"; 41270b57cec5SDimitry Andric } 41280b57cec5SDimitry Andric 41290b57cec5SDimitry Andric static std::string functionNameForCustomAppertainsTo(const Record &Subject) { 41300b57cec5SDimitry Andric return "is" + Subject.getName().str(); 41310b57cec5SDimitry Andric } 41320b57cec5SDimitry Andric 41335ffd83dbSDimitry Andric static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) { 41340b57cec5SDimitry Andric std::string FnName = functionNameForCustomAppertainsTo(Subject); 41350b57cec5SDimitry Andric 41365ffd83dbSDimitry Andric // If this code has already been generated, we don't need to do anything. 41370b57cec5SDimitry Andric static std::set<std::string> CustomSubjectSet; 41380b57cec5SDimitry Andric auto I = CustomSubjectSet.find(FnName); 41390b57cec5SDimitry Andric if (I != CustomSubjectSet.end()) 41405ffd83dbSDimitry Andric return; 41410b57cec5SDimitry Andric 4142480093f4SDimitry Andric // This only works with non-root Decls. 4143480093f4SDimitry Andric Record *Base = Subject.getValueAsDef(BaseFieldName); 41440b57cec5SDimitry Andric 41450b57cec5SDimitry Andric // Not currently support custom subjects within custom subjects. 41460b57cec5SDimitry Andric if (Base->isSubClassOf("SubsetSubject")) { 41470b57cec5SDimitry Andric PrintFatalError(Subject.getLoc(), 41480b57cec5SDimitry Andric "SubsetSubjects within SubsetSubjects is not supported"); 41495ffd83dbSDimitry Andric return; 41500b57cec5SDimitry Andric } 41510b57cec5SDimitry Andric 41520b57cec5SDimitry Andric OS << "static bool " << FnName << "(const Decl *D) {\n"; 41530b57cec5SDimitry Andric OS << " if (const auto *S = dyn_cast<"; 41540b57cec5SDimitry Andric OS << GetSubjectWithSuffix(Base); 41550b57cec5SDimitry Andric OS << ">(D))\n"; 41560b57cec5SDimitry Andric OS << " return " << Subject.getValueAsString("CheckCode") << ";\n"; 41570b57cec5SDimitry Andric OS << " return false;\n"; 41580b57cec5SDimitry Andric OS << "}\n\n"; 41590b57cec5SDimitry Andric 41600b57cec5SDimitry Andric CustomSubjectSet.insert(FnName); 41610b57cec5SDimitry Andric } 41620b57cec5SDimitry Andric 41635ffd83dbSDimitry Andric static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { 41640b57cec5SDimitry Andric // If the attribute does not contain a Subjects definition, then use the 41650b57cec5SDimitry Andric // default appertainsTo logic. 41660b57cec5SDimitry Andric if (Attr.isValueUnset("Subjects")) 41675ffd83dbSDimitry Andric return; 41680b57cec5SDimitry Andric 41690b57cec5SDimitry Andric const Record *SubjectObj = Attr.getValueAsDef("Subjects"); 41700b57cec5SDimitry Andric std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); 41710b57cec5SDimitry Andric 41720b57cec5SDimitry Andric // If the list of subjects is empty, it is assumed that the attribute 41730b57cec5SDimitry Andric // appertains to everything. 41740b57cec5SDimitry Andric if (Subjects.empty()) 41755ffd83dbSDimitry Andric return; 41760b57cec5SDimitry Andric 41770b57cec5SDimitry Andric bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn"); 41780b57cec5SDimitry Andric 4179fe6060f1SDimitry Andric // Split the subjects into declaration subjects and statement subjects. 4180fe6060f1SDimitry Andric // FIXME: subset subjects are added to the declaration list until there are 4181fe6060f1SDimitry Andric // enough statement attributes with custom subject needs to warrant 4182fe6060f1SDimitry Andric // the implementation effort. 4183fe6060f1SDimitry Andric std::vector<Record *> DeclSubjects, StmtSubjects; 4184fe6060f1SDimitry Andric llvm::copy_if( 4185fe6060f1SDimitry Andric Subjects, std::back_inserter(DeclSubjects), [](const Record *R) { 4186fe6060f1SDimitry Andric return R->isSubClassOf("SubsetSubject") || !R->isSubClassOf("StmtNode"); 4187fe6060f1SDimitry Andric }); 4188fe6060f1SDimitry Andric llvm::copy_if(Subjects, std::back_inserter(StmtSubjects), 4189fe6060f1SDimitry Andric [](const Record *R) { return R->isSubClassOf("StmtNode"); }); 4190fe6060f1SDimitry Andric 4191fe6060f1SDimitry Andric // We should have sorted all of the subjects into two lists. 4192fe6060f1SDimitry Andric // FIXME: this assertion will be wrong if we ever add type attribute subjects. 4193fe6060f1SDimitry Andric assert(DeclSubjects.size() + StmtSubjects.size() == Subjects.size()); 4194fe6060f1SDimitry Andric 4195fe6060f1SDimitry Andric if (DeclSubjects.empty()) { 4196fe6060f1SDimitry Andric // If there are no decl subjects but there are stmt subjects, diagnose 4197fe6060f1SDimitry Andric // trying to apply a statement attribute to a declaration. 4198fe6060f1SDimitry Andric if (!StmtSubjects.empty()) { 4199fe6060f1SDimitry Andric OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, "; 4200fe6060f1SDimitry Andric OS << "const Decl *D) const override {\n"; 420181ad6265SDimitry Andric OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n"; 420206c3fb27SDimitry Andric OS << " << AL << AL.isRegularKeywordAttribute() << " 420306c3fb27SDimitry Andric "D->getLocation();\n"; 4204fe6060f1SDimitry Andric OS << " return false;\n"; 4205fe6060f1SDimitry Andric OS << "}\n\n"; 4206fe6060f1SDimitry Andric } 4207fe6060f1SDimitry Andric } else { 4208fe6060f1SDimitry Andric // Otherwise, generate an appertainsTo check specific to this attribute 4209fe6060f1SDimitry Andric // which checks all of the given subjects against the Decl passed in. 42105ffd83dbSDimitry Andric OS << "bool diagAppertainsToDecl(Sema &S, "; 42115ffd83dbSDimitry Andric OS << "const ParsedAttr &Attr, const Decl *D) const override {\n"; 42125ffd83dbSDimitry Andric OS << " if ("; 4213fe6060f1SDimitry Andric for (auto I = DeclSubjects.begin(), E = DeclSubjects.end(); I != E; ++I) { 42145ffd83dbSDimitry Andric // If the subject has custom code associated with it, use the generated 42155ffd83dbSDimitry Andric // function for it. The function cannot be inlined into this check (yet) 42165ffd83dbSDimitry Andric // because it requires the subject to be of a specific type, and were that 4217fe6060f1SDimitry Andric // information inlined here, it would not support an attribute with 4218fe6060f1SDimitry Andric // multiple custom subjects. 4219fe6060f1SDimitry Andric if ((*I)->isSubClassOf("SubsetSubject")) 42205ffd83dbSDimitry Andric OS << "!" << functionNameForCustomAppertainsTo(**I) << "(D)"; 4221fe6060f1SDimitry Andric else 42225ffd83dbSDimitry Andric OS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)"; 42230b57cec5SDimitry Andric 42240b57cec5SDimitry Andric if (I + 1 != E) 42255ffd83dbSDimitry Andric OS << " && "; 42260b57cec5SDimitry Andric } 42275ffd83dbSDimitry Andric OS << ") {\n"; 42285ffd83dbSDimitry Andric OS << " S.Diag(Attr.getLoc(), diag::"; 4229fe6060f1SDimitry Andric OS << (Warn ? "warn_attribute_wrong_decl_type_str" 4230fe6060f1SDimitry Andric : "err_attribute_wrong_decl_type_str"); 42315ffd83dbSDimitry Andric OS << ")\n"; 423206c3fb27SDimitry Andric OS << " << Attr << Attr.isRegularKeywordAttribute() << "; 42335ffd83dbSDimitry Andric OS << CalculateDiagnostic(*SubjectObj) << ";\n"; 42345ffd83dbSDimitry Andric OS << " return false;\n"; 42355ffd83dbSDimitry Andric OS << " }\n"; 42365ffd83dbSDimitry Andric OS << " return true;\n"; 42375ffd83dbSDimitry Andric OS << "}\n\n"; 42380b57cec5SDimitry Andric } 42390b57cec5SDimitry Andric 4240fe6060f1SDimitry Andric if (StmtSubjects.empty()) { 4241fe6060f1SDimitry Andric // If there are no stmt subjects but there are decl subjects, diagnose 4242fe6060f1SDimitry Andric // trying to apply a declaration attribute to a statement. 4243fe6060f1SDimitry Andric if (!DeclSubjects.empty()) { 4244fe6060f1SDimitry Andric OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, "; 4245fe6060f1SDimitry Andric OS << "const Stmt *St) const override {\n"; 4246fe6060f1SDimitry Andric OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n"; 424706c3fb27SDimitry Andric OS << " << AL << AL.isRegularKeywordAttribute() << " 424806c3fb27SDimitry Andric "St->getBeginLoc();\n"; 4249fe6060f1SDimitry Andric OS << " return false;\n"; 4250fe6060f1SDimitry Andric OS << "}\n\n"; 4251fe6060f1SDimitry Andric } 4252fe6060f1SDimitry Andric } else { 4253fe6060f1SDimitry Andric // Now, do the same for statements. 4254fe6060f1SDimitry Andric OS << "bool diagAppertainsToStmt(Sema &S, "; 4255fe6060f1SDimitry Andric OS << "const ParsedAttr &Attr, const Stmt *St) const override {\n"; 4256fe6060f1SDimitry Andric OS << " if ("; 4257fe6060f1SDimitry Andric for (auto I = StmtSubjects.begin(), E = StmtSubjects.end(); I != E; ++I) { 4258fe6060f1SDimitry Andric OS << "!isa<" << (*I)->getName() << ">(St)"; 4259fe6060f1SDimitry Andric if (I + 1 != E) 4260fe6060f1SDimitry Andric OS << " && "; 4261fe6060f1SDimitry Andric } 4262fe6060f1SDimitry Andric OS << ") {\n"; 4263fe6060f1SDimitry Andric OS << " S.Diag(Attr.getLoc(), diag::"; 4264fe6060f1SDimitry Andric OS << (Warn ? "warn_attribute_wrong_decl_type_str" 4265fe6060f1SDimitry Andric : "err_attribute_wrong_decl_type_str"); 4266fe6060f1SDimitry Andric OS << ")\n"; 426706c3fb27SDimitry Andric OS << " << Attr << Attr.isRegularKeywordAttribute() << "; 4268fe6060f1SDimitry Andric OS << CalculateDiagnostic(*SubjectObj) << ";\n"; 4269fe6060f1SDimitry Andric OS << " return false;\n"; 4270fe6060f1SDimitry Andric OS << " }\n"; 4271fe6060f1SDimitry Andric OS << " return true;\n"; 4272fe6060f1SDimitry Andric OS << "}\n\n"; 4273fe6060f1SDimitry Andric } 4274fe6060f1SDimitry Andric } 4275fe6060f1SDimitry Andric 4276fe6060f1SDimitry Andric // Generates the mutual exclusion checks. The checks for parsed attributes are 4277fe6060f1SDimitry Andric // written into OS and the checks for merging declaration attributes are 4278fe6060f1SDimitry Andric // written into MergeOS. 4279fe6060f1SDimitry Andric static void GenerateMutualExclusionsChecks(const Record &Attr, 4280fe6060f1SDimitry Andric const RecordKeeper &Records, 4281fe6060f1SDimitry Andric raw_ostream &OS, 4282fe6060f1SDimitry Andric raw_ostream &MergeDeclOS, 4283fe6060f1SDimitry Andric raw_ostream &MergeStmtOS) { 4284fe6060f1SDimitry Andric // Find all of the definitions that inherit from MutualExclusions and include 4285fe6060f1SDimitry Andric // the given attribute in the list of exclusions to generate the 4286fe6060f1SDimitry Andric // diagMutualExclusion() check. 4287fe6060f1SDimitry Andric std::vector<Record *> ExclusionsList = 4288fe6060f1SDimitry Andric Records.getAllDerivedDefinitions("MutualExclusions"); 4289fe6060f1SDimitry Andric 4290fe6060f1SDimitry Andric // We don't do any of this magic for type attributes yet. 4291fe6060f1SDimitry Andric if (Attr.isSubClassOf("TypeAttr")) 4292fe6060f1SDimitry Andric return; 4293fe6060f1SDimitry Andric 4294fe6060f1SDimitry Andric // This means the attribute is either a statement attribute, a decl 4295fe6060f1SDimitry Andric // attribute, or both; find out which. 4296fe6060f1SDimitry Andric bool CurAttrIsStmtAttr = 4297fe6060f1SDimitry Andric Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr"); 4298fe6060f1SDimitry Andric bool CurAttrIsDeclAttr = 4299fe6060f1SDimitry Andric !CurAttrIsStmtAttr || Attr.isSubClassOf("DeclOrStmtAttr"); 4300fe6060f1SDimitry Andric 4301fe6060f1SDimitry Andric std::vector<std::string> DeclAttrs, StmtAttrs; 4302fe6060f1SDimitry Andric 4303fe6060f1SDimitry Andric for (const Record *Exclusion : ExclusionsList) { 4304fe6060f1SDimitry Andric std::vector<Record *> MutuallyExclusiveAttrs = 4305fe6060f1SDimitry Andric Exclusion->getValueAsListOfDefs("Exclusions"); 4306fe6060f1SDimitry Andric auto IsCurAttr = [Attr](const Record *R) { 4307fe6060f1SDimitry Andric return R->getName() == Attr.getName(); 4308fe6060f1SDimitry Andric }; 4309fe6060f1SDimitry Andric if (llvm::any_of(MutuallyExclusiveAttrs, IsCurAttr)) { 4310fe6060f1SDimitry Andric // This list of exclusions includes the attribute we're looking for, so 4311fe6060f1SDimitry Andric // add the exclusive attributes to the proper list for checking. 4312fe6060f1SDimitry Andric for (const Record *AttrToExclude : MutuallyExclusiveAttrs) { 4313fe6060f1SDimitry Andric if (IsCurAttr(AttrToExclude)) 4314fe6060f1SDimitry Andric continue; 4315fe6060f1SDimitry Andric 4316fe6060f1SDimitry Andric if (CurAttrIsStmtAttr) 4317fe6060f1SDimitry Andric StmtAttrs.push_back((AttrToExclude->getName() + "Attr").str()); 4318fe6060f1SDimitry Andric if (CurAttrIsDeclAttr) 4319fe6060f1SDimitry Andric DeclAttrs.push_back((AttrToExclude->getName() + "Attr").str()); 4320fe6060f1SDimitry Andric } 4321fe6060f1SDimitry Andric } 4322fe6060f1SDimitry Andric } 4323fe6060f1SDimitry Andric 4324fe6060f1SDimitry Andric // If there are any decl or stmt attributes, silence -Woverloaded-virtual 4325fe6060f1SDimitry Andric // warnings for them both. 4326fe6060f1SDimitry Andric if (!DeclAttrs.empty() || !StmtAttrs.empty()) 4327fe6060f1SDimitry Andric OS << " using ParsedAttrInfo::diagMutualExclusion;\n\n"; 4328fe6060f1SDimitry Andric 4329fe6060f1SDimitry Andric // If we discovered any decl or stmt attributes to test for, generate the 4330fe6060f1SDimitry Andric // predicates for them now. 4331fe6060f1SDimitry Andric if (!DeclAttrs.empty()) { 4332fe6060f1SDimitry Andric // Generate the ParsedAttrInfo subclass logic for declarations. 4333fe6060f1SDimitry Andric OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, " 4334fe6060f1SDimitry Andric << "const Decl *D) const override {\n"; 4335fe6060f1SDimitry Andric for (const std::string &A : DeclAttrs) { 4336fe6060f1SDimitry Andric OS << " if (const auto *A = D->getAttr<" << A << ">()) {\n"; 4337fe6060f1SDimitry Andric OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)" 433806c3fb27SDimitry Andric << " << AL << A << (AL.isRegularKeywordAttribute() ||" 433906c3fb27SDimitry Andric << " A->isRegularKeywordAttribute());\n"; 4340fe6060f1SDimitry Andric OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);"; 4341fe6060f1SDimitry Andric OS << " \nreturn false;\n"; 4342fe6060f1SDimitry Andric OS << " }\n"; 4343fe6060f1SDimitry Andric } 4344fe6060f1SDimitry Andric OS << " return true;\n"; 4345fe6060f1SDimitry Andric OS << " }\n\n"; 4346fe6060f1SDimitry Andric 4347fe6060f1SDimitry Andric // Also generate the declaration attribute merging logic if the current 4348fe6060f1SDimitry Andric // attribute is one that can be inheritted on a declaration. It is assumed 4349fe6060f1SDimitry Andric // this code will be executed in the context of a function with parameters: 4350fe6060f1SDimitry Andric // Sema &S, Decl *D, Attr *A and that returns a bool (false on diagnostic, 4351fe6060f1SDimitry Andric // true on success). 4352fe6060f1SDimitry Andric if (Attr.isSubClassOf("InheritableAttr")) { 4353fe6060f1SDimitry Andric MergeDeclOS << " if (const auto *Second = dyn_cast<" 4354fe6060f1SDimitry Andric << (Attr.getName() + "Attr").str() << ">(A)) {\n"; 4355fe6060f1SDimitry Andric for (const std::string &A : DeclAttrs) { 4356fe6060f1SDimitry Andric MergeDeclOS << " if (const auto *First = D->getAttr<" << A 4357fe6060f1SDimitry Andric << ">()) {\n"; 4358fe6060f1SDimitry Andric MergeDeclOS << " S.Diag(First->getLocation(), " 4359fe6060f1SDimitry Andric << "diag::err_attributes_are_not_compatible) << First << " 436006c3fb27SDimitry Andric << "Second << (First->isRegularKeywordAttribute() || " 436106c3fb27SDimitry Andric << "Second->isRegularKeywordAttribute());\n"; 4362fe6060f1SDimitry Andric MergeDeclOS << " S.Diag(Second->getLocation(), " 4363fe6060f1SDimitry Andric << "diag::note_conflicting_attribute);\n"; 4364fe6060f1SDimitry Andric MergeDeclOS << " return false;\n"; 4365fe6060f1SDimitry Andric MergeDeclOS << " }\n"; 4366fe6060f1SDimitry Andric } 4367fe6060f1SDimitry Andric MergeDeclOS << " return true;\n"; 4368fe6060f1SDimitry Andric MergeDeclOS << " }\n"; 4369fe6060f1SDimitry Andric } 4370fe6060f1SDimitry Andric } 4371fe6060f1SDimitry Andric 4372fe6060f1SDimitry Andric // Statement attributes are a bit different from declarations. With 4373fe6060f1SDimitry Andric // declarations, each attribute is added to the declaration as it is 4374fe6060f1SDimitry Andric // processed, and so you can look on the Decl * itself to see if there is a 4375fe6060f1SDimitry Andric // conflicting attribute. Statement attributes are processed as a group 4376fe6060f1SDimitry Andric // because AttributedStmt needs to tail-allocate all of the attribute nodes 4377fe6060f1SDimitry Andric // at once. This means we cannot check whether the statement already contains 4378fe6060f1SDimitry Andric // an attribute to check for the conflict. Instead, we need to check whether 4379fe6060f1SDimitry Andric // the given list of semantic attributes contain any conflicts. It is assumed 4380fe6060f1SDimitry Andric // this code will be executed in the context of a function with parameters: 4381fe6060f1SDimitry Andric // Sema &S, const SmallVectorImpl<const Attr *> &C. The code will be within a 4382fe6060f1SDimitry Andric // loop which loops over the container C with a loop variable named A to 4383fe6060f1SDimitry Andric // represent the current attribute to check for conflicts. 4384fe6060f1SDimitry Andric // 4385fe6060f1SDimitry Andric // FIXME: it would be nice not to walk over the list of potential attributes 4386fe6060f1SDimitry Andric // to apply to the statement more than once, but statements typically don't 4387fe6060f1SDimitry Andric // have long lists of attributes on them, so re-walking the list should not 4388fe6060f1SDimitry Andric // be an expensive operation. 4389fe6060f1SDimitry Andric if (!StmtAttrs.empty()) { 4390fe6060f1SDimitry Andric MergeStmtOS << " if (const auto *Second = dyn_cast<" 4391fe6060f1SDimitry Andric << (Attr.getName() + "Attr").str() << ">(A)) {\n"; 4392fe6060f1SDimitry Andric MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) " 4393fe6060f1SDimitry Andric << "{ return isa<"; 4394fe6060f1SDimitry Andric interleave( 4395fe6060f1SDimitry Andric StmtAttrs, [&](const std::string &Name) { MergeStmtOS << Name; }, 4396fe6060f1SDimitry Andric [&] { MergeStmtOS << ", "; }); 4397fe6060f1SDimitry Andric MergeStmtOS << ">(Check); });\n"; 4398fe6060f1SDimitry Andric MergeStmtOS << " if (Iter != C.end()) {\n"; 4399fe6060f1SDimitry Andric MergeStmtOS << " S.Diag((*Iter)->getLocation(), " 4400fe6060f1SDimitry Andric << "diag::err_attributes_are_not_compatible) << *Iter << " 440106c3fb27SDimitry Andric << "Second << ((*Iter)->isRegularKeywordAttribute() || " 440206c3fb27SDimitry Andric << "Second->isRegularKeywordAttribute());\n"; 4403fe6060f1SDimitry Andric MergeStmtOS << " S.Diag(Second->getLocation(), " 4404fe6060f1SDimitry Andric << "diag::note_conflicting_attribute);\n"; 4405fe6060f1SDimitry Andric MergeStmtOS << " return false;\n"; 4406fe6060f1SDimitry Andric MergeStmtOS << " }\n"; 4407fe6060f1SDimitry Andric MergeStmtOS << " }\n"; 4408fe6060f1SDimitry Andric } 4409fe6060f1SDimitry Andric } 4410fe6060f1SDimitry Andric 44110b57cec5SDimitry Andric static void 44120b57cec5SDimitry Andric emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport, 44130b57cec5SDimitry Andric raw_ostream &OS) { 44140b57cec5SDimitry Andric OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, " 44150b57cec5SDimitry Andric << AttributeSubjectMatchRule::EnumName << " rule) {\n"; 44160b57cec5SDimitry Andric OS << " switch (rule) {\n"; 44170b57cec5SDimitry Andric for (const auto &Rule : PragmaAttributeSupport.Rules) { 44180b57cec5SDimitry Andric if (Rule.isAbstractRule()) { 44190b57cec5SDimitry Andric OS << " case " << Rule.getEnumValue() << ":\n"; 44200b57cec5SDimitry Andric OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n"; 44210b57cec5SDimitry Andric OS << " return false;\n"; 44220b57cec5SDimitry Andric continue; 44230b57cec5SDimitry Andric } 44240b57cec5SDimitry Andric std::vector<Record *> Subjects = Rule.getSubjects(); 44250b57cec5SDimitry Andric assert(!Subjects.empty() && "Missing subjects"); 44260b57cec5SDimitry Andric OS << " case " << Rule.getEnumValue() << ":\n"; 44270b57cec5SDimitry Andric OS << " return "; 44280b57cec5SDimitry Andric for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { 44290b57cec5SDimitry Andric // If the subject has custom code associated with it, use the function 44300b57cec5SDimitry Andric // that was generated for GenerateAppertainsTo to check if the declaration 44310b57cec5SDimitry Andric // is valid. 44320b57cec5SDimitry Andric if ((*I)->isSubClassOf("SubsetSubject")) 44330b57cec5SDimitry Andric OS << functionNameForCustomAppertainsTo(**I) << "(D)"; 44340b57cec5SDimitry Andric else 44350b57cec5SDimitry Andric OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)"; 44360b57cec5SDimitry Andric 44370b57cec5SDimitry Andric if (I + 1 != E) 44380b57cec5SDimitry Andric OS << " || "; 44390b57cec5SDimitry Andric } 44400b57cec5SDimitry Andric OS << ";\n"; 44410b57cec5SDimitry Andric } 44420b57cec5SDimitry Andric OS << " }\n"; 44430b57cec5SDimitry Andric OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n"; 44440b57cec5SDimitry Andric OS << "}\n\n"; 44450b57cec5SDimitry Andric } 44460b57cec5SDimitry Andric 44475ffd83dbSDimitry Andric static void GenerateLangOptRequirements(const Record &R, 44480b57cec5SDimitry Andric raw_ostream &OS) { 44490b57cec5SDimitry Andric // If the attribute has an empty or unset list of language requirements, 44505ffd83dbSDimitry Andric // use the default handler. 44510b57cec5SDimitry Andric std::vector<Record *> LangOpts = R.getValueAsListOfDefs("LangOpts"); 44520b57cec5SDimitry Andric if (LangOpts.empty()) 44535ffd83dbSDimitry Andric return; 44540b57cec5SDimitry Andric 4455349cc55cSDimitry Andric OS << "bool acceptsLangOpts(const LangOptions &LangOpts) const override {\n"; 4456349cc55cSDimitry Andric OS << " return " << GenerateTestExpression(LangOpts) << ";\n"; 44570b57cec5SDimitry Andric OS << "}\n\n"; 44580b57cec5SDimitry Andric } 44590b57cec5SDimitry Andric 44605ffd83dbSDimitry Andric static void GenerateTargetRequirements(const Record &Attr, 44610b57cec5SDimitry Andric const ParsedAttrMap &Dupes, 44620b57cec5SDimitry Andric raw_ostream &OS) { 44635ffd83dbSDimitry Andric // If the attribute is not a target specific attribute, use the default 44640b57cec5SDimitry Andric // target handler. 44650b57cec5SDimitry Andric if (!Attr.isSubClassOf("TargetSpecificAttr")) 44665ffd83dbSDimitry Andric return; 44670b57cec5SDimitry Andric 44680b57cec5SDimitry Andric // Get the list of architectures to be tested for. 44690b57cec5SDimitry Andric const Record *R = Attr.getValueAsDef("Target"); 44700b57cec5SDimitry Andric std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches"); 44710b57cec5SDimitry Andric 44720b57cec5SDimitry Andric // If there are other attributes which share the same parsed attribute kind, 44730b57cec5SDimitry Andric // such as target-specific attributes with a shared spelling, collapse the 44740b57cec5SDimitry Andric // duplicate architectures. This is required because a shared target-specific 44750b57cec5SDimitry Andric // attribute has only one ParsedAttr::Kind enumeration value, but it 44760b57cec5SDimitry Andric // applies to multiple target architectures. In order for the attribute to be 44770b57cec5SDimitry Andric // considered valid, all of its architectures need to be included. 44780b57cec5SDimitry Andric if (!Attr.isValueUnset("ParseKind")) { 44790b57cec5SDimitry Andric const StringRef APK = Attr.getValueAsString("ParseKind"); 44800b57cec5SDimitry Andric for (const auto &I : Dupes) { 44810b57cec5SDimitry Andric if (I.first == APK) { 44820b57cec5SDimitry Andric std::vector<StringRef> DA = 44830b57cec5SDimitry Andric I.second->getValueAsDef("Target")->getValueAsListOfStrings( 44840b57cec5SDimitry Andric "Arches"); 44850b57cec5SDimitry Andric Arches.insert(Arches.end(), DA.begin(), DA.end()); 44860b57cec5SDimitry Andric } 44870b57cec5SDimitry Andric } 44880b57cec5SDimitry Andric } 44890b57cec5SDimitry Andric 44900b57cec5SDimitry Andric std::string FnName = "isTarget"; 44910b57cec5SDimitry Andric std::string Test; 44920b57cec5SDimitry Andric bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName); 44930b57cec5SDimitry Andric 44945ffd83dbSDimitry Andric OS << "bool existsInTarget(const TargetInfo &Target) const override {\n"; 44950b57cec5SDimitry Andric if (UsesT) 44960b57cec5SDimitry Andric OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n"; 44970b57cec5SDimitry Andric OS << " return " << Test << ";\n"; 44980b57cec5SDimitry Andric OS << "}\n\n"; 44990b57cec5SDimitry Andric } 45000b57cec5SDimitry Andric 45015f757f3fSDimitry Andric static void 45025f757f3fSDimitry Andric GenerateSpellingTargetRequirements(const Record &Attr, 45035f757f3fSDimitry Andric const std::vector<Record *> &TargetSpellings, 45045f757f3fSDimitry Andric raw_ostream &OS) { 45055f757f3fSDimitry Andric // If there are no target specific spellings, use the default target handler. 45065f757f3fSDimitry Andric if (TargetSpellings.empty()) 45075f757f3fSDimitry Andric return; 45085f757f3fSDimitry Andric 45095f757f3fSDimitry Andric std::string Test; 45105f757f3fSDimitry Andric bool UsesT = false; 45115f757f3fSDimitry Andric const std::vector<FlattenedSpelling> SpellingList = 45125f757f3fSDimitry Andric GetFlattenedSpellings(Attr); 45135f757f3fSDimitry Andric for (unsigned TargetIndex = 0; TargetIndex < TargetSpellings.size(); 45145f757f3fSDimitry Andric ++TargetIndex) { 45155f757f3fSDimitry Andric const auto &TargetSpelling = TargetSpellings[TargetIndex]; 45165f757f3fSDimitry Andric std::vector<FlattenedSpelling> Spellings = 45175f757f3fSDimitry Andric GetFlattenedSpellings(*TargetSpelling); 45185f757f3fSDimitry Andric 45195f757f3fSDimitry Andric Test += "((SpellingListIndex == "; 45205f757f3fSDimitry Andric for (unsigned Index = 0; Index < Spellings.size(); ++Index) { 45215f757f3fSDimitry Andric Test += 45225f757f3fSDimitry Andric llvm::itostr(getSpellingListIndex(SpellingList, Spellings[Index])); 45235f757f3fSDimitry Andric if (Index != Spellings.size() - 1) 45245f757f3fSDimitry Andric Test += " ||\n SpellingListIndex == "; 45255f757f3fSDimitry Andric else 45265f757f3fSDimitry Andric Test += ") && "; 45275f757f3fSDimitry Andric } 45285f757f3fSDimitry Andric 45295f757f3fSDimitry Andric const Record *Target = TargetSpelling->getValueAsDef("Target"); 45305f757f3fSDimitry Andric std::vector<StringRef> Arches = Target->getValueAsListOfStrings("Arches"); 45315f757f3fSDimitry Andric std::string FnName = "isTargetSpelling"; 45325f757f3fSDimitry Andric UsesT |= GenerateTargetSpecificAttrChecks(Target, Arches, Test, &FnName); 45335f757f3fSDimitry Andric Test += ")"; 45345f757f3fSDimitry Andric if (TargetIndex != TargetSpellings.size() - 1) 45355f757f3fSDimitry Andric Test += " || "; 45365f757f3fSDimitry Andric } 45375f757f3fSDimitry Andric 45385f757f3fSDimitry Andric OS << "bool spellingExistsInTarget(const TargetInfo &Target,\n"; 45395f757f3fSDimitry Andric OS << " const unsigned SpellingListIndex) const " 45405f757f3fSDimitry Andric "override {\n"; 45415f757f3fSDimitry Andric if (UsesT) 45425f757f3fSDimitry Andric OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n"; 45435f757f3fSDimitry Andric OS << " return " << Test << ";\n", OS << "}\n\n"; 45445f757f3fSDimitry Andric } 45455f757f3fSDimitry Andric 45465ffd83dbSDimitry Andric static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr, 45470b57cec5SDimitry Andric raw_ostream &OS) { 45480b57cec5SDimitry Andric // If the attribute does not have a semantic form, we can bail out early. 45490b57cec5SDimitry Andric if (!Attr.getValueAsBit("ASTNode")) 45505ffd83dbSDimitry Andric return; 45510b57cec5SDimitry Andric 45520b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); 45530b57cec5SDimitry Andric 45540b57cec5SDimitry Andric // If there are zero or one spellings, or all of the spellings share the same 45550b57cec5SDimitry Andric // name, we can also bail out early. 45560b57cec5SDimitry Andric if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings)) 45575ffd83dbSDimitry Andric return; 45580b57cec5SDimitry Andric 45590b57cec5SDimitry Andric // Generate the enumeration we will use for the mapping. 45600b57cec5SDimitry Andric SemanticSpellingMap SemanticToSyntacticMap; 45610b57cec5SDimitry Andric std::string Enum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); 45620b57cec5SDimitry Andric std::string Name = Attr.getName().str() + "AttrSpellingMap"; 45630b57cec5SDimitry Andric 45645ffd83dbSDimitry Andric OS << "unsigned spellingIndexToSemanticSpelling("; 45655ffd83dbSDimitry Andric OS << "const ParsedAttr &Attr) const override {\n"; 45660b57cec5SDimitry Andric OS << Enum; 45670b57cec5SDimitry Andric OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; 45680b57cec5SDimitry Andric WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS); 45690b57cec5SDimitry Andric OS << "}\n\n"; 45705ffd83dbSDimitry Andric } 45710b57cec5SDimitry Andric 45725ffd83dbSDimitry Andric static void GenerateHandleDeclAttribute(const Record &Attr, raw_ostream &OS) { 45735ffd83dbSDimitry Andric // Only generate if Attr can be handled simply. 45745ffd83dbSDimitry Andric if (!Attr.getValueAsBit("SimpleHandler")) 45755ffd83dbSDimitry Andric return; 45765ffd83dbSDimitry Andric 45775ffd83dbSDimitry Andric // Generate a function which just converts from ParsedAttr to the Attr type. 45785ffd83dbSDimitry Andric OS << "AttrHandling handleDeclAttribute(Sema &S, Decl *D,"; 45795ffd83dbSDimitry Andric OS << "const ParsedAttr &Attr) const override {\n"; 45805ffd83dbSDimitry Andric OS << " D->addAttr(::new (S.Context) " << Attr.getName(); 45815ffd83dbSDimitry Andric OS << "Attr(S.Context, Attr));\n"; 45825ffd83dbSDimitry Andric OS << " return AttributeApplied;\n"; 45835ffd83dbSDimitry Andric OS << "}\n\n"; 45840b57cec5SDimitry Andric } 45850b57cec5SDimitry Andric 458681ad6265SDimitry Andric static bool isParamExpr(const Record *Arg) { 458781ad6265SDimitry Andric return !Arg->getSuperClasses().empty() && 458881ad6265SDimitry Andric llvm::StringSwitch<bool>( 458981ad6265SDimitry Andric Arg->getSuperClasses().back().first->getName()) 459081ad6265SDimitry Andric .Case("ExprArgument", true) 459181ad6265SDimitry Andric .Case("VariadicExprArgument", true) 459281ad6265SDimitry Andric .Default(false); 459381ad6265SDimitry Andric } 459481ad6265SDimitry Andric 459581ad6265SDimitry Andric void GenerateIsParamExpr(const Record &Attr, raw_ostream &OS) { 459681ad6265SDimitry Andric OS << "bool isParamExpr(size_t N) const override {\n"; 459781ad6265SDimitry Andric OS << " return "; 459881ad6265SDimitry Andric auto Args = Attr.getValueAsListOfDefs("Args"); 459981ad6265SDimitry Andric for (size_t I = 0; I < Args.size(); ++I) 460081ad6265SDimitry Andric if (isParamExpr(Args[I])) 460181ad6265SDimitry Andric OS << "(N == " << I << ") || "; 460281ad6265SDimitry Andric OS << "false;\n"; 460381ad6265SDimitry Andric OS << "}\n\n"; 460481ad6265SDimitry Andric } 460581ad6265SDimitry Andric 460681ad6265SDimitry Andric void GenerateHandleAttrWithDelayedArgs(RecordKeeper &Records, raw_ostream &OS) { 460781ad6265SDimitry Andric OS << "static void handleAttrWithDelayedArgs(Sema &S, Decl *D, "; 460881ad6265SDimitry Andric OS << "const ParsedAttr &Attr) {\n"; 460981ad6265SDimitry Andric OS << " SmallVector<Expr *, 4> ArgExprs;\n"; 461081ad6265SDimitry Andric OS << " ArgExprs.reserve(Attr.getNumArgs());\n"; 461181ad6265SDimitry Andric OS << " for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {\n"; 461281ad6265SDimitry Andric OS << " assert(!Attr.isArgIdent(I));\n"; 461381ad6265SDimitry Andric OS << " ArgExprs.push_back(Attr.getArgAsExpr(I));\n"; 461481ad6265SDimitry Andric OS << " }\n"; 461581ad6265SDimitry Andric OS << " clang::Attr *CreatedAttr = nullptr;\n"; 461681ad6265SDimitry Andric OS << " switch (Attr.getKind()) {\n"; 461781ad6265SDimitry Andric OS << " default:\n"; 461881ad6265SDimitry Andric OS << " llvm_unreachable(\"Attribute cannot hold delayed arguments.\");\n"; 461981ad6265SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records); 462081ad6265SDimitry Andric for (const auto &I : Attrs) { 462181ad6265SDimitry Andric const Record &R = *I.second; 462281ad6265SDimitry Andric if (!R.getValueAsBit("AcceptsExprPack")) 462381ad6265SDimitry Andric continue; 462481ad6265SDimitry Andric OS << " case ParsedAttr::AT_" << I.first << ": {\n"; 462581ad6265SDimitry Andric OS << " CreatedAttr = " << R.getName() << "Attr::CreateWithDelayedArgs"; 462681ad6265SDimitry Andric OS << "(S.Context, ArgExprs.data(), ArgExprs.size(), Attr);\n"; 462781ad6265SDimitry Andric OS << " break;\n"; 462881ad6265SDimitry Andric OS << " }\n"; 462981ad6265SDimitry Andric } 463081ad6265SDimitry Andric OS << " }\n"; 463181ad6265SDimitry Andric OS << " D->addAttr(CreatedAttr);\n"; 463281ad6265SDimitry Andric OS << "}\n\n"; 463381ad6265SDimitry Andric } 463481ad6265SDimitry Andric 46350b57cec5SDimitry Andric static bool IsKnownToGCC(const Record &Attr) { 46360b57cec5SDimitry Andric // Look at the spellings for this subject; if there are any spellings which 46370b57cec5SDimitry Andric // claim to be known to GCC, the attribute is known to GCC. 46380b57cec5SDimitry Andric return llvm::any_of( 46390b57cec5SDimitry Andric GetFlattenedSpellings(Attr), 46400b57cec5SDimitry Andric [](const FlattenedSpelling &S) { return S.knownToGCC(); }); 46410b57cec5SDimitry Andric } 46420b57cec5SDimitry Andric 46430b57cec5SDimitry Andric /// Emits the parsed attribute helpers 46440b57cec5SDimitry Andric void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { 46455f757f3fSDimitry Andric emitSourceFileHeader("Parsed attribute helpers", OS, Records); 46460b57cec5SDimitry Andric 4647fe6060f1SDimitry Andric OS << "#if !defined(WANT_DECL_MERGE_LOGIC) && " 4648fe6060f1SDimitry Andric << "!defined(WANT_STMT_MERGE_LOGIC)\n"; 46490b57cec5SDimitry Andric PragmaClangAttributeSupport &PragmaAttributeSupport = 46500b57cec5SDimitry Andric getPragmaAttributeSupport(Records); 46510b57cec5SDimitry Andric 46520b57cec5SDimitry Andric // Get the list of parsed attributes, and accept the optional list of 46530b57cec5SDimitry Andric // duplicates due to the ParseKind. 46540b57cec5SDimitry Andric ParsedAttrMap Dupes; 46550b57cec5SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes); 46560b57cec5SDimitry Andric 46575ffd83dbSDimitry Andric // Generate all of the custom appertainsTo functions that the attributes 46585ffd83dbSDimitry Andric // will be using. 465906c3fb27SDimitry Andric for (const auto &I : Attrs) { 46605ffd83dbSDimitry Andric const Record &Attr = *I.second; 46615ffd83dbSDimitry Andric if (Attr.isValueUnset("Subjects")) 46625ffd83dbSDimitry Andric continue; 46635ffd83dbSDimitry Andric const Record *SubjectObj = Attr.getValueAsDef("Subjects"); 46645ffd83dbSDimitry Andric for (auto Subject : SubjectObj->getValueAsListOfDefs("Subjects")) 46655ffd83dbSDimitry Andric if (Subject->isSubClassOf("SubsetSubject")) 46665ffd83dbSDimitry Andric GenerateCustomAppertainsTo(*Subject, OS); 46675ffd83dbSDimitry Andric } 46680b57cec5SDimitry Andric 4669fe6060f1SDimitry Andric // This stream is used to collect all of the declaration attribute merging 4670fe6060f1SDimitry Andric // logic for performing mutual exclusion checks. This gets emitted at the 4671fe6060f1SDimitry Andric // end of the file in a helper function of its own. 4672fe6060f1SDimitry Andric std::string DeclMergeChecks, StmtMergeChecks; 4673fe6060f1SDimitry Andric raw_string_ostream MergeDeclOS(DeclMergeChecks), MergeStmtOS(StmtMergeChecks); 4674fe6060f1SDimitry Andric 46755ffd83dbSDimitry Andric // Generate a ParsedAttrInfo struct for each of the attributes. 46760b57cec5SDimitry Andric for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { 46770b57cec5SDimitry Andric // TODO: If the attribute's kind appears in the list of duplicates, that is 46780b57cec5SDimitry Andric // because it is a target-specific attribute that appears multiple times. 46790b57cec5SDimitry Andric // It would be beneficial to test whether the duplicates are "similar 46800b57cec5SDimitry Andric // enough" to each other to not cause problems. For instance, check that 46810b57cec5SDimitry Andric // the spellings are identical, and custom parsing rules match, etc. 46820b57cec5SDimitry Andric 46830b57cec5SDimitry Andric // We need to generate struct instances based off ParsedAttrInfo from 46840b57cec5SDimitry Andric // ParsedAttr.cpp. 46855ffd83dbSDimitry Andric const std::string &AttrName = I->first; 46865ffd83dbSDimitry Andric const Record &Attr = *I->second; 46875ffd83dbSDimitry Andric auto Spellings = GetFlattenedSpellings(Attr); 46885ffd83dbSDimitry Andric if (!Spellings.empty()) { 46895ffd83dbSDimitry Andric OS << "static constexpr ParsedAttrInfo::Spelling " << I->first 46905ffd83dbSDimitry Andric << "Spellings[] = {\n"; 46915ffd83dbSDimitry Andric for (const auto &S : Spellings) { 46925ffd83dbSDimitry Andric const std::string &RawSpelling = S.name(); 46935ffd83dbSDimitry Andric std::string Spelling; 46945ffd83dbSDimitry Andric if (!S.nameSpace().empty()) 46955ffd83dbSDimitry Andric Spelling += S.nameSpace() + "::"; 46965ffd83dbSDimitry Andric if (S.variety() == "GNU") 46975ffd83dbSDimitry Andric Spelling += NormalizeGNUAttrSpelling(RawSpelling); 46985ffd83dbSDimitry Andric else 46995ffd83dbSDimitry Andric Spelling += RawSpelling; 47005ffd83dbSDimitry Andric OS << " {AttributeCommonInfo::AS_" << S.variety(); 47015ffd83dbSDimitry Andric OS << ", \"" << Spelling << "\"},\n"; 47025ffd83dbSDimitry Andric } 47035ffd83dbSDimitry Andric OS << "};\n"; 47045ffd83dbSDimitry Andric } 4705349cc55cSDimitry Andric 4706349cc55cSDimitry Andric std::vector<std::string> ArgNames; 4707349cc55cSDimitry Andric for (const auto &Arg : Attr.getValueAsListOfDefs("Args")) { 4708349cc55cSDimitry Andric bool UnusedUnset; 4709349cc55cSDimitry Andric if (Arg->getValueAsBitOrUnset("Fake", UnusedUnset)) 4710349cc55cSDimitry Andric continue; 4711349cc55cSDimitry Andric ArgNames.push_back(Arg->getValueAsString("Name").str()); 4712349cc55cSDimitry Andric for (const auto &Class : Arg->getSuperClasses()) { 47135f757f3fSDimitry Andric if (Class.first->getName().starts_with("Variadic")) { 4714349cc55cSDimitry Andric ArgNames.back().append("..."); 4715349cc55cSDimitry Andric break; 4716349cc55cSDimitry Andric } 4717349cc55cSDimitry Andric } 4718349cc55cSDimitry Andric } 4719349cc55cSDimitry Andric if (!ArgNames.empty()) { 4720349cc55cSDimitry Andric OS << "static constexpr const char *" << I->first << "ArgNames[] = {\n"; 4721349cc55cSDimitry Andric for (const auto &N : ArgNames) 4722349cc55cSDimitry Andric OS << '"' << N << "\","; 4723349cc55cSDimitry Andric OS << "};\n"; 4724349cc55cSDimitry Andric } 4725349cc55cSDimitry Andric 47265ffd83dbSDimitry Andric OS << "struct ParsedAttrInfo" << I->first 47275ffd83dbSDimitry Andric << " final : public ParsedAttrInfo {\n"; 472881ad6265SDimitry Andric OS << " constexpr ParsedAttrInfo" << I->first << "() : ParsedAttrInfo(\n"; 472981ad6265SDimitry Andric OS << " /*AttrKind=*/ParsedAttr::AT_" << AttrName << ",\n"; 47305ffd83dbSDimitry Andric emitArgInfo(Attr, OS); 473181ad6265SDimitry Andric OS << " /*HasCustomParsing=*/"; 473281ad6265SDimitry Andric OS << Attr.getValueAsBit("HasCustomParsing") << ",\n"; 473381ad6265SDimitry Andric OS << " /*AcceptsExprPack=*/"; 473481ad6265SDimitry Andric OS << Attr.getValueAsBit("AcceptsExprPack") << ",\n"; 473581ad6265SDimitry Andric OS << " /*IsTargetSpecific=*/"; 473681ad6265SDimitry Andric OS << Attr.isSubClassOf("TargetSpecificAttr") << ",\n"; 473781ad6265SDimitry Andric OS << " /*IsType=*/"; 473881ad6265SDimitry Andric OS << (Attr.isSubClassOf("TypeAttr") || Attr.isSubClassOf("DeclOrTypeAttr")) 473981ad6265SDimitry Andric << ",\n"; 474081ad6265SDimitry Andric OS << " /*IsStmt=*/"; 4741e8d8bef9SDimitry Andric OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr")) 474281ad6265SDimitry Andric << ",\n"; 474381ad6265SDimitry Andric OS << " /*IsKnownToGCC=*/"; 474481ad6265SDimitry Andric OS << IsKnownToGCC(Attr) << ",\n"; 474581ad6265SDimitry Andric OS << " /*IsSupportedByPragmaAttribute=*/"; 474681ad6265SDimitry Andric OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ",\n"; 47475ffd83dbSDimitry Andric if (!Spellings.empty()) 474881ad6265SDimitry Andric OS << " /*Spellings=*/" << I->first << "Spellings,\n"; 474981ad6265SDimitry Andric else 475081ad6265SDimitry Andric OS << " /*Spellings=*/{},\n"; 4751349cc55cSDimitry Andric if (!ArgNames.empty()) 475281ad6265SDimitry Andric OS << " /*ArgNames=*/" << I->first << "ArgNames"; 475381ad6265SDimitry Andric else 475481ad6265SDimitry Andric OS << " /*ArgNames=*/{}"; 475581ad6265SDimitry Andric OS << ") {}\n"; 47565ffd83dbSDimitry Andric GenerateAppertainsTo(Attr, OS); 4757fe6060f1SDimitry Andric GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS); 47585ffd83dbSDimitry Andric GenerateLangOptRequirements(Attr, OS); 47595ffd83dbSDimitry Andric GenerateTargetRequirements(Attr, Dupes, OS); 47605f757f3fSDimitry Andric GenerateSpellingTargetRequirements( 47615f757f3fSDimitry Andric Attr, Attr.getValueAsListOfDefs("TargetSpecificSpellings"), OS); 47625ffd83dbSDimitry Andric GenerateSpellingIndexToSemanticSpelling(Attr, OS); 47635ffd83dbSDimitry Andric PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS); 47645ffd83dbSDimitry Andric GenerateHandleDeclAttribute(Attr, OS); 476581ad6265SDimitry Andric GenerateIsParamExpr(Attr, OS); 47665ffd83dbSDimitry Andric OS << "static const ParsedAttrInfo" << I->first << " Instance;\n"; 47675ffd83dbSDimitry Andric OS << "};\n"; 47685ffd83dbSDimitry Andric OS << "const ParsedAttrInfo" << I->first << " ParsedAttrInfo" << I->first 47695ffd83dbSDimitry Andric << "::Instance;\n"; 47700b57cec5SDimitry Andric } 47710b57cec5SDimitry Andric 47725ffd83dbSDimitry Andric OS << "static const ParsedAttrInfo *AttrInfoMap[] = {\n"; 47735ffd83dbSDimitry Andric for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { 47745ffd83dbSDimitry Andric OS << "&ParsedAttrInfo" << I->first << "::Instance,\n"; 47755ffd83dbSDimitry Andric } 47760b57cec5SDimitry Andric OS << "};\n\n"; 47770b57cec5SDimitry Andric 477881ad6265SDimitry Andric // Generate function for handling attributes with delayed arguments 477981ad6265SDimitry Andric GenerateHandleAttrWithDelayedArgs(Records, OS); 478081ad6265SDimitry Andric 47810b57cec5SDimitry Andric // Generate the attribute match rules. 47820b57cec5SDimitry Andric emitAttributeMatchRules(PragmaAttributeSupport, OS); 4783fe6060f1SDimitry Andric 4784fe6060f1SDimitry Andric OS << "#elif defined(WANT_DECL_MERGE_LOGIC)\n\n"; 4785fe6060f1SDimitry Andric 4786fe6060f1SDimitry Andric // Write out the declaration merging check logic. 4787fe6060f1SDimitry Andric OS << "static bool DiagnoseMutualExclusions(Sema &S, const NamedDecl *D, " 4788fe6060f1SDimitry Andric << "const Attr *A) {\n"; 4789*0fca6ea1SDimitry Andric OS << DeclMergeChecks; 4790fe6060f1SDimitry Andric OS << " return true;\n"; 4791fe6060f1SDimitry Andric OS << "}\n\n"; 4792fe6060f1SDimitry Andric 4793fe6060f1SDimitry Andric OS << "#elif defined(WANT_STMT_MERGE_LOGIC)\n\n"; 4794fe6060f1SDimitry Andric 4795fe6060f1SDimitry Andric // Write out the statement merging check logic. 4796fe6060f1SDimitry Andric OS << "static bool DiagnoseMutualExclusions(Sema &S, " 4797fe6060f1SDimitry Andric << "const SmallVectorImpl<const Attr *> &C) {\n"; 4798fe6060f1SDimitry Andric OS << " for (const Attr *A : C) {\n"; 4799*0fca6ea1SDimitry Andric OS << StmtMergeChecks; 4800fe6060f1SDimitry Andric OS << " }\n"; 4801fe6060f1SDimitry Andric OS << " return true;\n"; 4802fe6060f1SDimitry Andric OS << "}\n\n"; 4803fe6060f1SDimitry Andric 4804fe6060f1SDimitry Andric OS << "#endif\n"; 48050b57cec5SDimitry Andric } 48060b57cec5SDimitry Andric 48070b57cec5SDimitry Andric // Emits the kind list of parsed attributes 48080b57cec5SDimitry Andric void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { 48095f757f3fSDimitry Andric emitSourceFileHeader("Attribute name matcher", OS, Records); 48100b57cec5SDimitry Andric 48110b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 48120b57cec5SDimitry Andric std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11, 4813*0fca6ea1SDimitry Andric Keywords, Pragma, C23, HLSLAnnotation; 48140b57cec5SDimitry Andric std::set<std::string> Seen; 48150b57cec5SDimitry Andric for (const auto *A : Attrs) { 48160b57cec5SDimitry Andric const Record &Attr = *A; 48170b57cec5SDimitry Andric 48180b57cec5SDimitry Andric bool SemaHandler = Attr.getValueAsBit("SemaHandler"); 48190b57cec5SDimitry Andric bool Ignored = Attr.getValueAsBit("Ignored"); 48200b57cec5SDimitry Andric if (SemaHandler || Ignored) { 48210b57cec5SDimitry Andric // Attribute spellings can be shared between target-specific attributes, 48220b57cec5SDimitry Andric // and can be shared between syntaxes for the same attribute. For 48230b57cec5SDimitry Andric // instance, an attribute can be spelled GNU<"interrupt"> for an ARM- 48240b57cec5SDimitry Andric // specific attribute, or MSP430-specific attribute. Additionally, an 48250b57cec5SDimitry Andric // attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport"> 48260b57cec5SDimitry Andric // for the same semantic attribute. Ultimately, we need to map each of 4827a7dea167SDimitry Andric // these to a single AttributeCommonInfo::Kind value, but the 4828a7dea167SDimitry Andric // StringMatcher class cannot handle duplicate match strings. So we 4829a7dea167SDimitry Andric // generate a list of string to match based on the syntax, and emit 4830a7dea167SDimitry Andric // multiple string matchers depending on the syntax used. 48310b57cec5SDimitry Andric std::string AttrName; 48320b57cec5SDimitry Andric if (Attr.isSubClassOf("TargetSpecificAttr") && 48330b57cec5SDimitry Andric !Attr.isValueUnset("ParseKind")) { 48345ffd83dbSDimitry Andric AttrName = std::string(Attr.getValueAsString("ParseKind")); 483581ad6265SDimitry Andric if (!Seen.insert(AttrName).second) 48360b57cec5SDimitry Andric continue; 48370b57cec5SDimitry Andric } else 48380b57cec5SDimitry Andric AttrName = NormalizeAttrName(StringRef(Attr.getName())).str(); 48390b57cec5SDimitry Andric 48400b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); 48410b57cec5SDimitry Andric for (const auto &S : Spellings) { 48420b57cec5SDimitry Andric const std::string &RawSpelling = S.name(); 48430b57cec5SDimitry Andric std::vector<StringMatcher::StringPair> *Matches = nullptr; 48440b57cec5SDimitry Andric std::string Spelling; 48450b57cec5SDimitry Andric const std::string &Variety = S.variety(); 48460b57cec5SDimitry Andric if (Variety == "CXX11") { 48470b57cec5SDimitry Andric Matches = &CXX11; 48485ffd83dbSDimitry Andric if (!S.nameSpace().empty()) 48495ffd83dbSDimitry Andric Spelling += S.nameSpace() + "::"; 48505f757f3fSDimitry Andric } else if (Variety == "C23") { 48515f757f3fSDimitry Andric Matches = &C23; 48525ffd83dbSDimitry Andric if (!S.nameSpace().empty()) 48535ffd83dbSDimitry Andric Spelling += S.nameSpace() + "::"; 48540b57cec5SDimitry Andric } else if (Variety == "GNU") 48550b57cec5SDimitry Andric Matches = &GNU; 48560b57cec5SDimitry Andric else if (Variety == "Declspec") 48570b57cec5SDimitry Andric Matches = &Declspec; 48580b57cec5SDimitry Andric else if (Variety == "Microsoft") 48590b57cec5SDimitry Andric Matches = &Microsoft; 48600b57cec5SDimitry Andric else if (Variety == "Keyword") 48610b57cec5SDimitry Andric Matches = &Keywords; 48620b57cec5SDimitry Andric else if (Variety == "Pragma") 48630b57cec5SDimitry Andric Matches = &Pragma; 4864*0fca6ea1SDimitry Andric else if (Variety == "HLSLAnnotation") 4865*0fca6ea1SDimitry Andric Matches = &HLSLAnnotation; 48660b57cec5SDimitry Andric 48670b57cec5SDimitry Andric assert(Matches && "Unsupported spelling variety found"); 48680b57cec5SDimitry Andric 48690b57cec5SDimitry Andric if (Variety == "GNU") 48700b57cec5SDimitry Andric Spelling += NormalizeGNUAttrSpelling(RawSpelling); 48710b57cec5SDimitry Andric else 48720b57cec5SDimitry Andric Spelling += RawSpelling; 48730b57cec5SDimitry Andric 48740b57cec5SDimitry Andric if (SemaHandler) 48750b57cec5SDimitry Andric Matches->push_back(StringMatcher::StringPair( 4876a7dea167SDimitry Andric Spelling, "return AttributeCommonInfo::AT_" + AttrName + ";")); 48770b57cec5SDimitry Andric else 48780b57cec5SDimitry Andric Matches->push_back(StringMatcher::StringPair( 4879a7dea167SDimitry Andric Spelling, "return AttributeCommonInfo::IgnoredAttribute;")); 48800b57cec5SDimitry Andric } 48810b57cec5SDimitry Andric } 48820b57cec5SDimitry Andric } 48830b57cec5SDimitry Andric 4884a7dea167SDimitry Andric OS << "static AttributeCommonInfo::Kind getAttrKind(StringRef Name, "; 4885a7dea167SDimitry Andric OS << "AttributeCommonInfo::Syntax Syntax) {\n"; 4886a7dea167SDimitry Andric OS << " if (AttributeCommonInfo::AS_GNU == Syntax) {\n"; 48870b57cec5SDimitry Andric StringMatcher("Name", GNU, OS).Emit(); 4888a7dea167SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_Declspec == Syntax) {\n"; 48890b57cec5SDimitry Andric StringMatcher("Name", Declspec, OS).Emit(); 4890a7dea167SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_Microsoft == Syntax) {\n"; 48910b57cec5SDimitry Andric StringMatcher("Name", Microsoft, OS).Emit(); 4892a7dea167SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_CXX11 == Syntax) {\n"; 48930b57cec5SDimitry Andric StringMatcher("Name", CXX11, OS).Emit(); 48945f757f3fSDimitry Andric OS << " } else if (AttributeCommonInfo::AS_C23 == Syntax) {\n"; 48955f757f3fSDimitry Andric StringMatcher("Name", C23, OS).Emit(); 4896a7dea167SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || "; 4897a7dea167SDimitry Andric OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n"; 48980b57cec5SDimitry Andric StringMatcher("Name", Keywords, OS).Emit(); 4899a7dea167SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n"; 49000b57cec5SDimitry Andric StringMatcher("Name", Pragma, OS).Emit(); 4901*0fca6ea1SDimitry Andric OS << " } else if (AttributeCommonInfo::AS_HLSLAnnotation == Syntax) {\n"; 4902*0fca6ea1SDimitry Andric StringMatcher("Name", HLSLAnnotation, OS).Emit(); 49030b57cec5SDimitry Andric OS << " }\n"; 4904a7dea167SDimitry Andric OS << " return AttributeCommonInfo::UnknownAttribute;\n" 49050b57cec5SDimitry Andric << "}\n"; 49060b57cec5SDimitry Andric } 49070b57cec5SDimitry Andric 49080b57cec5SDimitry Andric // Emits the code to dump an attribute. 49090b57cec5SDimitry Andric void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) { 49105f757f3fSDimitry Andric emitSourceFileHeader("Attribute text node dumper", OS, Records); 49110b57cec5SDimitry Andric 49120b57cec5SDimitry Andric std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; 49130b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 49140b57cec5SDimitry Andric const Record &R = *Attr; 49150b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 49160b57cec5SDimitry Andric continue; 49170b57cec5SDimitry Andric 49180b57cec5SDimitry Andric // If the attribute has a semantically-meaningful name (which is determined 49190b57cec5SDimitry Andric // by whether there is a Spelling enumeration for it), then write out the 49200b57cec5SDimitry Andric // spelling used for the attribute. 49210b57cec5SDimitry Andric 49220b57cec5SDimitry Andric std::string FunctionContent; 49230b57cec5SDimitry Andric llvm::raw_string_ostream SS(FunctionContent); 49240b57cec5SDimitry Andric 49250b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R); 49260b57cec5SDimitry Andric if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings)) 49270b57cec5SDimitry Andric SS << " OS << \" \" << A->getSpelling();\n"; 49280b57cec5SDimitry Andric 49290b57cec5SDimitry Andric Args = R.getValueAsListOfDefs("Args"); 49300b57cec5SDimitry Andric for (const auto *Arg : Args) 49310b57cec5SDimitry Andric createArgument(*Arg, R.getName())->writeDump(SS); 49320b57cec5SDimitry Andric 493381ad6265SDimitry Andric if (Attr->getValueAsBit("AcceptsExprPack")) 493481ad6265SDimitry Andric VariadicExprArgument("DelayedArgs", R.getName()).writeDump(OS); 493581ad6265SDimitry Andric 49360b57cec5SDimitry Andric if (SS.tell()) { 49370b57cec5SDimitry Andric OS << " void Visit" << R.getName() << "Attr(const " << R.getName() 49380b57cec5SDimitry Andric << "Attr *A) {\n"; 49390b57cec5SDimitry Andric if (!Args.empty()) 49400b57cec5SDimitry Andric OS << " const auto *SA = cast<" << R.getName() 49410b57cec5SDimitry Andric << "Attr>(A); (void)SA;\n"; 4942*0fca6ea1SDimitry Andric OS << FunctionContent; 49430b57cec5SDimitry Andric OS << " }\n"; 49440b57cec5SDimitry Andric } 49450b57cec5SDimitry Andric } 49460b57cec5SDimitry Andric } 49470b57cec5SDimitry Andric 49480b57cec5SDimitry Andric void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) { 49495f757f3fSDimitry Andric emitSourceFileHeader("Attribute text node traverser", OS, Records); 49500b57cec5SDimitry Andric 49510b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; 49520b57cec5SDimitry Andric for (const auto *Attr : Attrs) { 49530b57cec5SDimitry Andric const Record &R = *Attr; 49540b57cec5SDimitry Andric if (!R.getValueAsBit("ASTNode")) 49550b57cec5SDimitry Andric continue; 49560b57cec5SDimitry Andric 49570b57cec5SDimitry Andric std::string FunctionContent; 49580b57cec5SDimitry Andric llvm::raw_string_ostream SS(FunctionContent); 49590b57cec5SDimitry Andric 49600b57cec5SDimitry Andric Args = R.getValueAsListOfDefs("Args"); 49610b57cec5SDimitry Andric for (const auto *Arg : Args) 49620b57cec5SDimitry Andric createArgument(*Arg, R.getName())->writeDumpChildren(SS); 496381ad6265SDimitry Andric if (Attr->getValueAsBit("AcceptsExprPack")) 496481ad6265SDimitry Andric VariadicExprArgument("DelayedArgs", R.getName()).writeDumpChildren(SS); 49650b57cec5SDimitry Andric if (SS.tell()) { 49660b57cec5SDimitry Andric OS << " void Visit" << R.getName() << "Attr(const " << R.getName() 49670b57cec5SDimitry Andric << "Attr *A) {\n"; 49680b57cec5SDimitry Andric if (!Args.empty()) 49690b57cec5SDimitry Andric OS << " const auto *SA = cast<" << R.getName() 49700b57cec5SDimitry Andric << "Attr>(A); (void)SA;\n"; 4971*0fca6ea1SDimitry Andric OS << FunctionContent; 49720b57cec5SDimitry Andric OS << " }\n"; 49730b57cec5SDimitry Andric } 49740b57cec5SDimitry Andric } 49750b57cec5SDimitry Andric } 49760b57cec5SDimitry Andric 49775f757f3fSDimitry Andric void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS) { 49785f757f3fSDimitry Andric emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS, Records); 49790b57cec5SDimitry Andric emitClangAttrArgContextList(Records, OS); 49800b57cec5SDimitry Andric emitClangAttrIdentifierArgList(Records, OS); 49815f757f3fSDimitry Andric emitClangAttrUnevaluatedStringLiteralList(Records, OS); 49820b57cec5SDimitry Andric emitClangAttrVariadicIdentifierArgList(Records, OS); 49830b57cec5SDimitry Andric emitClangAttrThisIsaIdentifierArgList(Records, OS); 498481ad6265SDimitry Andric emitClangAttrAcceptsExprPack(Records, OS); 49850b57cec5SDimitry Andric emitClangAttrTypeArgList(Records, OS); 49860b57cec5SDimitry Andric emitClangAttrLateParsedList(Records, OS); 4987*0fca6ea1SDimitry Andric emitClangAttrLateParsedExperimentalList(Records, OS); 4988*0fca6ea1SDimitry Andric emitClangAttrStrictIdentifierArgAtIndexList(Records, OS); 49890b57cec5SDimitry Andric } 49900b57cec5SDimitry Andric 49910b57cec5SDimitry Andric void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, 49920b57cec5SDimitry Andric raw_ostream &OS) { 49930b57cec5SDimitry Andric getPragmaAttributeSupport(Records).generateParsingHelpers(OS); 49940b57cec5SDimitry Andric } 49950b57cec5SDimitry Andric 4996349cc55cSDimitry Andric void EmitClangAttrDocTable(RecordKeeper &Records, raw_ostream &OS) { 49975f757f3fSDimitry Andric emitSourceFileHeader("Clang attribute documentation", OS, Records); 4998349cc55cSDimitry Andric 4999349cc55cSDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 5000349cc55cSDimitry Andric for (const auto *A : Attrs) { 5001349cc55cSDimitry Andric if (!A->getValueAsBit("ASTNode")) 5002349cc55cSDimitry Andric continue; 5003349cc55cSDimitry Andric std::vector<Record *> Docs = A->getValueAsListOfDefs("Documentation"); 5004349cc55cSDimitry Andric assert(!Docs.empty()); 5005349cc55cSDimitry Andric // Only look at the first documentation if there are several. 5006349cc55cSDimitry Andric // (Currently there's only one such attr, revisit if this becomes common). 5007349cc55cSDimitry Andric StringRef Text = 500881ad6265SDimitry Andric Docs.front()->getValueAsOptionalString("Content").value_or(""); 5009349cc55cSDimitry Andric OS << "\nstatic const char AttrDoc_" << A->getName() << "[] = " 5010349cc55cSDimitry Andric << "R\"reST(" << Text.trim() << ")reST\";\n"; 5011349cc55cSDimitry Andric } 5012349cc55cSDimitry Andric } 5013349cc55cSDimitry Andric 501481ad6265SDimitry Andric enum class SpellingKind : size_t { 50150b57cec5SDimitry Andric GNU, 50160b57cec5SDimitry Andric CXX11, 50175f757f3fSDimitry Andric C23, 50180b57cec5SDimitry Andric Declspec, 50190b57cec5SDimitry Andric Microsoft, 50200b57cec5SDimitry Andric Keyword, 50210b57cec5SDimitry Andric Pragma, 5022*0fca6ea1SDimitry Andric HLSLAnnotation, 502381ad6265SDimitry Andric NumSpellingKinds 50240b57cec5SDimitry Andric }; 502581ad6265SDimitry Andric static const size_t NumSpellingKinds = (size_t)SpellingKind::NumSpellingKinds; 50260b57cec5SDimitry Andric 50270b57cec5SDimitry Andric class SpellingList { 50280b57cec5SDimitry Andric std::vector<std::string> Spellings[NumSpellingKinds]; 50290b57cec5SDimitry Andric 50300b57cec5SDimitry Andric public: 50310b57cec5SDimitry Andric ArrayRef<std::string> operator[](SpellingKind K) const { 50320b57cec5SDimitry Andric return Spellings[(size_t)K]; 50330b57cec5SDimitry Andric } 50340b57cec5SDimitry Andric 50350b57cec5SDimitry Andric void add(const Record &Attr, FlattenedSpelling Spelling) { 5036*0fca6ea1SDimitry Andric SpellingKind Kind = 5037*0fca6ea1SDimitry Andric StringSwitch<SpellingKind>(Spelling.variety()) 50380b57cec5SDimitry Andric .Case("GNU", SpellingKind::GNU) 50390b57cec5SDimitry Andric .Case("CXX11", SpellingKind::CXX11) 50405f757f3fSDimitry Andric .Case("C23", SpellingKind::C23) 50410b57cec5SDimitry Andric .Case("Declspec", SpellingKind::Declspec) 50420b57cec5SDimitry Andric .Case("Microsoft", SpellingKind::Microsoft) 50430b57cec5SDimitry Andric .Case("Keyword", SpellingKind::Keyword) 504481ad6265SDimitry Andric .Case("Pragma", SpellingKind::Pragma) 5045*0fca6ea1SDimitry Andric .Case("HLSLAnnotation", SpellingKind::HLSLAnnotation); 50460b57cec5SDimitry Andric std::string Name; 50470b57cec5SDimitry Andric if (!Spelling.nameSpace().empty()) { 50480b57cec5SDimitry Andric switch (Kind) { 50490b57cec5SDimitry Andric case SpellingKind::CXX11: 50505f757f3fSDimitry Andric case SpellingKind::C23: 50510b57cec5SDimitry Andric Name = Spelling.nameSpace() + "::"; 50520b57cec5SDimitry Andric break; 50530b57cec5SDimitry Andric case SpellingKind::Pragma: 50540b57cec5SDimitry Andric Name = Spelling.nameSpace() + " "; 50550b57cec5SDimitry Andric break; 50560b57cec5SDimitry Andric default: 50570b57cec5SDimitry Andric PrintFatalError(Attr.getLoc(), "Unexpected namespace in spelling"); 50580b57cec5SDimitry Andric } 50590b57cec5SDimitry Andric } 50600b57cec5SDimitry Andric Name += Spelling.name(); 50610b57cec5SDimitry Andric 50620b57cec5SDimitry Andric Spellings[(size_t)Kind].push_back(Name); 50630b57cec5SDimitry Andric } 50640b57cec5SDimitry Andric }; 50650b57cec5SDimitry Andric 50660b57cec5SDimitry Andric class DocumentationData { 50670b57cec5SDimitry Andric public: 50680b57cec5SDimitry Andric const Record *Documentation; 50690b57cec5SDimitry Andric const Record *Attribute; 50700b57cec5SDimitry Andric std::string Heading; 50710b57cec5SDimitry Andric SpellingList SupportedSpellings; 50720b57cec5SDimitry Andric 50730b57cec5SDimitry Andric DocumentationData(const Record &Documentation, const Record &Attribute, 50740b57cec5SDimitry Andric std::pair<std::string, SpellingList> HeadingAndSpellings) 50750b57cec5SDimitry Andric : Documentation(&Documentation), Attribute(&Attribute), 50760b57cec5SDimitry Andric Heading(std::move(HeadingAndSpellings.first)), 50770b57cec5SDimitry Andric SupportedSpellings(std::move(HeadingAndSpellings.second)) {} 50780b57cec5SDimitry Andric }; 50790b57cec5SDimitry Andric 50800b57cec5SDimitry Andric static void WriteCategoryHeader(const Record *DocCategory, 50810b57cec5SDimitry Andric raw_ostream &OS) { 50820b57cec5SDimitry Andric const StringRef Name = DocCategory->getValueAsString("Name"); 50830b57cec5SDimitry Andric OS << Name << "\n" << std::string(Name.size(), '=') << "\n"; 50840b57cec5SDimitry Andric 50850b57cec5SDimitry Andric // If there is content, print that as well. 50860b57cec5SDimitry Andric const StringRef ContentStr = DocCategory->getValueAsString("Content"); 50870b57cec5SDimitry Andric // Trim leading and trailing newlines and spaces. 50880b57cec5SDimitry Andric OS << ContentStr.trim(); 50890b57cec5SDimitry Andric 50900b57cec5SDimitry Andric OS << "\n\n"; 50910b57cec5SDimitry Andric } 50920b57cec5SDimitry Andric 50930b57cec5SDimitry Andric static std::pair<std::string, SpellingList> 50940b57cec5SDimitry Andric GetAttributeHeadingAndSpellings(const Record &Documentation, 509581ad6265SDimitry Andric const Record &Attribute, 509681ad6265SDimitry Andric StringRef Cat) { 50970b57cec5SDimitry Andric // FIXME: there is no way to have a per-spelling category for the attribute 50980b57cec5SDimitry Andric // documentation. This may not be a limiting factor since the spellings 50990b57cec5SDimitry Andric // should generally be consistently applied across the category. 51000b57cec5SDimitry Andric 51010b57cec5SDimitry Andric std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); 51020b57cec5SDimitry Andric if (Spellings.empty()) 51030b57cec5SDimitry Andric PrintFatalError(Attribute.getLoc(), 51040b57cec5SDimitry Andric "Attribute has no supported spellings; cannot be " 51050b57cec5SDimitry Andric "documented"); 51060b57cec5SDimitry Andric 51070b57cec5SDimitry Andric // Determine the heading to be used for this attribute. 51085ffd83dbSDimitry Andric std::string Heading = std::string(Documentation.getValueAsString("Heading")); 51090b57cec5SDimitry Andric if (Heading.empty()) { 51100b57cec5SDimitry Andric // If there's only one spelling, we can simply use that. 51110b57cec5SDimitry Andric if (Spellings.size() == 1) 51120b57cec5SDimitry Andric Heading = Spellings.begin()->name(); 51130b57cec5SDimitry Andric else { 51140b57cec5SDimitry Andric std::set<std::string> Uniques; 51150b57cec5SDimitry Andric for (auto I = Spellings.begin(), E = Spellings.end(); 511681ad6265SDimitry Andric I != E; ++I) { 51175ffd83dbSDimitry Andric std::string Spelling = 51185ffd83dbSDimitry Andric std::string(NormalizeNameForSpellingComparison(I->name())); 51190b57cec5SDimitry Andric Uniques.insert(Spelling); 51200b57cec5SDimitry Andric } 51210b57cec5SDimitry Andric // If the semantic map has only one spelling, that is sufficient for our 51220b57cec5SDimitry Andric // needs. 51230b57cec5SDimitry Andric if (Uniques.size() == 1) 51240b57cec5SDimitry Andric Heading = *Uniques.begin(); 512581ad6265SDimitry Andric // If it's in the undocumented category, just construct a header by 512681ad6265SDimitry Andric // concatenating all the spellings. Might not be great, but better than 512781ad6265SDimitry Andric // nothing. 512881ad6265SDimitry Andric else if (Cat == "Undocumented") 512981ad6265SDimitry Andric Heading = llvm::join(Uniques.begin(), Uniques.end(), ", "); 51300b57cec5SDimitry Andric } 51310b57cec5SDimitry Andric } 51320b57cec5SDimitry Andric 51330b57cec5SDimitry Andric // If the heading is still empty, it is an error. 51340b57cec5SDimitry Andric if (Heading.empty()) 51350b57cec5SDimitry Andric PrintFatalError(Attribute.getLoc(), 51360b57cec5SDimitry Andric "This attribute requires a heading to be specified"); 51370b57cec5SDimitry Andric 51380b57cec5SDimitry Andric SpellingList SupportedSpellings; 51390b57cec5SDimitry Andric for (const auto &I : Spellings) 51400b57cec5SDimitry Andric SupportedSpellings.add(Attribute, I); 51410b57cec5SDimitry Andric 51420b57cec5SDimitry Andric return std::make_pair(std::move(Heading), std::move(SupportedSpellings)); 51430b57cec5SDimitry Andric } 51440b57cec5SDimitry Andric 51450b57cec5SDimitry Andric static void WriteDocumentation(RecordKeeper &Records, 51460b57cec5SDimitry Andric const DocumentationData &Doc, raw_ostream &OS) { 51470b57cec5SDimitry Andric OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n"; 51480b57cec5SDimitry Andric 51490b57cec5SDimitry Andric // List what spelling syntaxes the attribute supports. 5150bdd1243dSDimitry Andric // Note: "#pragma clang attribute" is handled outside the spelling kinds loop 5151bdd1243dSDimitry Andric // so it must be last. 51520b57cec5SDimitry Andric OS << ".. csv-table:: Supported Syntaxes\n"; 51535f757f3fSDimitry Andric OS << " :header: \"GNU\", \"C++11\", \"C23\", \"``__declspec``\","; 5154*0fca6ea1SDimitry Andric OS << " \"Keyword\", \"``#pragma``\", \"HLSL Annotation\", \"``#pragma " 5155*0fca6ea1SDimitry Andric "clang "; 5156bdd1243dSDimitry Andric OS << "attribute``\"\n\n \""; 51570b57cec5SDimitry Andric for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) { 51580b57cec5SDimitry Andric SpellingKind K = (SpellingKind)Kind; 51590b57cec5SDimitry Andric // TODO: List Microsoft (IDL-style attribute) spellings once we fully 51600b57cec5SDimitry Andric // support them. 51610b57cec5SDimitry Andric if (K == SpellingKind::Microsoft) 51620b57cec5SDimitry Andric continue; 51630b57cec5SDimitry Andric 51640b57cec5SDimitry Andric bool PrintedAny = false; 51650b57cec5SDimitry Andric for (StringRef Spelling : Doc.SupportedSpellings[K]) { 51660b57cec5SDimitry Andric if (PrintedAny) 51670b57cec5SDimitry Andric OS << " |br| "; 51680b57cec5SDimitry Andric OS << "``" << Spelling << "``"; 51690b57cec5SDimitry Andric PrintedAny = true; 51700b57cec5SDimitry Andric } 51710b57cec5SDimitry Andric 51720b57cec5SDimitry Andric OS << "\",\""; 51730b57cec5SDimitry Andric } 51740b57cec5SDimitry Andric 51750b57cec5SDimitry Andric if (getPragmaAttributeSupport(Records).isAttributedSupported( 51760b57cec5SDimitry Andric *Doc.Attribute)) 51770b57cec5SDimitry Andric OS << "Yes"; 51780b57cec5SDimitry Andric OS << "\"\n\n"; 51790b57cec5SDimitry Andric 51800b57cec5SDimitry Andric // If the attribute is deprecated, print a message about it, and possibly 51810b57cec5SDimitry Andric // provide a replacement attribute. 51820b57cec5SDimitry Andric if (!Doc.Documentation->isValueUnset("Deprecated")) { 51830b57cec5SDimitry Andric OS << "This attribute has been deprecated, and may be removed in a future " 51840b57cec5SDimitry Andric << "version of Clang."; 51850b57cec5SDimitry Andric const Record &Deprecated = *Doc.Documentation->getValueAsDef("Deprecated"); 51860b57cec5SDimitry Andric const StringRef Replacement = Deprecated.getValueAsString("Replacement"); 51870b57cec5SDimitry Andric if (!Replacement.empty()) 51880b57cec5SDimitry Andric OS << " This attribute has been superseded by ``" << Replacement 51890b57cec5SDimitry Andric << "``."; 51900b57cec5SDimitry Andric OS << "\n\n"; 51910b57cec5SDimitry Andric } 51920b57cec5SDimitry Andric 51930b57cec5SDimitry Andric const StringRef ContentStr = Doc.Documentation->getValueAsString("Content"); 51940b57cec5SDimitry Andric // Trim leading and trailing newlines and spaces. 51950b57cec5SDimitry Andric OS << ContentStr.trim(); 51960b57cec5SDimitry Andric 51970b57cec5SDimitry Andric OS << "\n\n\n"; 51980b57cec5SDimitry Andric } 51990b57cec5SDimitry Andric 52000b57cec5SDimitry Andric void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { 52010b57cec5SDimitry Andric // Get the documentation introduction paragraph. 52020b57cec5SDimitry Andric const Record *Documentation = Records.getDef("GlobalDocumentation"); 52030b57cec5SDimitry Andric if (!Documentation) { 52040b57cec5SDimitry Andric PrintFatalError("The Documentation top-level definition is missing, " 52050b57cec5SDimitry Andric "no documentation will be generated."); 52060b57cec5SDimitry Andric return; 52070b57cec5SDimitry Andric } 52080b57cec5SDimitry Andric 52090b57cec5SDimitry Andric OS << Documentation->getValueAsString("Intro") << "\n"; 52100b57cec5SDimitry Andric 52110b57cec5SDimitry Andric // Gather the Documentation lists from each of the attributes, based on the 52120b57cec5SDimitry Andric // category provided. 52130b57cec5SDimitry Andric std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); 5214349cc55cSDimitry Andric struct CategoryLess { 5215349cc55cSDimitry Andric bool operator()(const Record *L, const Record *R) const { 5216349cc55cSDimitry Andric return L->getValueAsString("Name") < R->getValueAsString("Name"); 5217349cc55cSDimitry Andric } 5218349cc55cSDimitry Andric }; 5219349cc55cSDimitry Andric std::map<const Record *, std::vector<DocumentationData>, CategoryLess> 5220349cc55cSDimitry Andric SplitDocs; 52210b57cec5SDimitry Andric for (const auto *A : Attrs) { 52220b57cec5SDimitry Andric const Record &Attr = *A; 52230b57cec5SDimitry Andric std::vector<Record *> Docs = Attr.getValueAsListOfDefs("Documentation"); 52240b57cec5SDimitry Andric for (const auto *D : Docs) { 52250b57cec5SDimitry Andric const Record &Doc = *D; 52260b57cec5SDimitry Andric const Record *Category = Doc.getValueAsDef("Category"); 522781ad6265SDimitry Andric // If the category is "InternalOnly", then there cannot be any other 522881ad6265SDimitry Andric // documentation categories (otherwise, the attribute would be 522981ad6265SDimitry Andric // emitted into the docs). 52300b57cec5SDimitry Andric const StringRef Cat = Category->getValueAsString("Name"); 523181ad6265SDimitry Andric bool InternalOnly = Cat == "InternalOnly"; 523281ad6265SDimitry Andric if (InternalOnly && Docs.size() > 1) 52330b57cec5SDimitry Andric PrintFatalError(Doc.getLoc(), 523481ad6265SDimitry Andric "Attribute is \"InternalOnly\", but has multiple " 52350b57cec5SDimitry Andric "documentation categories"); 52360b57cec5SDimitry Andric 523781ad6265SDimitry Andric if (!InternalOnly) 52380b57cec5SDimitry Andric SplitDocs[Category].push_back(DocumentationData( 523981ad6265SDimitry Andric Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr, Cat))); 52400b57cec5SDimitry Andric } 52410b57cec5SDimitry Andric } 52420b57cec5SDimitry Andric 52430b57cec5SDimitry Andric // Having split the attributes out based on what documentation goes where, 52440b57cec5SDimitry Andric // we can begin to generate sections of documentation. 52450b57cec5SDimitry Andric for (auto &I : SplitDocs) { 52460b57cec5SDimitry Andric WriteCategoryHeader(I.first, OS); 52470b57cec5SDimitry Andric 52480b57cec5SDimitry Andric llvm::sort(I.second, 52490b57cec5SDimitry Andric [](const DocumentationData &D1, const DocumentationData &D2) { 52500b57cec5SDimitry Andric return D1.Heading < D2.Heading; 52510b57cec5SDimitry Andric }); 52520b57cec5SDimitry Andric 52530b57cec5SDimitry Andric // Walk over each of the attributes in the category and write out their 52540b57cec5SDimitry Andric // documentation. 52550b57cec5SDimitry Andric for (const auto &Doc : I.second) 52560b57cec5SDimitry Andric WriteDocumentation(Records, Doc, OS); 52570b57cec5SDimitry Andric } 52580b57cec5SDimitry Andric } 52590b57cec5SDimitry Andric 52600b57cec5SDimitry Andric void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records, 52610b57cec5SDimitry Andric raw_ostream &OS) { 52620b57cec5SDimitry Andric PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records); 52630b57cec5SDimitry Andric ParsedAttrMap Attrs = getParsedAttrList(Records); 52640b57cec5SDimitry Andric OS << "#pragma clang attribute supports the following attributes:\n"; 52650b57cec5SDimitry Andric for (const auto &I : Attrs) { 52660b57cec5SDimitry Andric if (!Support.isAttributedSupported(*I.second)) 52670b57cec5SDimitry Andric continue; 52680b57cec5SDimitry Andric OS << I.first; 52690b57cec5SDimitry Andric if (I.second->isValueUnset("Subjects")) { 52700b57cec5SDimitry Andric OS << " ()\n"; 52710b57cec5SDimitry Andric continue; 52720b57cec5SDimitry Andric } 52730b57cec5SDimitry Andric const Record *SubjectObj = I.second->getValueAsDef("Subjects"); 52740b57cec5SDimitry Andric std::vector<Record *> Subjects = 52750b57cec5SDimitry Andric SubjectObj->getValueAsListOfDefs("Subjects"); 52760b57cec5SDimitry Andric OS << " ("; 5277fe6060f1SDimitry Andric bool PrintComma = false; 52780b57cec5SDimitry Andric for (const auto &Subject : llvm::enumerate(Subjects)) { 5279fe6060f1SDimitry Andric if (!isSupportedPragmaClangAttributeSubject(*Subject.value())) 5280fe6060f1SDimitry Andric continue; 5281fe6060f1SDimitry Andric if (PrintComma) 52820b57cec5SDimitry Andric OS << ", "; 5283fe6060f1SDimitry Andric PrintComma = true; 52840b57cec5SDimitry Andric PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = 52850b57cec5SDimitry Andric Support.SubjectsToRules.find(Subject.value())->getSecond(); 52860b57cec5SDimitry Andric if (RuleSet.isRule()) { 52870b57cec5SDimitry Andric OS << RuleSet.getRule().getEnumValueName(); 52880b57cec5SDimitry Andric continue; 52890b57cec5SDimitry Andric } 52900b57cec5SDimitry Andric OS << "("; 52910b57cec5SDimitry Andric for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) { 52920b57cec5SDimitry Andric if (Rule.index()) 52930b57cec5SDimitry Andric OS << ", "; 52940b57cec5SDimitry Andric OS << Rule.value().getEnumValueName(); 52950b57cec5SDimitry Andric } 52960b57cec5SDimitry Andric OS << ")"; 52970b57cec5SDimitry Andric } 52980b57cec5SDimitry Andric OS << ")\n"; 52990b57cec5SDimitry Andric } 53000b57cec5SDimitry Andric OS << "End of supported attributes.\n"; 53010b57cec5SDimitry Andric } 53020b57cec5SDimitry Andric 53030b57cec5SDimitry Andric } // end namespace clang 5304