2011-10-06 21:03:08 +08:00
|
|
|
//===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// These tablegen backends emit Clang attribute processing code
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-05-13 06:27:08 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2016-12-01 08:13:18 +08:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2016-05-13 06:27:08 +08:00
|
|
|
#include "llvm/ADT/iterator_range.h"
|
2012-06-19 00:13:52 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2014-11-18 02:17:19 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2016-05-13 06:27:08 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2014-01-07 19:51:46 +08:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2016-05-13 06:27:08 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-01-07 19:51:46 +08:00
|
|
|
#include "llvm/TableGen/Error.h"
|
2011-10-06 21:03:08 +08:00
|
|
|
#include "llvm/TableGen/Record.h"
|
2012-05-03 01:33:51 +08:00
|
|
|
#include "llvm/TableGen/StringMatcher.h"
|
2012-06-13 13:12:41 +08:00
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
2011-10-06 21:03:08 +08:00
|
|
|
#include <algorithm>
|
2016-05-13 06:27:08 +08:00
|
|
|
#include <cassert>
|
2011-10-06 21:03:08 +08:00
|
|
|
#include <cctype>
|
2016-05-13 06:27:08 +08:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <map>
|
2014-03-06 00:49:55 +08:00
|
|
|
#include <memory>
|
2013-11-29 22:57:58 +08:00
|
|
|
#include <set>
|
2014-01-07 19:51:46 +08:00
|
|
|
#include <sstream>
|
2016-05-13 06:27:08 +08:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2015-03-11 02:24:01 +08:00
|
|
|
namespace {
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
class FlattenedSpelling {
|
|
|
|
std::string V, N, NS;
|
|
|
|
bool K;
|
|
|
|
|
|
|
|
public:
|
|
|
|
FlattenedSpelling(const std::string &Variety, const std::string &Name,
|
|
|
|
const std::string &Namespace, bool KnownToGCC) :
|
|
|
|
V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {}
|
|
|
|
explicit FlattenedSpelling(const Record &Spelling) :
|
|
|
|
V(Spelling.getValueAsString("Variety")),
|
|
|
|
N(Spelling.getValueAsString("Name")) {
|
|
|
|
|
|
|
|
assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been"
|
|
|
|
"flattened!");
|
2014-06-14 01:57:25 +08:00
|
|
|
if (V == "CXX11" || V == "Pragma")
|
2014-01-28 06:10:04 +08:00
|
|
|
NS = Spelling.getValueAsString("Namespace");
|
|
|
|
bool Unset;
|
|
|
|
K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string &variety() const { return V; }
|
|
|
|
const std::string &name() const { return N; }
|
|
|
|
const std::string &nameSpace() const { return NS; }
|
|
|
|
bool knownToGCC() const { return K; }
|
|
|
|
};
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2015-10-07 07:40:43 +08:00
|
|
|
} // end anonymous namespace
|
2014-01-28 06:10:04 +08:00
|
|
|
|
2015-03-11 02:24:01 +08:00
|
|
|
static std::vector<FlattenedSpelling>
|
|
|
|
GetFlattenedSpellings(const Record &Attr) {
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings");
|
|
|
|
std::vector<FlattenedSpelling> Ret;
|
|
|
|
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &Spelling : Spellings) {
|
|
|
|
if (Spelling->getValueAsString("Variety") == "GCC") {
|
2014-01-28 06:10:04 +08:00
|
|
|
// Gin up two new spelling objects to add into the list.
|
2015-05-30 03:42:19 +08:00
|
|
|
Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true);
|
|
|
|
Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu",
|
|
|
|
true);
|
2014-01-28 06:10:04 +08:00
|
|
|
} else
|
2014-03-03 01:38:37 +08:00
|
|
|
Ret.push_back(FlattenedSpelling(*Spelling));
|
2014-01-28 06:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
static std::string ReadPCHRecord(StringRef type) {
|
|
|
|
return StringSwitch<std::string>(type)
|
2017-01-24 09:04:30 +08:00
|
|
|
.EndsWith("Decl *", "Record.GetLocalDeclAs<"
|
|
|
|
+ std::string(type, 0, type.size()-1) + ">(Record.readInt())")
|
|
|
|
.Case("TypeSourceInfo *", "Record.getTypeSourceInfo()")
|
|
|
|
.Case("Expr *", "Record.readExpr()")
|
|
|
|
.Case("IdentifierInfo *", "Record.getIdentifierInfo()")
|
|
|
|
.Case("StringRef", "Record.readString()")
|
|
|
|
.Default("Record.readInt()");
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2016-05-18 08:16:51 +08:00
|
|
|
// Get a type that is suitable for storing an object of the specified type.
|
|
|
|
static StringRef getStorageType(StringRef type) {
|
|
|
|
return StringSwitch<StringRef>(type)
|
|
|
|
.Case("StringRef", "std::string")
|
|
|
|
.Default(type);
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
// Assumes that the way to get the value is SA->getname()
|
|
|
|
static std::string WritePCHRecord(StringRef type, StringRef name) {
|
2016-04-07 01:06:00 +08:00
|
|
|
return "Record." + StringSwitch<std::string>(type)
|
|
|
|
.EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ");\n")
|
|
|
|
.Case("TypeSourceInfo *", "AddTypeSourceInfo(" + std::string(name) + ");\n")
|
2011-10-06 21:03:08 +08:00
|
|
|
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
|
2016-04-07 01:06:00 +08:00
|
|
|
.Case("IdentifierInfo *", "AddIdentifierRef(" + std::string(name) + ");\n")
|
|
|
|
.Case("StringRef", "AddString(" + std::string(name) + ");\n")
|
|
|
|
.Default("push_back(" + std::string(name) + ");\n");
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2012-03-07 08:12:16 +08:00
|
|
|
// Normalize attribute name by removing leading and trailing
|
|
|
|
// underscores. For example, __foo, foo__, __foo__ would
|
|
|
|
// become foo.
|
|
|
|
static StringRef NormalizeAttrName(StringRef AttrName) {
|
2016-12-01 08:13:18 +08:00
|
|
|
AttrName.consume_front("__");
|
|
|
|
AttrName.consume_back("__");
|
2012-03-07 08:12:16 +08:00
|
|
|
return AttrName;
|
|
|
|
}
|
|
|
|
|
2014-01-16 21:03:14 +08:00
|
|
|
// Normalize the name by removing any and all leading and trailing underscores.
|
|
|
|
// This is different from NormalizeAttrName in that it also handles names like
|
|
|
|
// _pascal and __pascal.
|
|
|
|
static StringRef NormalizeNameForSpellingComparison(StringRef Name) {
|
2015-04-11 05:37:21 +08:00
|
|
|
return Name.trim("_");
|
2014-01-16 21:03:14 +08:00
|
|
|
}
|
|
|
|
|
2017-01-06 00:51:54 +08:00
|
|
|
// Normalize the spelling of a GNU attribute (i.e. "x" in "__attribute__((x))"),
|
|
|
|
// removing "__" if it appears at the beginning and end of the attribute's name.
|
|
|
|
static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) {
|
2012-03-07 08:12:16 +08:00
|
|
|
if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) {
|
|
|
|
AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
return AttrSpelling;
|
|
|
|
}
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
typedef std::vector<std::pair<std::string, const Record *>> ParsedAttrMap;
|
2013-12-15 21:05:48 +08:00
|
|
|
|
2014-01-10 06:48:32 +08:00
|
|
|
static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records,
|
2014-05-07 14:21:57 +08:00
|
|
|
ParsedAttrMap *Dupes = nullptr) {
|
2014-03-03 01:38:37 +08:00
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
2013-12-15 21:05:48 +08:00
|
|
|
std::set<std::string> Seen;
|
|
|
|
ParsedAttrMap R;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
2014-03-03 01:38:37 +08:00
|
|
|
if (Attr->getValueAsBit("SemaHandler")) {
|
2013-12-15 21:05:48 +08:00
|
|
|
std::string AN;
|
2014-03-03 01:38:37 +08:00
|
|
|
if (Attr->isSubClassOf("TargetSpecificAttr") &&
|
|
|
|
!Attr->isValueUnset("ParseKind")) {
|
|
|
|
AN = Attr->getValueAsString("ParseKind");
|
2013-12-15 21:05:48 +08:00
|
|
|
|
|
|
|
// If this attribute has already been handled, it does not need to be
|
|
|
|
// handled again.
|
2014-01-10 06:48:32 +08:00
|
|
|
if (Seen.find(AN) != Seen.end()) {
|
|
|
|
if (Dupes)
|
2014-03-03 01:38:37 +08:00
|
|
|
Dupes->push_back(std::make_pair(AN, Attr));
|
2013-12-15 21:05:48 +08:00
|
|
|
continue;
|
2014-01-10 06:48:32 +08:00
|
|
|
}
|
2013-12-15 21:05:48 +08:00
|
|
|
Seen.insert(AN);
|
|
|
|
} else
|
2014-03-03 01:38:37 +08:00
|
|
|
AN = NormalizeAttrName(Attr->getName()).str();
|
2013-12-15 21:05:48 +08:00
|
|
|
|
2014-03-03 01:38:37 +08:00
|
|
|
R.push_back(std::make_pair(AN, Attr));
|
2013-12-15 21:05:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
namespace {
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
class Argument {
|
|
|
|
std::string lowerName, upperName;
|
|
|
|
StringRef attrName;
|
2013-09-10 07:33:17 +08:00
|
|
|
bool isOpt;
|
2015-10-28 08:17:34 +08:00
|
|
|
bool Fake;
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
Argument(const Record &Arg, StringRef Attr)
|
2011-10-06 21:03:08 +08:00
|
|
|
: lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
|
2015-10-28 08:17:34 +08:00
|
|
|
attrName(Attr), isOpt(false), Fake(false) {
|
2011-10-06 21:03:08 +08:00
|
|
|
if (!lowerName.empty()) {
|
|
|
|
lowerName[0] = std::tolower(lowerName[0]);
|
|
|
|
upperName[0] = std::toupper(upperName[0]);
|
|
|
|
}
|
2016-06-01 01:42:56 +08:00
|
|
|
// Work around MinGW's macro definition of 'interface' to 'struct'. We
|
|
|
|
// have an attribute argument called 'Interface', so only the lower case
|
|
|
|
// name conflicts with the macro definition.
|
|
|
|
if (lowerName == "interface")
|
|
|
|
lowerName = "interface_";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2015-10-07 07:40:43 +08:00
|
|
|
virtual ~Argument() = default;
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
StringRef getLowerName() const { return lowerName; }
|
|
|
|
StringRef getUpperName() const { return upperName; }
|
|
|
|
StringRef getAttrName() const { return attrName; }
|
|
|
|
|
2013-09-10 07:33:17 +08:00
|
|
|
bool isOptional() const { return isOpt; }
|
|
|
|
void setOptional(bool set) { isOpt = set; }
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
bool isFake() const { return Fake; }
|
|
|
|
void setFake(bool fake) { Fake = fake; }
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
// These functions print the argument contents formatted in different ways.
|
|
|
|
virtual void writeAccessors(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
|
2013-12-31 01:24:36 +08:00
|
|
|
virtual void writeASTVisitorTraversal(raw_ostream &OS) const {}
|
2011-10-06 21:03:08 +08:00
|
|
|
virtual void writeCloneArgs(raw_ostream &OS) const = 0;
|
2012-01-21 06:37:06 +08:00
|
|
|
virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0;
|
2012-02-10 14:00:29 +08:00
|
|
|
virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
|
2011-10-06 21:03:08 +08:00
|
|
|
virtual void writeCtorBody(raw_ostream &OS) const {}
|
|
|
|
virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
|
2013-09-10 07:33:17 +08:00
|
|
|
virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0;
|
2011-10-06 21:03:08 +08:00
|
|
|
virtual void writeCtorParameters(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writeDeclarations(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writePCHWrite(raw_ostream &OS) const = 0;
|
2011-11-20 03:22:57 +08:00
|
|
|
virtual void writeValue(raw_ostream &OS) const = 0;
|
2013-01-08 01:53:08 +08:00
|
|
|
virtual void writeDump(raw_ostream &OS) const = 0;
|
|
|
|
virtual void writeDumpChildren(raw_ostream &OS) const {}
|
2013-01-31 09:44:26 +08:00
|
|
|
virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; }
|
2013-09-12 03:47:58 +08:00
|
|
|
|
|
|
|
virtual bool isEnumArg() const { return false; }
|
2013-10-05 05:28:06 +08:00
|
|
|
virtual bool isVariadicEnumArg() const { return false; }
|
2014-08-01 00:37:04 +08:00
|
|
|
virtual bool isVariadic() const { return false; }
|
2014-01-16 21:03:14 +08:00
|
|
|
|
|
|
|
virtual void writeImplicitCtorArgs(raw_ostream &OS) const {
|
|
|
|
OS << getUpperName();
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class SimpleArgument : public Argument {
|
|
|
|
std::string type;
|
|
|
|
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
SimpleArgument(const Record &Arg, StringRef Attr, std::string T)
|
2016-05-27 22:27:13 +08:00
|
|
|
: Argument(Arg, Attr), type(std::move(T)) {}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2012-01-21 06:37:06 +08:00
|
|
|
std::string getType() const { return type; }
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " " << type << " get" << getUpperName() << "() const {\n";
|
|
|
|
OS << " return " << getLowerName() << ";\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "A->get" << getUpperName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName() << "(" << getUpperName() << ")";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << getLowerName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << type << " " << getUpperName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << type << " " << getLowerName() << ";";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
std::string read = ReadPCHRecord(type);
|
|
|
|
OS << " " << type << " " << getLowerName() << " = " << read << ";\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " " << WritePCHRecord(type, "SA->get" +
|
|
|
|
std::string(getUpperName()) + "()");
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2011-11-20 03:22:57 +08:00
|
|
|
if (type == "FunctionDecl *") {
|
2013-11-01 05:23:20 +08:00
|
|
|
OS << "\" << get" << getUpperName()
|
|
|
|
<< "()->getNameInfo().getAsString() << \"";
|
2011-11-20 03:22:57 +08:00
|
|
|
} else if (type == "IdentifierInfo *") {
|
2016-09-10 11:29:43 +08:00
|
|
|
OS << "\";\n";
|
|
|
|
if (isOptional())
|
|
|
|
OS << " if (get" << getUpperName() << "()) ";
|
|
|
|
else
|
|
|
|
OS << " ";
|
|
|
|
OS << "OS << get" << getUpperName() << "()->getName();\n";
|
|
|
|
OS << " OS << \"";
|
2013-11-01 05:23:20 +08:00
|
|
|
} else if (type == "TypeSourceInfo *") {
|
2011-11-20 03:22:57 +08:00
|
|
|
OS << "\" << get" << getUpperName() << "().getAsString() << \"";
|
|
|
|
} else {
|
|
|
|
OS << "\" << get" << getUpperName() << "() << \"";
|
|
|
|
}
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
if (type == "FunctionDecl *") {
|
|
|
|
OS << " OS << \" \";\n";
|
|
|
|
OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
|
|
|
|
} else if (type == "IdentifierInfo *") {
|
2015-11-30 23:25:34 +08:00
|
|
|
if (isOptional())
|
|
|
|
OS << " if (SA->get" << getUpperName() << "())\n ";
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " OS << \" \" << SA->get" << getUpperName()
|
|
|
|
<< "()->getName();\n";
|
2013-11-01 05:23:20 +08:00
|
|
|
} else if (type == "TypeSourceInfo *") {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " OS << \" \" << SA->get" << getUpperName()
|
|
|
|
<< "().getAsString();\n";
|
|
|
|
} else if (type == "bool") {
|
|
|
|
OS << " if (SA->get" << getUpperName() << "()) OS << \" "
|
|
|
|
<< getUpperName() << "\";\n";
|
|
|
|
} else if (type == "int" || type == "unsigned") {
|
|
|
|
OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
|
|
|
|
} else {
|
|
|
|
llvm_unreachable("Unknown SimpleArgument type!");
|
|
|
|
}
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
|
|
|
|
2013-11-21 08:28:23 +08:00
|
|
|
class DefaultSimpleArgument : public SimpleArgument {
|
|
|
|
int64_t Default;
|
|
|
|
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
DefaultSimpleArgument(const Record &Arg, StringRef Attr,
|
2013-11-21 08:28:23 +08:00
|
|
|
std::string T, int64_t Default)
|
|
|
|
: SimpleArgument(Arg, Attr, T), Default(Default) {}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2013-11-21 08:28:23 +08:00
|
|
|
SimpleArgument::writeAccessors(OS);
|
|
|
|
|
|
|
|
OS << "\n\n static const " << getType() << " Default" << getUpperName()
|
2016-05-13 06:27:08 +08:00
|
|
|
<< " = ";
|
|
|
|
if (getType() == "bool")
|
|
|
|
OS << (Default != 0 ? "true" : "false");
|
|
|
|
else
|
|
|
|
OS << Default;
|
|
|
|
OS << ";";
|
2013-11-21 08:28:23 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
class StringArgument : public Argument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
StringArgument(const Record &Arg, StringRef Attr)
|
2011-10-06 21:03:08 +08:00
|
|
|
: Argument(Arg, Attr)
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " llvm::StringRef get" << getUpperName() << "() const {\n";
|
|
|
|
OS << " return llvm::StringRef(" << getLowerName() << ", "
|
|
|
|
<< getLowerName() << "Length);\n";
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " unsigned get" << getUpperName() << "Length() const {\n";
|
|
|
|
OS << " return " << getLowerName() << "Length;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " void set" << getUpperName()
|
|
|
|
<< "(ASTContext &C, llvm::StringRef S) {\n";
|
|
|
|
OS << " " << getLowerName() << "Length = S.size();\n";
|
|
|
|
OS << " this->" << getLowerName() << " = new (C, 1) char ["
|
|
|
|
<< getLowerName() << "Length];\n";
|
2015-08-04 11:53:01 +08:00
|
|
|
OS << " if (!S.empty())\n";
|
|
|
|
OS << " std::memcpy(this->" << getLowerName() << ", S.data(), "
|
2011-10-06 21:03:08 +08:00
|
|
|
<< getLowerName() << "Length);\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "get" << getUpperName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "A->get" << getUpperName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorBody(raw_ostream &OS) const override {
|
2015-08-04 11:53:01 +08:00
|
|
|
OS << " if (!" << getUpperName() << ".empty())\n";
|
|
|
|
OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
|
2016-05-13 06:27:08 +08:00
|
|
|
<< ".data(), " << getLowerName() << "Length);\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName() << "Length(" << getUpperName() << ".size()),"
|
|
|
|
<< getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
|
|
|
|
<< "Length])";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2015-09-30 04:56:43 +08:00
|
|
|
OS << getLowerName() << "Length(0)," << getLowerName() << "(nullptr)";
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "llvm::StringRef " << getUpperName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "unsigned " << getLowerName() << "Length;\n";
|
|
|
|
OS << "char *" << getLowerName() << ";";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " std::string " << getLowerName()
|
2017-01-24 09:04:30 +08:00
|
|
|
<< "= Record.readString();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2016-04-07 01:06:00 +08:00
|
|
|
OS << " Record.AddString(SA->get" << getUpperName() << "());\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2011-11-20 03:22:57 +08:00
|
|
|
OS << "\\\"\" << get" << getUpperName() << "() << \"\\\"";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " OS << \" \\\"\" << SA->get" << getUpperName()
|
|
|
|
<< "() << \"\\\"\";\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class AlignedArgument : public Argument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
AlignedArgument(const Record &Arg, StringRef Attr)
|
2011-10-06 21:03:08 +08:00
|
|
|
: Argument(Arg, Attr)
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " bool is" << getUpperName() << "Dependent() const;\n";
|
|
|
|
|
|
|
|
OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n";
|
|
|
|
|
|
|
|
OS << " bool is" << getUpperName() << "Expr() const {\n";
|
|
|
|
OS << " return is" << getLowerName() << "Expr;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
|
|
|
|
OS << " Expr *get" << getUpperName() << "Expr() const {\n";
|
|
|
|
OS << " assert(is" << getLowerName() << "Expr);\n";
|
|
|
|
OS << " return " << getLowerName() << "Expr;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
|
|
|
|
OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n";
|
|
|
|
OS << " assert(!is" << getLowerName() << "Expr);\n";
|
|
|
|
OS << " return " << getLowerName() << "Type;\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessorDefinitions(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "bool " << getAttrName() << "Attr::is" << getUpperName()
|
|
|
|
<< "Dependent() const {\n";
|
|
|
|
OS << " if (is" << getLowerName() << "Expr)\n";
|
|
|
|
OS << " return " << getLowerName() << "Expr && (" << getLowerName()
|
|
|
|
<< "Expr->isValueDependent() || " << getLowerName()
|
|
|
|
<< "Expr->isTypeDependent());\n";
|
|
|
|
OS << " else\n";
|
|
|
|
OS << " return " << getLowerName()
|
|
|
|
<< "Type->getType()->isDependentType();\n";
|
|
|
|
OS << "}\n";
|
|
|
|
|
|
|
|
// FIXME: Do not do the calculation here
|
|
|
|
// FIXME: Handle types correctly
|
|
|
|
// A null pointer means maximum alignment
|
|
|
|
OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName()
|
|
|
|
<< "(ASTContext &Ctx) const {\n";
|
|
|
|
OS << " assert(!is" << getUpperName() << "Dependent());\n";
|
|
|
|
OS << " if (is" << getLowerName() << "Expr)\n";
|
Implement target-specific __attribute__((aligned)) value
The GCC construct __attribute__((aligned)) is defined to set alignment
to "the default alignment for the target architecture" according to
the GCC documentation:
The default alignment is sufficient for all scalar types, but may not be
enough for all vector types on a target that supports vector operations.
The default alignment is fixed for a particular target ABI.
clang currently hard-coded an alignment of 16 bytes for that construct,
which is correct on some platforms (including X86), but wrong on others
(including SystemZ). Since this value is ABI-relevant, it is important
to get correct for compatibility purposes.
This patch adds a new TargetInfo member "DefaultAlignForAttributeAligned"
that targets can set to the appropriate default __attribute__((aligned))
value.
Note that I'm deliberately *not* using the existing "SuitableAlign"
value, which is used to set the pre-defined macro __BIGGEST_ALIGNMENT__,
since those two values may not be the same on all platforms. In fact,
on X86, __attribute__((aligned)) always uses 16-byte alignment, while
__BIGGEST_ALIGNMENT__ may be larger if AVX-2 or AVX-512 are supported.
(This is actually not yet correctly implemented in clang either.)
The patch provides a value for DefaultAlignForAttributeAligned only for
SystemZ, and leaves the default for all other targets at 16, which means
no visible change in behavior on all other targets. (The value is still
wrong for some other targets, but I'd prefer to leave it to the target
maintainers for those platforms to fix.)
llvm-svn: 235397
2015-04-22 01:29:35 +08:00
|
|
|
OS << " return " << getLowerName() << "Expr ? " << getLowerName()
|
|
|
|
<< "Expr->EvaluateKnownConstInt(Ctx).getZExtValue()"
|
|
|
|
<< " * Ctx.getCharWidth() : "
|
|
|
|
<< "Ctx.getTargetDefaultAlignForAttributeAligned();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " else\n";
|
|
|
|
OS << " return 0; // FIXME\n";
|
|
|
|
OS << "}\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "is" << getLowerName() << "Expr, is" << getLowerName()
|
|
|
|
<< "Expr ? static_cast<void*>(" << getLowerName()
|
|
|
|
<< "Expr) : " << getLowerName()
|
|
|
|
<< "Type";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
// FIXME: move the definition in Sema::InstantiateAttrs to here.
|
|
|
|
// In the meantime, aligned attributes are cloned.
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorBody(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " if (is" << getLowerName() << "Expr)\n";
|
|
|
|
OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>("
|
|
|
|
<< getUpperName() << ");\n";
|
|
|
|
OS << " else\n";
|
|
|
|
OS << " " << getLowerName()
|
|
|
|
<< "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName()
|
2016-05-13 06:27:08 +08:00
|
|
|
<< ");\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << "is" << getLowerName() << "Expr(false)";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeImplicitCtorArgs(raw_ostream &OS) const override {
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << "Is" << getUpperName() << "Expr, " << getUpperName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "bool is" << getLowerName() << "Expr;\n";
|
|
|
|
OS << "union {\n";
|
|
|
|
OS << "Expr *" << getLowerName() << "Expr;\n";
|
|
|
|
OS << "TypeSourceInfo *" << getLowerName() << "Type;\n";
|
|
|
|
OS << "};";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2017-01-24 09:04:30 +08:00
|
|
|
OS << " bool is" << getLowerName() << "Expr = Record.readInt();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " void *" << getLowerName() << "Ptr;\n";
|
|
|
|
OS << " if (is" << getLowerName() << "Expr)\n";
|
2017-01-24 09:04:30 +08:00
|
|
|
OS << " " << getLowerName() << "Ptr = Record.readExpr();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " else\n";
|
|
|
|
OS << " " << getLowerName()
|
2017-01-24 09:04:30 +08:00
|
|
|
<< "Ptr = Record.getTypeSourceInfo();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n";
|
|
|
|
OS << " if (SA->is" << getUpperName() << "Expr())\n";
|
2016-04-07 01:06:00 +08:00
|
|
|
OS << " Record.AddStmt(SA->get" << getUpperName() << "Expr());\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " else\n";
|
2016-04-07 01:06:00 +08:00
|
|
|
OS << " Record.AddTypeSourceInfo(SA->get" << getUpperName()
|
|
|
|
<< "Type());\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2014-06-10 06:53:25 +08:00
|
|
|
OS << "\";\n";
|
2014-08-01 21:49:00 +08:00
|
|
|
// The aligned attribute argument expression is optional.
|
|
|
|
OS << " if (is" << getLowerName() << "Expr && "
|
|
|
|
<< getLowerName() << "Expr)\n";
|
2015-09-30 04:56:43 +08:00
|
|
|
OS << " " << getLowerName() << "Expr->printPretty(OS, nullptr, Policy);\n";
|
2014-06-10 06:53:25 +08:00
|
|
|
OS << " OS << \"";
|
2011-11-20 03:22:57 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
|
|
|
void writeDump(raw_ostream &OS) const override {}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDumpChildren(raw_ostream &OS) const override {
|
2014-10-31 05:02:37 +08:00
|
|
|
OS << " if (SA->is" << getUpperName() << "Expr())\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n";
|
2014-10-31 05:02:37 +08:00
|
|
|
OS << " else\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " dumpType(SA->get" << getUpperName()
|
|
|
|
<< "Type()->getType());\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeHasChildren(raw_ostream &OS) const override {
|
2013-01-31 09:44:26 +08:00
|
|
|
OS << "SA->is" << getUpperName() << "Expr()";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class VariadicArgument : public Argument {
|
2014-05-02 21:35:42 +08:00
|
|
|
std::string Type, ArgName, ArgSizeName, RangeName;
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-09-15 23:14:13 +08:00
|
|
|
protected:
|
|
|
|
// Assumed to receive a parameter: raw_ostream OS.
|
|
|
|
virtual void writeValueImpl(raw_ostream &OS) const {
|
|
|
|
OS << " OS << Val;\n";
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
VariadicArgument(const Record &Arg, StringRef Attr, std::string T)
|
2016-05-27 22:27:13 +08:00
|
|
|
: Argument(Arg, Attr), Type(std::move(T)),
|
|
|
|
ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"),
|
|
|
|
RangeName(getLowerName()) {}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-02-14 02:11:49 +08:00
|
|
|
const std::string &getType() const { return Type; }
|
|
|
|
const std::string &getArgName() const { return ArgName; }
|
|
|
|
const std::string &getArgSizeName() const { return ArgSizeName; }
|
2014-08-01 00:37:04 +08:00
|
|
|
bool isVariadic() const override { return true; }
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
std::string IteratorType = getLowerName().str() + "_iterator";
|
|
|
|
std::string BeginFn = getLowerName().str() + "_begin()";
|
|
|
|
std::string EndFn = getLowerName().str() + "_end()";
|
|
|
|
|
|
|
|
OS << " typedef " << Type << "* " << IteratorType << ";\n";
|
|
|
|
OS << " " << IteratorType << " " << BeginFn << " const {"
|
|
|
|
<< " return " << ArgName << "; }\n";
|
|
|
|
OS << " " << IteratorType << " " << EndFn << " const {"
|
|
|
|
<< " return " << ArgName << " + " << ArgSizeName << "; }\n";
|
|
|
|
OS << " unsigned " << getLowerName() << "_size() const {"
|
|
|
|
<< " return " << ArgSizeName << "; }\n";
|
|
|
|
OS << " llvm::iterator_range<" << IteratorType << "> " << RangeName
|
|
|
|
<< "() const { return llvm::make_range(" << BeginFn << ", " << EndFn
|
|
|
|
<< "); }\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << ArgName << ", " << ArgSizeName;
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
// This isn't elegant, but we have to go through public methods...
|
|
|
|
OS << "A->" << getLowerName() << "_begin(), "
|
|
|
|
<< "A->" << getLowerName() << "_size()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorBody(raw_ostream &OS) const override {
|
2014-05-01 23:21:03 +08:00
|
|
|
OS << " std::copy(" << getUpperName() << ", " << getUpperName()
|
2016-05-13 06:27:08 +08:00
|
|
|
<< " + " << ArgSizeName << ", " << ArgName << ");\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << ArgSizeName << "(" << getUpperName() << "Size), "
|
|
|
|
<< ArgName << "(new (Ctx, 16) " << getType() << "["
|
|
|
|
<< ArgSizeName << "])";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << ArgSizeName << "(0), " << ArgName << "(nullptr)";
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getType() << " *" << getUpperName() << ", unsigned "
|
|
|
|
<< getUpperName() << "Size";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeImplicitCtorArgs(raw_ostream &OS) const override {
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << getUpperName() << ", " << getUpperName() << "Size";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << " unsigned " << ArgSizeName << ";\n";
|
|
|
|
OS << " " << getType() << " *" << ArgName << ";";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2017-01-24 09:04:30 +08:00
|
|
|
OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
|
2016-05-18 08:16:51 +08:00
|
|
|
OS << " SmallVector<" << getType() << ", 4> "
|
|
|
|
<< getLowerName() << ";\n";
|
|
|
|
OS << " " << getLowerName() << ".reserve(" << getLowerName()
|
2011-10-06 21:03:08 +08:00
|
|
|
<< "Size);\n";
|
2016-05-18 08:16:51 +08:00
|
|
|
|
|
|
|
// If we can't store the values in the current type (if it's something
|
|
|
|
// like StringRef), store them in a different type and convert the
|
|
|
|
// container afterwards.
|
|
|
|
std::string StorageType = getStorageType(getType());
|
|
|
|
std::string StorageName = getLowerName();
|
|
|
|
if (StorageType != getType()) {
|
|
|
|
StorageName += "Storage";
|
|
|
|
OS << " SmallVector<" << StorageType << ", 4> "
|
|
|
|
<< StorageName << ";\n";
|
|
|
|
OS << " " << StorageName << ".reserve(" << getLowerName()
|
|
|
|
<< "Size);\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n";
|
2014-05-02 21:35:42 +08:00
|
|
|
std::string read = ReadPCHRecord(Type);
|
2016-05-18 08:16:51 +08:00
|
|
|
OS << " " << StorageName << ".push_back(" << read << ");\n";
|
|
|
|
|
|
|
|
if (StorageType != getType()) {
|
|
|
|
OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n";
|
|
|
|
OS << " " << getLowerName() << ".push_back("
|
|
|
|
<< StorageName << "[i]);\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName() << ".data(), " << getLowerName() << "Size";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << " for (auto &Val : SA->" << RangeName << "())\n";
|
|
|
|
OS << " " << WritePCHRecord(Type, "Val");
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2011-11-20 03:22:57 +08:00
|
|
|
OS << "\";\n";
|
|
|
|
OS << " bool isFirst = true;\n"
|
2014-05-02 21:35:42 +08:00
|
|
|
<< " for (const auto &Val : " << RangeName << "()) {\n"
|
2011-11-20 03:22:57 +08:00
|
|
|
<< " if (isFirst) isFirst = false;\n"
|
2014-09-15 23:14:13 +08:00
|
|
|
<< " else OS << \", \";\n";
|
|
|
|
writeValueImpl(OS);
|
|
|
|
OS << " }\n";
|
2011-11-20 03:22:57 +08:00
|
|
|
OS << " OS << \"";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2014-05-02 21:35:42 +08:00
|
|
|
OS << " for (const auto &Val : SA->" << RangeName << "())\n";
|
|
|
|
OS << " OS << \" \" << Val;\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
|
|
|
|
2014-02-13 02:22:18 +08:00
|
|
|
// Unique the enums, but maintain the original declaration ordering.
|
2014-02-13 03:26:24 +08:00
|
|
|
std::vector<std::string>
|
|
|
|
uniqueEnumsInOrder(const std::vector<std::string> &enums) {
|
2014-02-13 02:22:18 +08:00
|
|
|
std::vector<std::string> uniques;
|
2016-12-01 08:13:18 +08:00
|
|
|
SmallDenseSet<StringRef, 8> unique_set;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &i : enums) {
|
2016-12-01 08:13:18 +08:00
|
|
|
if (unique_set.insert(i).second)
|
2014-03-03 01:38:37 +08:00
|
|
|
uniques.push_back(i);
|
2014-02-13 02:22:18 +08:00
|
|
|
}
|
|
|
|
return uniques;
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
class EnumArgument : public Argument {
|
|
|
|
std::string type;
|
2014-01-06 05:08:29 +08:00
|
|
|
std::vector<std::string> values, enums, uniques;
|
2011-10-06 21:03:08 +08:00
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
EnumArgument(const Record &Arg, StringRef Attr)
|
2011-10-06 21:03:08 +08:00
|
|
|
: Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
|
2014-01-06 05:08:29 +08:00
|
|
|
values(Arg.getValueAsListOfStrings("Values")),
|
|
|
|
enums(Arg.getValueAsListOfStrings("Enums")),
|
2014-02-13 02:22:18 +08:00
|
|
|
uniques(uniqueEnumsInOrder(enums))
|
2013-01-08 01:53:08 +08:00
|
|
|
{
|
|
|
|
// FIXME: Emit a proper error
|
|
|
|
assert(!uniques.empty());
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
bool isEnumArg() const override { return true; }
|
2013-09-12 03:47:58 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " " << type << " get" << getUpperName() << "() const {\n";
|
|
|
|
OS << " return " << getLowerName() << ";\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "A->get" << getUpperName() << "()";
|
|
|
|
}
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName() << "(" << getUpperName() << ")";
|
|
|
|
}
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << getLowerName() << "(" << type << "(0))";
|
|
|
|
}
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << type << " " << getUpperName();
|
|
|
|
}
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2015-12-09 02:49:01 +08:00
|
|
|
auto i = uniques.cbegin(), e = uniques.cend();
|
2011-10-06 21:03:08 +08:00
|
|
|
// The last one needs to not have a comma.
|
|
|
|
--e;
|
|
|
|
|
|
|
|
OS << "public:\n";
|
|
|
|
OS << " enum " << type << " {\n";
|
|
|
|
for (; i != e; ++i)
|
|
|
|
OS << " " << *i << ",\n";
|
|
|
|
OS << " " << *e << "\n";
|
|
|
|
OS << " };\n";
|
|
|
|
OS << "private:\n";
|
|
|
|
OS << " " << type << " " << getLowerName() << ";";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
|
|
|
|
<< "(static_cast<" << getAttrName() << "Attr::" << type
|
2017-01-24 09:04:30 +08:00
|
|
|
<< ">(Record.readInt()));\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2014-09-16 00:16:14 +08:00
|
|
|
// FIXME: this isn't 100% correct -- some enum arguments require printing
|
|
|
|
// as a string literal, while others require printing as an identifier.
|
|
|
|
// Tablegen currently does not distinguish between the two forms.
|
2014-09-15 23:14:13 +08:00
|
|
|
OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << type << "ToStr(get"
|
|
|
|
<< getUpperName() << "()) << \"\\\"";
|
2011-11-20 03:22:57 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " switch(SA->get" << getUpperName() << "()) {\n";
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : uniques) {
|
|
|
|
OS << " case " << getAttrName() << "Attr::" << I << ":\n";
|
|
|
|
OS << " OS << \" " << I << "\";\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " break;\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
2013-09-12 03:47:58 +08:00
|
|
|
|
|
|
|
void writeConversion(raw_ostream &OS) const {
|
|
|
|
OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
|
|
|
|
OS << type << " &Out) {\n";
|
|
|
|
OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
|
2014-03-03 01:38:37 +08:00
|
|
|
OS << type << ">>(Val)\n";
|
2013-09-12 03:47:58 +08:00
|
|
|
for (size_t I = 0; I < enums.size(); ++I) {
|
|
|
|
OS << " .Case(\"" << values[I] << "\", ";
|
|
|
|
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
|
|
|
|
}
|
|
|
|
OS << " .Default(Optional<" << type << ">());\n";
|
|
|
|
OS << " if (R) {\n";
|
|
|
|
OS << " Out = *R;\n return true;\n }\n";
|
|
|
|
OS << " return false;\n";
|
2014-09-15 23:14:13 +08:00
|
|
|
OS << " }\n\n";
|
|
|
|
|
|
|
|
// Mapping from enumeration values back to enumeration strings isn't
|
|
|
|
// trivial because some enumeration values have multiple named
|
|
|
|
// enumerators, such as type_visibility(internal) and
|
|
|
|
// type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden.
|
|
|
|
OS << " static const char *Convert" << type << "ToStr("
|
|
|
|
<< type << " Val) {\n"
|
|
|
|
<< " switch(Val) {\n";
|
2016-12-01 08:13:18 +08:00
|
|
|
SmallDenseSet<StringRef, 8> Uniques;
|
2014-09-15 23:14:13 +08:00
|
|
|
for (size_t I = 0; I < enums.size(); ++I) {
|
|
|
|
if (Uniques.insert(enums[I]).second)
|
|
|
|
OS << " case " << getAttrName() << "Attr::" << enums[I]
|
|
|
|
<< ": return \"" << values[I] << "\";\n";
|
|
|
|
}
|
|
|
|
OS << " }\n"
|
|
|
|
<< " llvm_unreachable(\"No enumerator with that value\");\n"
|
|
|
|
<< " }\n";
|
2013-09-12 03:47:58 +08:00
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
2013-10-05 05:28:06 +08:00
|
|
|
|
|
|
|
class VariadicEnumArgument: public VariadicArgument {
|
|
|
|
std::string type, QualifiedTypeName;
|
2014-01-06 05:08:29 +08:00
|
|
|
std::vector<std::string> values, enums, uniques;
|
2014-09-15 23:14:13 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
void writeValueImpl(raw_ostream &OS) const override {
|
2014-09-16 00:16:14 +08:00
|
|
|
// FIXME: this isn't 100% correct -- some enum arguments require printing
|
|
|
|
// as a string literal, while others require printing as an identifier.
|
|
|
|
// Tablegen currently does not distinguish between the two forms.
|
2014-09-15 23:14:13 +08:00
|
|
|
OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" << type
|
|
|
|
<< "ToStr(Val)" << "<< \"\\\"\";\n";
|
|
|
|
}
|
|
|
|
|
2013-10-05 05:28:06 +08:00
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
VariadicEnumArgument(const Record &Arg, StringRef Attr)
|
2013-10-05 05:28:06 +08:00
|
|
|
: VariadicArgument(Arg, Attr, Arg.getValueAsString("Type")),
|
|
|
|
type(Arg.getValueAsString("Type")),
|
2014-01-06 05:08:29 +08:00
|
|
|
values(Arg.getValueAsListOfStrings("Values")),
|
|
|
|
enums(Arg.getValueAsListOfStrings("Enums")),
|
2014-02-13 02:22:18 +08:00
|
|
|
uniques(uniqueEnumsInOrder(enums))
|
2013-10-05 05:28:06 +08:00
|
|
|
{
|
|
|
|
QualifiedTypeName = getAttrName().str() + "Attr::" + type;
|
|
|
|
|
|
|
|
// FIXME: Emit a proper error
|
|
|
|
assert(!uniques.empty());
|
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
bool isVariadicEnumArg() const override { return true; }
|
2013-10-05 05:28:06 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2015-12-09 02:49:01 +08:00
|
|
|
auto i = uniques.cbegin(), e = uniques.cend();
|
2013-10-05 05:28:06 +08:00
|
|
|
// The last one needs to not have a comma.
|
|
|
|
--e;
|
|
|
|
|
|
|
|
OS << "public:\n";
|
|
|
|
OS << " enum " << type << " {\n";
|
|
|
|
for (; i != e; ++i)
|
|
|
|
OS << " " << *i << ",\n";
|
|
|
|
OS << " " << *e << "\n";
|
|
|
|
OS << " };\n";
|
|
|
|
OS << "private:\n";
|
|
|
|
|
|
|
|
VariadicArgument::writeDeclarations(OS);
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2013-10-05 05:28:06 +08:00
|
|
|
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
|
|
|
|
<< "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
|
|
|
|
<< getLowerName() << "_end(); I != E; ++I) {\n";
|
|
|
|
OS << " switch(*I) {\n";
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &UI : uniques) {
|
|
|
|
OS << " case " << getAttrName() << "Attr::" << UI << ":\n";
|
|
|
|
OS << " OS << \" " << UI << "\";\n";
|
2013-10-05 05:28:06 +08:00
|
|
|
OS << " break;\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2017-01-24 09:04:30 +08:00
|
|
|
OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
|
2013-10-05 05:28:06 +08:00
|
|
|
OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName()
|
|
|
|
<< ";\n";
|
|
|
|
OS << " " << getLowerName() << ".reserve(" << getLowerName()
|
|
|
|
<< "Size);\n";
|
|
|
|
OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
|
|
|
|
OS << " " << getLowerName() << ".push_back(" << "static_cast<"
|
2017-01-24 09:04:30 +08:00
|
|
|
<< QualifiedTypeName << ">(Record.readInt()));\n";
|
2013-10-05 05:28:06 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2013-10-05 05:28:06 +08:00
|
|
|
OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
|
|
|
|
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
|
|
|
|
<< "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->"
|
|
|
|
<< getLowerName() << "_end(); i != e; ++i)\n";
|
|
|
|
OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)");
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2013-10-05 05:28:06 +08:00
|
|
|
void writeConversion(raw_ostream &OS) const {
|
|
|
|
OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
|
|
|
|
OS << type << " &Out) {\n";
|
|
|
|
OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
|
2014-03-03 01:38:37 +08:00
|
|
|
OS << type << ">>(Val)\n";
|
2013-10-05 05:28:06 +08:00
|
|
|
for (size_t I = 0; I < enums.size(); ++I) {
|
|
|
|
OS << " .Case(\"" << values[I] << "\", ";
|
|
|
|
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
|
|
|
|
}
|
|
|
|
OS << " .Default(Optional<" << type << ">());\n";
|
|
|
|
OS << " if (R) {\n";
|
|
|
|
OS << " Out = *R;\n return true;\n }\n";
|
|
|
|
OS << " return false;\n";
|
2014-09-15 23:14:13 +08:00
|
|
|
OS << " }\n\n";
|
|
|
|
|
|
|
|
OS << " static const char *Convert" << type << "ToStr("
|
|
|
|
<< type << " Val) {\n"
|
|
|
|
<< " switch(Val) {\n";
|
2016-12-01 08:13:18 +08:00
|
|
|
SmallDenseSet<StringRef, 8> Uniques;
|
2014-09-15 23:14:13 +08:00
|
|
|
for (size_t I = 0; I < enums.size(); ++I) {
|
|
|
|
if (Uniques.insert(enums[I]).second)
|
|
|
|
OS << " case " << getAttrName() << "Attr::" << enums[I]
|
|
|
|
<< ": return \"" << values[I] << "\";\n";
|
|
|
|
}
|
|
|
|
OS << " }\n"
|
|
|
|
<< " llvm_unreachable(\"No enumerator with that value\");\n"
|
|
|
|
<< " }\n";
|
2013-10-05 05:28:06 +08:00
|
|
|
}
|
|
|
|
};
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
class VersionArgument : public Argument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
VersionArgument(const Record &Arg, StringRef Attr)
|
2011-10-06 21:03:08 +08:00
|
|
|
: Argument(Arg, Attr)
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " VersionTuple get" << getUpperName() << "() const {\n";
|
|
|
|
OS << " return " << getLowerName() << ";\n";
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " void set" << getUpperName()
|
|
|
|
<< "(ASTContext &C, VersionTuple V) {\n";
|
|
|
|
OS << " " << getLowerName() << " = V;\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCloneArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "get" << getUpperName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "A->get" << getUpperName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorInitializers(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName() << "(" << getUpperName() << ")";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << getLowerName() << "()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeCtorParameters(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "VersionTuple " << getUpperName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDeclarations(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "VersionTuple " << getLowerName() << ";\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadDecls(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " VersionTuple " << getLowerName()
|
2017-01-24 09:04:30 +08:00
|
|
|
<< "= Record.readVersionTuple();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHReadArgs(raw_ostream &OS) const override {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << getLowerName();
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2016-04-07 01:06:00 +08:00
|
|
|
OS << " Record.AddVersionTuple(SA->get" << getUpperName() << "());\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeValue(raw_ostream &OS) const override {
|
2011-11-20 03:22:57 +08:00
|
|
|
OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
};
|
2012-01-21 06:37:06 +08:00
|
|
|
|
|
|
|
class ExprArgument : public SimpleArgument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
ExprArgument(const Record &Arg, StringRef Attr)
|
2012-01-21 06:37:06 +08:00
|
|
|
: SimpleArgument(Arg, Attr, "Expr *")
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeASTVisitorTraversal(raw_ostream &OS) const override {
|
2013-12-31 01:24:36 +08:00
|
|
|
OS << " if (!"
|
|
|
|
<< "getDerived().TraverseStmt(A->get" << getUpperName() << "()))\n";
|
|
|
|
OS << " return false;\n";
|
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "tempInst" << getUpperName();
|
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiation(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " " << getType() << " tempInst" << getUpperName() << ";\n";
|
|
|
|
OS << " {\n";
|
|
|
|
OS << " EnterExpressionEvaluationContext "
|
2017-04-02 05:30:49 +08:00
|
|
|
<< "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " ExprResult " << "Result = S.SubstExpr("
|
|
|
|
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
|
|
|
|
OS << " tempInst" << getUpperName() << " = "
|
2014-05-29 18:55:11 +08:00
|
|
|
<< "Result.getAs<Expr>();\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " }\n";
|
|
|
|
}
|
2013-01-08 01:53:08 +08:00
|
|
|
|
2014-03-11 11:39:26 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {}
|
2013-01-08 01:53:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDumpChildren(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " dumpStmt(SA->get" << getUpperName() << "());\n";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeHasChildren(raw_ostream &OS) const override { OS << "true"; }
|
2012-01-21 06:37:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class VariadicExprArgument : public VariadicArgument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
VariadicExprArgument(const Record &Arg, StringRef Attr)
|
2012-01-21 06:37:06 +08:00
|
|
|
: VariadicArgument(Arg, Attr, "Expr *")
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeASTVisitorTraversal(raw_ostream &OS) const override {
|
2013-12-31 01:24:36 +08:00
|
|
|
OS << " {\n";
|
|
|
|
OS << " " << getType() << " *I = A->" << getLowerName()
|
|
|
|
<< "_begin();\n";
|
|
|
|
OS << " " << getType() << " *E = A->" << getLowerName()
|
|
|
|
<< "_end();\n";
|
|
|
|
OS << " for (; I != E; ++I) {\n";
|
|
|
|
OS << " if (!getDerived().TraverseStmt(*I))\n";
|
|
|
|
OS << " return false;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << "tempInst" << getUpperName() << ", "
|
|
|
|
<< "A->" << getLowerName() << "_size()";
|
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiation(raw_ostream &OS) const override {
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " auto *tempInst" << getUpperName()
|
2012-01-21 06:37:06 +08:00
|
|
|
<< " = new (C, 16) " << getType()
|
|
|
|
<< "[A->" << getLowerName() << "_size()];\n";
|
|
|
|
OS << " {\n";
|
|
|
|
OS << " EnterExpressionEvaluationContext "
|
2017-04-02 05:30:49 +08:00
|
|
|
<< "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " " << getType() << " *TI = tempInst" << getUpperName()
|
|
|
|
<< ";\n";
|
|
|
|
OS << " " << getType() << " *I = A->" << getLowerName()
|
|
|
|
<< "_begin();\n";
|
|
|
|
OS << " " << getType() << " *E = A->" << getLowerName()
|
|
|
|
<< "_end();\n";
|
|
|
|
OS << " for (; I != E; ++I, ++TI) {\n";
|
|
|
|
OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
|
2014-05-29 18:55:11 +08:00
|
|
|
OS << " *TI = Result.getAs<Expr>();\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " }\n";
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
2013-01-08 01:53:08 +08:00
|
|
|
|
2014-03-11 11:39:26 +08:00
|
|
|
void writeDump(raw_ostream &OS) const override {}
|
2013-01-08 01:53:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeDumpChildren(raw_ostream &OS) const override {
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
|
|
|
|
<< "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
|
2014-10-31 05:02:37 +08:00
|
|
|
<< getLowerName() << "_end(); I != E; ++I)\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
OS << " dumpStmt(*I);\n";
|
2013-01-31 09:44:26 +08:00
|
|
|
}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeHasChildren(raw_ostream &OS) const override {
|
2013-01-31 09:44:26 +08:00
|
|
|
OS << "SA->" << getLowerName() << "_begin() != "
|
|
|
|
<< "SA->" << getLowerName() << "_end()";
|
2013-01-08 01:53:08 +08:00
|
|
|
}
|
2012-01-21 06:37:06 +08:00
|
|
|
};
|
2013-11-01 05:23:20 +08:00
|
|
|
|
2015-05-16 02:33:32 +08:00
|
|
|
class VariadicStringArgument : public VariadicArgument {
|
|
|
|
public:
|
|
|
|
VariadicStringArgument(const Record &Arg, StringRef Attr)
|
2016-02-14 02:11:49 +08:00
|
|
|
: VariadicArgument(Arg, Attr, "StringRef")
|
2015-05-16 02:33:32 +08:00
|
|
|
{}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2016-02-14 02:11:49 +08:00
|
|
|
void writeCtorBody(raw_ostream &OS) const override {
|
|
|
|
OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n"
|
|
|
|
" ++I) {\n"
|
|
|
|
" StringRef Ref = " << getUpperName() << "[I];\n"
|
|
|
|
" if (!Ref.empty()) {\n"
|
|
|
|
" char *Mem = new (Ctx, 1) char[Ref.size()];\n"
|
|
|
|
" std::memcpy(Mem, Ref.data(), Ref.size());\n"
|
|
|
|
" " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n"
|
|
|
|
" }\n"
|
2016-05-13 06:27:08 +08:00
|
|
|
" }\n";
|
2016-02-14 02:11:49 +08:00
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2015-05-16 02:33:32 +08:00
|
|
|
void writeValueImpl(raw_ostream &OS) const override {
|
|
|
|
OS << " OS << \"\\\"\" << Val << \"\\\"\";\n";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-01 05:23:20 +08:00
|
|
|
class TypeArgument : public SimpleArgument {
|
|
|
|
public:
|
2014-05-21 03:47:14 +08:00
|
|
|
TypeArgument(const Record &Arg, StringRef Attr)
|
2013-11-01 05:23:20 +08:00
|
|
|
: SimpleArgument(Arg, Attr, "TypeSourceInfo *")
|
|
|
|
{}
|
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeAccessors(raw_ostream &OS) const override {
|
2013-11-01 05:23:20 +08:00
|
|
|
OS << " QualType get" << getUpperName() << "() const {\n";
|
|
|
|
OS << " return " << getLowerName() << "->getType();\n";
|
|
|
|
OS << " }";
|
|
|
|
OS << " " << getType() << " get" << getUpperName() << "Loc() const {\n";
|
|
|
|
OS << " return " << getLowerName() << ";\n";
|
|
|
|
OS << " }";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
2013-11-01 05:23:20 +08:00
|
|
|
OS << "A->get" << getUpperName() << "Loc()";
|
|
|
|
}
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2014-03-06 23:09:50 +08:00
|
|
|
void writePCHWrite(raw_ostream &OS) const override {
|
2013-11-01 05:23:20 +08:00
|
|
|
OS << " " << WritePCHRecord(
|
|
|
|
getType(), "SA->get" + std::string(getUpperName()) + "Loc()");
|
|
|
|
}
|
|
|
|
};
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2015-10-07 07:40:43 +08:00
|
|
|
} // end anonymous namespace
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
static std::unique_ptr<Argument>
|
|
|
|
createArgument(const Record &Arg, StringRef Attr,
|
|
|
|
const Record *Search = nullptr) {
|
2011-10-06 21:03:08 +08:00
|
|
|
if (!Search)
|
|
|
|
Search = &Arg;
|
|
|
|
|
2014-08-09 07:59:38 +08:00
|
|
|
std::unique_ptr<Argument> Ptr;
|
2011-10-06 21:03:08 +08:00
|
|
|
llvm::StringRef ArgName = Search->getName();
|
|
|
|
|
2014-08-09 07:59:38 +08:00
|
|
|
if (ArgName == "AlignedArgument")
|
|
|
|
Ptr = llvm::make_unique<AlignedArgument>(Arg, Attr);
|
|
|
|
else if (ArgName == "EnumArgument")
|
|
|
|
Ptr = llvm::make_unique<EnumArgument>(Arg, Attr);
|
|
|
|
else if (ArgName == "ExprArgument")
|
|
|
|
Ptr = llvm::make_unique<ExprArgument>(Arg, Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "FunctionArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "IdentifierArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
|
2014-02-11 03:50:15 +08:00
|
|
|
else if (ArgName == "DefaultBoolArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<DefaultSimpleArgument>(
|
|
|
|
Arg, Attr, "bool", Arg.getValueAsBit("Default"));
|
|
|
|
else if (ArgName == "BoolArgument")
|
|
|
|
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "bool");
|
2013-11-21 08:28:23 +08:00
|
|
|
else if (ArgName == "DefaultIntArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<DefaultSimpleArgument>(
|
|
|
|
Arg, Attr, "int", Arg.getValueAsInt("Default"));
|
|
|
|
else if (ArgName == "IntArgument")
|
|
|
|
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "int");
|
|
|
|
else if (ArgName == "StringArgument")
|
|
|
|
Ptr = llvm::make_unique<StringArgument>(Arg, Attr);
|
|
|
|
else if (ArgName == "TypeArgument")
|
|
|
|
Ptr = llvm::make_unique<TypeArgument>(Arg, Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "UnsignedArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "VariadicUnsignedArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
|
2015-05-16 02:33:32 +08:00
|
|
|
else if (ArgName == "VariadicStringArgument")
|
|
|
|
Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr);
|
2013-10-05 05:28:06 +08:00
|
|
|
else if (ArgName == "VariadicEnumArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "VariadicExprArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
else if (ArgName == "VersionArgument")
|
2014-08-09 07:59:38 +08:00
|
|
|
Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
if (!Ptr) {
|
2013-11-21 08:28:23 +08:00
|
|
|
// Search in reverse order so that the most-derived type is handled first.
|
2016-01-19 03:52:54 +08:00
|
|
|
ArrayRef<std::pair<Record*, SMRange>> Bases = Search->getSuperClasses();
|
2016-06-23 08:15:04 +08:00
|
|
|
for (const auto &Base : llvm::reverse(Bases)) {
|
2016-01-19 03:52:54 +08:00
|
|
|
if ((Ptr = createArgument(Arg, Attr, Base.first)))
|
2011-10-06 21:03:08 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-09-10 07:33:17 +08:00
|
|
|
|
|
|
|
if (Ptr && Arg.getValueAsBit("Optional"))
|
|
|
|
Ptr->setOptional(true);
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
if (Ptr && Arg.getValueAsBit("Fake"))
|
|
|
|
Ptr->setFake(true);
|
|
|
|
|
2014-08-09 07:59:38 +08:00
|
|
|
return Ptr;
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2011-11-20 03:22:57 +08:00
|
|
|
static void writeAvailabilityValue(raw_ostream &OS) {
|
|
|
|
OS << "\" << getPlatform()->getName();\n"
|
2016-03-11 07:54:12 +08:00
|
|
|
<< " if (getStrict()) OS << \", strict\";\n"
|
2011-11-20 03:22:57 +08:00
|
|
|
<< " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n"
|
|
|
|
<< " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n"
|
|
|
|
<< " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n"
|
|
|
|
<< " if (getUnavailable()) OS << \", unavailable\";\n"
|
|
|
|
<< " OS << \"";
|
|
|
|
}
|
|
|
|
|
2016-03-17 02:50:49 +08:00
|
|
|
static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) {
|
|
|
|
OS << "\\\"\" << getMessage() << \"\\\"\";\n";
|
|
|
|
// Only GNU deprecated has an optional fixit argument at the second position.
|
|
|
|
if (Variety == "GNU")
|
|
|
|
OS << " if (!getReplacement().empty()) OS << \", \\\"\""
|
|
|
|
" << getReplacement() << \"\\\"\";\n";
|
|
|
|
OS << " OS << \"";
|
|
|
|
}
|
|
|
|
|
2013-12-27 02:30:57 +08:00
|
|
|
static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
2013-12-27 02:30:57 +08:00
|
|
|
|
|
|
|
OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n";
|
|
|
|
if (Spellings.empty()) {
|
|
|
|
OS << " return \"(No spelling)\";\n}\n\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << " switch (SpellingListIndex) {\n"
|
|
|
|
" default:\n"
|
|
|
|
" llvm_unreachable(\"Unknown attribute spelling!\");\n"
|
|
|
|
" return \"(No spelling)\";\n";
|
|
|
|
|
|
|
|
for (unsigned I = 0; I < Spellings.size(); ++I)
|
|
|
|
OS << " case " << I << ":\n"
|
2014-01-28 06:10:04 +08:00
|
|
|
" return \"" << Spellings[I].name() << "\";\n";
|
2013-12-27 02:30:57 +08:00
|
|
|
// End of the switch statement.
|
|
|
|
OS << " }\n";
|
|
|
|
// End of the getSpelling function.
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
static void
|
|
|
|
writePrettyPrintFunction(Record &R,
|
|
|
|
const std::vector<std::unique_ptr<Argument>> &Args,
|
|
|
|
raw_ostream &OS) {
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
2013-01-25 00:46:58 +08:00
|
|
|
|
|
|
|
OS << "void " << R.getName() << "Attr::printPretty("
|
|
|
|
<< "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
|
|
|
|
|
2014-06-14 01:57:25 +08:00
|
|
|
if (Spellings.empty()) {
|
2013-01-25 00:46:58 +08:00
|
|
|
OS << "}\n\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS <<
|
|
|
|
" switch (SpellingListIndex) {\n"
|
|
|
|
" default:\n"
|
|
|
|
" llvm_unreachable(\"Unknown attribute spelling!\");\n"
|
|
|
|
" break;\n";
|
|
|
|
|
|
|
|
for (unsigned I = 0; I < Spellings.size(); ++ I) {
|
|
|
|
llvm::SmallString<16> Prefix;
|
|
|
|
llvm::SmallString<8> Suffix;
|
|
|
|
// The actual spelling of the name and namespace (if applicable)
|
|
|
|
// of an attribute without considering prefix and suffix.
|
|
|
|
llvm::SmallString<64> Spelling;
|
2014-01-28 06:10:04 +08:00
|
|
|
std::string Name = Spellings[I].name();
|
|
|
|
std::string Variety = Spellings[I].variety();
|
2013-01-25 00:46:58 +08:00
|
|
|
|
|
|
|
if (Variety == "GNU") {
|
|
|
|
Prefix = " __attribute__((";
|
|
|
|
Suffix = "))";
|
|
|
|
} else if (Variety == "CXX11") {
|
|
|
|
Prefix = " [[";
|
|
|
|
Suffix = "]]";
|
2014-01-28 06:10:04 +08:00
|
|
|
std::string Namespace = Spellings[I].nameSpace();
|
2014-06-14 01:57:25 +08:00
|
|
|
if (!Namespace.empty()) {
|
2013-01-25 00:46:58 +08:00
|
|
|
Spelling += Namespace;
|
|
|
|
Spelling += "::";
|
|
|
|
}
|
|
|
|
} else if (Variety == "Declspec") {
|
|
|
|
Prefix = " __declspec(";
|
|
|
|
Suffix = ")";
|
2016-09-03 10:55:10 +08:00
|
|
|
} else if (Variety == "Microsoft") {
|
|
|
|
Prefix = "[";
|
|
|
|
Suffix = "]";
|
2013-01-29 09:24:26 +08:00
|
|
|
} else if (Variety == "Keyword") {
|
|
|
|
Prefix = " ";
|
|
|
|
Suffix = "";
|
2014-06-14 01:57:25 +08:00
|
|
|
} else if (Variety == "Pragma") {
|
|
|
|
Prefix = "#pragma ";
|
|
|
|
Suffix = "\n";
|
|
|
|
std::string Namespace = Spellings[I].nameSpace();
|
|
|
|
if (!Namespace.empty()) {
|
|
|
|
Spelling += Namespace;
|
|
|
|
Spelling += " ";
|
|
|
|
}
|
2013-01-25 00:46:58 +08:00
|
|
|
} else {
|
2013-01-29 09:24:26 +08:00
|
|
|
llvm_unreachable("Unknown attribute syntax variety!");
|
2013-01-25 00:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Spelling += Name;
|
|
|
|
|
|
|
|
OS <<
|
|
|
|
" case " << I << " : {\n"
|
2015-03-10 15:33:23 +08:00
|
|
|
" OS << \"" << Prefix << Spelling;
|
2013-01-25 00:46:58 +08:00
|
|
|
|
2014-06-14 01:57:25 +08:00
|
|
|
if (Variety == "Pragma") {
|
|
|
|
OS << " \";\n";
|
|
|
|
OS << " printPrettyPragma(OS, Policy);\n";
|
2015-10-12 14:59:48 +08:00
|
|
|
OS << " OS << \"\\n\";";
|
2014-06-14 01:57:25 +08:00
|
|
|
OS << " break;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Fake arguments aren't part of the parsed form and should not be
|
|
|
|
// pretty-printed.
|
2016-12-01 08:13:18 +08:00
|
|
|
bool hasNonFakeArgs = llvm::any_of(
|
|
|
|
Args, [](const std::unique_ptr<Argument> &A) { return !A->isFake(); });
|
2015-10-28 08:17:34 +08:00
|
|
|
|
2014-08-01 21:49:00 +08:00
|
|
|
// FIXME: always printing the parenthesis isn't the correct behavior for
|
|
|
|
// attributes which have optional arguments that were not provided. For
|
|
|
|
// instance: __attribute__((aligned)) will be pretty printed as
|
|
|
|
// __attribute__((aligned())). The logic should check whether there is only
|
|
|
|
// a single argument, and if it is optional, whether it has been provided.
|
2015-10-28 08:17:34 +08:00
|
|
|
if (hasNonFakeArgs)
|
2014-03-06 00:49:55 +08:00
|
|
|
OS << "(";
|
2013-01-25 00:46:58 +08:00
|
|
|
if (Spelling == "availability") {
|
|
|
|
writeAvailabilityValue(OS);
|
2016-03-17 02:50:49 +08:00
|
|
|
} else if (Spelling == "deprecated" || Spelling == "gnu::deprecated") {
|
|
|
|
writeDeprecatedAttrValue(OS, Variety);
|
2013-01-25 00:46:58 +08:00
|
|
|
} else {
|
2015-10-28 08:17:34 +08:00
|
|
|
unsigned index = 0;
|
|
|
|
for (const auto &arg : Args) {
|
|
|
|
if (arg->isFake()) continue;
|
|
|
|
if (index++) OS << ", ";
|
|
|
|
arg->writeValue(OS);
|
2013-01-25 00:46:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
if (hasNonFakeArgs)
|
2014-03-06 00:49:55 +08:00
|
|
|
OS << ")";
|
2015-03-10 15:33:23 +08:00
|
|
|
OS << Suffix + "\";\n";
|
2013-01-25 00:46:58 +08:00
|
|
|
|
|
|
|
OS <<
|
|
|
|
" break;\n"
|
|
|
|
" }\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// End of the switch statement.
|
|
|
|
OS << "}\n";
|
|
|
|
// End of the print function.
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
2013-02-01 09:19:17 +08:00
|
|
|
/// \brief Return the index of a spelling in a spelling list.
|
2014-01-28 06:10:04 +08:00
|
|
|
static unsigned
|
|
|
|
getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList,
|
|
|
|
const FlattenedSpelling &Spelling) {
|
2015-01-23 23:36:10 +08:00
|
|
|
assert(!SpellingList.empty() && "Spelling list is empty!");
|
2013-02-01 09:19:17 +08:00
|
|
|
|
|
|
|
for (unsigned Index = 0; Index < SpellingList.size(); ++Index) {
|
2014-01-28 06:10:04 +08:00
|
|
|
const FlattenedSpelling &S = SpellingList[Index];
|
|
|
|
if (S.variety() != Spelling.variety())
|
2013-02-01 09:19:17 +08:00
|
|
|
continue;
|
2014-01-28 06:10:04 +08:00
|
|
|
if (S.nameSpace() != Spelling.nameSpace())
|
2013-02-01 09:19:17 +08:00
|
|
|
continue;
|
2014-01-28 06:10:04 +08:00
|
|
|
if (S.name() != Spelling.name())
|
2013-02-01 09:19:17 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
return Index;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unknown spelling!");
|
|
|
|
}
|
|
|
|
|
2014-03-03 01:38:37 +08:00
|
|
|
static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) {
|
2013-02-01 09:19:17 +08:00
|
|
|
std::vector<Record*> Accessors = R.getValueAsListOfDefs("Accessors");
|
2016-12-01 08:13:18 +08:00
|
|
|
if (Accessors.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(R);
|
|
|
|
assert(!SpellingList.empty() &&
|
|
|
|
"Attribute with empty spelling list can't have accessors!");
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Accessor : Accessors) {
|
2013-02-01 09:19:17 +08:00
|
|
|
std::string Name = Accessor->getValueAsString("Name");
|
2016-12-01 08:13:18 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor);
|
2013-02-01 09:19:17 +08:00
|
|
|
|
|
|
|
OS << " bool " << Name << "() const { return SpellingListIndex == ";
|
|
|
|
for (unsigned Index = 0; Index < Spellings.size(); ++Index) {
|
2014-01-28 06:10:04 +08:00
|
|
|
OS << getSpellingListIndex(SpellingList, Spellings[Index]);
|
2016-12-01 08:13:18 +08:00
|
|
|
if (Index != Spellings.size() - 1)
|
2013-02-01 09:19:17 +08:00
|
|
|
OS << " ||\n SpellingListIndex == ";
|
|
|
|
else
|
|
|
|
OS << "; }\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
static bool
|
|
|
|
SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) {
|
2014-01-16 21:03:14 +08:00
|
|
|
assert(!Spellings.empty() && "An empty list of spellings was provided");
|
|
|
|
std::string FirstName = NormalizeNameForSpellingComparison(
|
2014-01-28 06:10:04 +08:00
|
|
|
Spellings.front().name());
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto &Spelling :
|
|
|
|
llvm::make_range(std::next(Spellings.begin()), Spellings.end())) {
|
|
|
|
std::string Name = NormalizeNameForSpellingComparison(Spelling.name());
|
2014-01-16 21:03:14 +08:00
|
|
|
if (Name != FirstName)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-25 05:32:49 +08:00
|
|
|
typedef std::map<unsigned, std::string> SemanticSpellingMap;
|
|
|
|
static std::string
|
2014-01-28 06:10:04 +08:00
|
|
|
CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings,
|
2014-01-25 05:32:49 +08:00
|
|
|
SemanticSpellingMap &Map) {
|
|
|
|
// The enumerants are automatically generated based on the variety,
|
|
|
|
// namespace (if present) and name for each attribute spelling. However,
|
|
|
|
// care is taken to avoid trampling on the reserved namespace due to
|
|
|
|
// underscores.
|
|
|
|
std::string Ret(" enum Spelling {\n");
|
|
|
|
std::set<std::string> Uniques;
|
|
|
|
unsigned Idx = 0;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) {
|
2014-01-28 06:10:04 +08:00
|
|
|
const FlattenedSpelling &S = *I;
|
2016-05-27 21:36:58 +08:00
|
|
|
const std::string &Variety = S.variety();
|
|
|
|
const std::string &Spelling = S.name();
|
|
|
|
const std::string &Namespace = S.nameSpace();
|
2016-05-13 06:27:08 +08:00
|
|
|
std::string EnumName;
|
2014-01-25 05:32:49 +08:00
|
|
|
|
|
|
|
EnumName += (Variety + "_");
|
|
|
|
if (!Namespace.empty())
|
|
|
|
EnumName += (NormalizeNameForSpellingComparison(Namespace).str() +
|
|
|
|
"_");
|
|
|
|
EnumName += NormalizeNameForSpellingComparison(Spelling);
|
|
|
|
|
|
|
|
// Even if the name is not unique, this spelling index corresponds to a
|
|
|
|
// particular enumerant name that we've calculated.
|
|
|
|
Map[Idx] = EnumName;
|
|
|
|
|
|
|
|
// Since we have been stripping underscores to avoid trampling on the
|
|
|
|
// reserved namespace, we may have inadvertently created duplicate
|
|
|
|
// enumerant names. These duplicates are not considered part of the
|
|
|
|
// semantic spelling, and can be elided.
|
|
|
|
if (Uniques.find(EnumName) != Uniques.end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Uniques.insert(EnumName);
|
|
|
|
if (I != Spellings.begin())
|
|
|
|
Ret += ",\n";
|
2015-03-11 01:19:18 +08:00
|
|
|
// Duplicate spellings are not considered part of the semantic spelling
|
|
|
|
// enumeration, but the spelling index and semantic spelling values are
|
|
|
|
// meant to be equivalent, so we must specify a concrete value for each
|
|
|
|
// enumerator.
|
|
|
|
Ret += " " + EnumName + " = " + llvm::utostr(Idx);
|
2014-01-25 05:32:49 +08:00
|
|
|
}
|
|
|
|
Ret += "\n };\n\n";
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteSemanticSpellingSwitch(const std::string &VarName,
|
|
|
|
const SemanticSpellingMap &Map,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
OS << " switch (" << VarName << ") {\n default: "
|
|
|
|
<< "llvm_unreachable(\"Unknown spelling list index\");\n";
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Map)
|
|
|
|
OS << " case " << I.first << ": return " << I.second << ";\n";
|
2014-01-25 05:32:49 +08:00
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
|
2014-01-30 06:13:45 +08:00
|
|
|
// Emits the LateParsed property for attributes.
|
|
|
|
static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n";
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
2014-03-03 01:38:37 +08:00
|
|
|
bool LateParsed = Attr->getValueAsBit("LateParsed");
|
2014-01-30 06:13:45 +08:00
|
|
|
|
|
|
|
if (LateParsed) {
|
2014-03-03 01:38:37 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
|
2014-01-30 06:13:45 +08:00
|
|
|
|
|
|
|
// FIXME: Handle non-GNU attributes
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Spellings) {
|
|
|
|
if (I.variety() != "GNU")
|
2014-01-30 06:13:45 +08:00
|
|
|
continue;
|
2014-03-03 01:38:37 +08:00
|
|
|
OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n";
|
2014-01-30 06:13:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
|
|
|
|
}
|
|
|
|
|
2016-12-01 08:13:18 +08:00
|
|
|
template <typename Fn>
|
|
|
|
static void forEachUniqueSpelling(const Record &Attr, Fn &&F) {
|
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
|
|
|
|
SmallDenseSet<StringRef, 8> Seen;
|
|
|
|
for (const FlattenedSpelling &S : Spellings) {
|
|
|
|
if (Seen.insert(S.name()).second)
|
|
|
|
F(S);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-30 06:13:45 +08:00
|
|
|
/// \brief Emits the first-argument-is-type property for attributes.
|
|
|
|
static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n";
|
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
2014-01-30 06:13:45 +08:00
|
|
|
// Determine whether the first argument is a type.
|
2014-03-03 01:38:37 +08:00
|
|
|
std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args");
|
2014-01-30 06:13:45 +08:00
|
|
|
if (Args.empty())
|
|
|
|
continue;
|
|
|
|
|
2016-01-19 03:52:54 +08:00
|
|
|
if (Args[0]->getSuperClasses().back().first->getName() != "TypeArgument")
|
2014-01-30 06:13:45 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// All these spellings take a single type argument.
|
2016-12-01 08:13:18 +08:00
|
|
|
forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) {
|
|
|
|
OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n";
|
|
|
|
});
|
2014-01-30 06:13:45 +08:00
|
|
|
}
|
|
|
|
OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Emits the parse-arguments-in-unevaluated-context property for
|
|
|
|
/// attributes.
|
|
|
|
static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n";
|
|
|
|
ParsedAttrMap Attrs = getParsedAttrList(Records);
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Attrs) {
|
|
|
|
const Record &Attr = *I.second;
|
2014-01-30 06:13:45 +08:00
|
|
|
|
|
|
|
if (!Attr.getValueAsBit("ParseArgumentsAsUnevaluated"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// All these spellings take are parsed unevaluated.
|
2016-12-01 08:13:18 +08:00
|
|
|
forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) {
|
|
|
|
OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n";
|
|
|
|
});
|
2014-01-30 06:13:45 +08:00
|
|
|
}
|
|
|
|
OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isIdentifierArgument(Record *Arg) {
|
|
|
|
return !Arg->getSuperClasses().empty() &&
|
2016-01-19 03:52:54 +08:00
|
|
|
llvm::StringSwitch<bool>(Arg->getSuperClasses().back().first->getName())
|
2014-01-30 06:13:45 +08:00
|
|
|
.Case("IdentifierArgument", true)
|
|
|
|
.Case("EnumArgument", true)
|
2014-12-20 00:42:04 +08:00
|
|
|
.Case("VariadicEnumArgument", true)
|
2014-01-30 06:13:45 +08:00
|
|
|
.Default(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emits the first-argument-is-identifier property for attributes.
|
|
|
|
static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n";
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
2014-01-30 06:13:45 +08:00
|
|
|
// Determine whether the first argument is an identifier.
|
2014-03-03 01:38:37 +08:00
|
|
|
std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args");
|
2014-01-30 06:13:45 +08:00
|
|
|
if (Args.empty() || !isIdentifierArgument(Args[0]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// All these spellings take an identifier argument.
|
2016-12-01 08:13:18 +08:00
|
|
|
forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) {
|
|
|
|
OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n";
|
|
|
|
});
|
2014-01-30 06:13:45 +08:00
|
|
|
}
|
|
|
|
OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n";
|
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
namespace clang {
|
|
|
|
|
|
|
|
// Emits the class definitions for attributes.
|
|
|
|
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute classes' definitions", OS);
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
|
|
|
|
OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
|
|
|
|
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2014-02-18 02:23:02 +08:00
|
|
|
|
|
|
|
// FIXME: Currently, documentation is generated as-needed due to the fact
|
|
|
|
// that there is no way to allow a generated project "reach into" the docs
|
|
|
|
// directory (for instance, it may be an out-of-tree build). However, we want
|
|
|
|
// to ensure that every attribute has a Documentation field, and produce an
|
|
|
|
// error if it has been neglected. Otherwise, the on-demand generation which
|
|
|
|
// happens server-side will fail. This code is ensuring that functionality,
|
|
|
|
// even though this Emitter doesn't technically need the documentation.
|
|
|
|
// When attribute documentation can be generated as part of the build
|
|
|
|
// itself, this code can be removed.
|
|
|
|
(void)R.getValueAsListOfDefs("Documentation");
|
2012-05-02 23:56:52 +08:00
|
|
|
|
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
|
2016-01-19 03:52:54 +08:00
|
|
|
ArrayRef<std::pair<Record *, SMRange>> Supers = R.getSuperClasses();
|
2013-07-30 09:44:15 +08:00
|
|
|
assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
|
|
|
|
std::string SuperName;
|
2016-06-23 08:15:04 +08:00
|
|
|
for (const auto &Super : llvm::reverse(Supers)) {
|
2016-01-19 03:52:54 +08:00
|
|
|
const Record *R = Super.first;
|
|
|
|
if (R->getName() != "TargetSpecificAttr" && SuperName.empty())
|
|
|
|
SuperName = R->getName();
|
2013-07-30 09:44:15 +08:00
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
|
|
|
|
|
|
|
|
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
2014-03-06 00:49:55 +08:00
|
|
|
std::vector<std::unique_ptr<Argument>> Args;
|
2011-10-06 21:03:08 +08:00
|
|
|
Args.reserve(ArgRecords.size());
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
bool HasOptArg = false;
|
|
|
|
bool HasFakeArg = false;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *ArgRecord : ArgRecords) {
|
2014-03-06 00:49:55 +08:00
|
|
|
Args.emplace_back(createArgument(*ArgRecord, R.getName()));
|
|
|
|
Args.back()->writeDeclarations(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "\n\n";
|
2015-10-28 08:17:34 +08:00
|
|
|
|
|
|
|
// For these purposes, fake takes priority over optional.
|
|
|
|
if (Args.back()->isFake()) {
|
|
|
|
HasFakeArg = true;
|
|
|
|
} else if (Args.back()->isOptional()) {
|
|
|
|
HasOptArg = true;
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2016-05-13 06:27:08 +08:00
|
|
|
OS << "public:\n";
|
2014-01-16 21:03:14 +08:00
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
2014-01-16 21:03:14 +08:00
|
|
|
|
|
|
|
// If there are zero or one spellings, all spelling-related functionality
|
|
|
|
// can be elided. If all of the spellings share the same name, the spelling
|
|
|
|
// functionality can also be elided.
|
|
|
|
bool ElideSpelling = (Spellings.size() <= 1) ||
|
|
|
|
SpellingNamesAreCommon(Spellings);
|
|
|
|
|
2014-01-25 05:32:49 +08:00
|
|
|
// This maps spelling index values to semantic Spelling enumerants.
|
|
|
|
SemanticSpellingMap SemanticToSyntacticMap;
|
|
|
|
|
|
|
|
if (!ElideSpelling)
|
|
|
|
OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
|
2014-01-16 21:03:14 +08:00
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Emit CreateImplicit factory methods.
|
|
|
|
auto emitCreateImplicit = [&](bool emitFake) {
|
|
|
|
OS << " static " << R.getName() << "Attr *CreateImplicit(";
|
|
|
|
OS << "ASTContext &Ctx";
|
|
|
|
if (!ElideSpelling)
|
|
|
|
OS << ", Spelling S";
|
|
|
|
for (auto const &ai : Args) {
|
|
|
|
if (ai->isFake() && !emitFake) continue;
|
|
|
|
OS << ", ";
|
|
|
|
ai->writeCtorParameters(OS);
|
|
|
|
}
|
|
|
|
OS << ", SourceRange Loc = SourceRange()";
|
|
|
|
OS << ") {\n";
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " auto *A = new (Ctx) " << R.getName();
|
2015-10-28 08:17:34 +08:00
|
|
|
OS << "Attr(Loc, Ctx, ";
|
|
|
|
for (auto const &ai : Args) {
|
|
|
|
if (ai->isFake() && !emitFake) continue;
|
|
|
|
ai->writeImplicitCtorArgs(OS);
|
|
|
|
OS << ", ";
|
|
|
|
}
|
|
|
|
OS << (ElideSpelling ? "0" : "S") << ");\n";
|
|
|
|
OS << " A->setImplicit(true);\n";
|
|
|
|
OS << " return A;\n }\n\n";
|
|
|
|
};
|
2013-01-25 00:46:58 +08:00
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Emit a CreateImplicit that takes all the arguments.
|
|
|
|
emitCreateImplicit(true);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Emit a CreateImplicit that takes all the non-fake arguments.
|
|
|
|
if (HasFakeArg) {
|
|
|
|
emitCreateImplicit(false);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Emit constructors.
|
|
|
|
auto emitCtor = [&](bool emitOpt, bool emitFake) {
|
|
|
|
auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) {
|
|
|
|
if (arg->isFake()) return emitFake;
|
|
|
|
if (arg->isOptional()) return emitOpt;
|
|
|
|
return true;
|
|
|
|
};
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2015-10-28 08:17:34 +08:00
|
|
|
if (!shouldEmitArg(ai)) continue;
|
|
|
|
OS << " , ";
|
|
|
|
ai->writeCtorParameters(OS);
|
|
|
|
OS << "\n";
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
OS << " , ";
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << "unsigned SI\n";
|
2013-09-10 07:33:17 +08:00
|
|
|
|
|
|
|
OS << " )\n";
|
2015-03-20 00:06:49 +08:00
|
|
|
OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, "
|
2016-05-13 06:27:08 +08:00
|
|
|
<< ( R.getValueAsBit("LateParsed") ? "true" : "false" ) << ", "
|
|
|
|
<< ( R.getValueAsBit("DuplicatesAllowedWhileMerging") ? "true" : "false" ) << ")\n";
|
2013-09-10 07:33:17 +08:00
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << " , ";
|
2015-10-28 08:17:34 +08:00
|
|
|
if (!shouldEmitArg(ai)) {
|
|
|
|
ai->writeCtorDefaultInitializers(OS);
|
|
|
|
} else {
|
|
|
|
ai->writeCtorInitializers(OS);
|
|
|
|
}
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << " {\n";
|
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2015-10-28 08:17:34 +08:00
|
|
|
if (!shouldEmitArg(ai)) continue;
|
|
|
|
ai->writeCtorBody(OS);
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
|
|
|
OS << " }\n\n";
|
2015-10-28 08:17:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Emit a constructor that includes all the arguments.
|
|
|
|
// This is necessary for cloning.
|
|
|
|
emitCtor(true, true);
|
|
|
|
|
|
|
|
// Emit a constructor that takes all the non-fake arguments.
|
|
|
|
if (HasFakeArg) {
|
|
|
|
emitCtor(true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit a constructor that takes all the non-fake, non-optional arguments.
|
|
|
|
if (HasOptArg) {
|
|
|
|
emitCtor(false, false);
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
|
|
|
|
2015-03-20 00:06:49 +08:00
|
|
|
OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
|
2014-03-11 14:22:39 +08:00
|
|
|
OS << " void printPretty(raw_ostream &OS,\n"
|
2015-03-20 00:06:49 +08:00
|
|
|
<< " const PrintingPolicy &Policy) const;\n";
|
|
|
|
OS << " const char *getSpelling() const;\n";
|
2014-01-25 05:32:49 +08:00
|
|
|
|
|
|
|
if (!ElideSpelling) {
|
|
|
|
assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list");
|
|
|
|
OS << " Spelling getSemanticSpelling() const {\n";
|
|
|
|
WriteSemanticSpellingSwitch("SpellingListIndex", SemanticToSyntacticMap,
|
|
|
|
OS);
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2013-02-01 09:19:17 +08:00
|
|
|
writeAttrAccessorDefinition(R, OS);
|
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2014-03-03 01:38:37 +08:00
|
|
|
ai->writeAccessors(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "\n\n";
|
2013-09-12 03:47:58 +08:00
|
|
|
|
2015-10-28 08:17:34 +08:00
|
|
|
// Don't write conversion routines for fake arguments.
|
|
|
|
if (ai->isFake()) continue;
|
|
|
|
|
2014-03-03 01:38:37 +08:00
|
|
|
if (ai->isEnumArg())
|
2014-03-06 00:49:55 +08:00
|
|
|
static_cast<const EnumArgument *>(ai.get())->writeConversion(OS);
|
2014-03-03 01:38:37 +08:00
|
|
|
else if (ai->isVariadicEnumArg())
|
2014-03-06 00:49:55 +08:00
|
|
|
static_cast<const VariadicEnumArgument *>(ai.get())
|
|
|
|
->writeConversion(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2012-01-13 12:57:47 +08:00
|
|
|
OS << R.getValueAsString("AdditionalMembers");
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "\n\n";
|
|
|
|
|
|
|
|
OS << " static bool classof(const Attr *A) { return A->getKind() == "
|
|
|
|
<< "attr::" << R.getName() << "; }\n";
|
2012-01-21 06:50:54 +08:00
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << "};\n\n";
|
|
|
|
}
|
|
|
|
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
// Emits the class method definitions for attributes.
|
|
|
|
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute classes' member function definitions", OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (auto *Attr : Attrs) {
|
|
|
|
Record &R = *Attr;
|
2012-05-02 23:56:52 +08:00
|
|
|
|
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
2014-03-06 00:49:55 +08:00
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
2014-03-06 00:49:55 +08:00
|
|
|
std::vector<std::unique_ptr<Argument>> Args;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : ArgRecords)
|
|
|
|
Args.emplace_back(createArgument(*Arg, R.getName()));
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args)
|
2014-03-03 01:38:37 +08:00
|
|
|
ai->writeAccessorDefinitions(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
OS << R.getName() << "Attr *" << R.getName()
|
|
|
|
<< "Attr::clone(ASTContext &C) const {\n";
|
2014-05-31 09:30:30 +08:00
|
|
|
OS << " auto *A = new (C) " << R.getName() << "Attr(getLocation(), C";
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << ", ";
|
2014-03-03 01:38:37 +08:00
|
|
|
ai->writeCloneArgs(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2014-05-31 09:30:30 +08:00
|
|
|
OS << ", getSpellingListIndex());\n";
|
|
|
|
OS << " A->Inherited = Inherited;\n";
|
|
|
|
OS << " A->IsPackExpansion = IsPackExpansion;\n";
|
|
|
|
OS << " A->Implicit = Implicit;\n";
|
|
|
|
OS << " return A;\n}\n\n";
|
2011-11-20 03:22:57 +08:00
|
|
|
|
2013-01-25 00:46:58 +08:00
|
|
|
writePrettyPrintFunction(R, Args, OS);
|
2013-12-27 02:30:57 +08:00
|
|
|
writeGetSpellingFunction(R, OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2015-03-20 00:06:49 +08:00
|
|
|
|
|
|
|
// Instead of relying on virtual dispatch we just create a huge dispatch
|
|
|
|
// switch. This is both smaller and faster than virtual functions.
|
|
|
|
auto EmitFunc = [&](const char *Method) {
|
|
|
|
OS << " switch (getKind()) {\n";
|
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
OS << " case attr::" << R.getName() << ":\n";
|
|
|
|
OS << " return cast<" << R.getName() << "Attr>(this)->" << Method
|
|
|
|
<< ";\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
};
|
|
|
|
|
|
|
|
OS << "const char *Attr::getSpelling() const {\n";
|
|
|
|
EmitFunc("getSpelling()");
|
|
|
|
|
|
|
|
OS << "Attr *Attr::clone(ASTContext &C) const {\n";
|
|
|
|
EmitFunc("clone(C)");
|
|
|
|
|
|
|
|
OS << "void Attr::printPretty(raw_ostream &OS, "
|
|
|
|
"const PrintingPolicy &Policy) const {\n";
|
|
|
|
EmitFunc("printPretty(OS, Policy)");
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
} // end namespace clang
|
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
static void emitAttrList(raw_ostream &OS, StringRef Class,
|
2011-10-06 21:03:08 +08:00
|
|
|
const std::vector<Record*> &AttrList) {
|
2016-03-01 08:18:05 +08:00
|
|
|
for (auto Cur : AttrList) {
|
|
|
|
OS << Class << "(" << Cur->getName() << ")\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-13 04:46:07 +08:00
|
|
|
// Determines if an attribute has a Pragma spelling.
|
|
|
|
static bool AttrHasPragmaSpelling(const Record *R) {
|
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
|
2016-12-01 08:13:18 +08:00
|
|
|
return llvm::find_if(Spellings, [](const FlattenedSpelling &S) {
|
2014-10-13 04:46:07 +08:00
|
|
|
return S.variety() == "Pragma";
|
|
|
|
}) != Spellings.end();
|
|
|
|
}
|
2012-06-13 13:12:41 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
namespace {
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
struct AttrClassDescriptor {
|
|
|
|
const char * const MacroName;
|
|
|
|
const char * const TableGenName;
|
|
|
|
};
|
2016-05-13 06:27:08 +08:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
static const AttrClassDescriptor AttrClassDescriptors[] = {
|
|
|
|
{ "ATTR", "Attr" },
|
2016-03-08 08:32:55 +08:00
|
|
|
{ "STMT_ATTR", "StmtAttr" },
|
2016-03-01 08:18:05 +08:00
|
|
|
{ "INHERITABLE_ATTR", "InheritableAttr" },
|
2016-03-03 14:39:32 +08:00
|
|
|
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
|
|
|
|
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
|
2016-03-01 08:18:05 +08:00
|
|
|
};
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
static void emitDefaultDefine(raw_ostream &OS, StringRef name,
|
|
|
|
const char *superName) {
|
|
|
|
OS << "#ifndef " << name << "\n";
|
|
|
|
OS << "#define " << name << "(NAME) ";
|
|
|
|
if (superName) OS << superName << "(NAME)";
|
|
|
|
OS << "\n#endif\n\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
namespace {
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
/// A class of attributes.
|
|
|
|
struct AttrClass {
|
|
|
|
const AttrClassDescriptor &Descriptor;
|
|
|
|
Record *TheRecord;
|
|
|
|
AttrClass *SuperClass = nullptr;
|
|
|
|
std::vector<AttrClass*> SubClasses;
|
|
|
|
std::vector<Record*> Attrs;
|
|
|
|
|
|
|
|
AttrClass(const AttrClassDescriptor &Descriptor, Record *R)
|
|
|
|
: Descriptor(Descriptor), TheRecord(R) {}
|
|
|
|
|
|
|
|
void emitDefaultDefines(raw_ostream &OS) const {
|
|
|
|
// Default the macro unless this is a root class (i.e. Attr).
|
|
|
|
if (SuperClass) {
|
|
|
|
emitDefaultDefine(OS, Descriptor.MacroName,
|
|
|
|
SuperClass->Descriptor.MacroName);
|
|
|
|
}
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
void emitUndefs(raw_ostream &OS) const {
|
|
|
|
OS << "#undef " << Descriptor.MacroName << "\n";
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
void emitAttrList(raw_ostream &OS) const {
|
|
|
|
for (auto SubClass : SubClasses) {
|
|
|
|
SubClass->emitAttrList(OS);
|
|
|
|
}
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
::emitAttrList(OS, Descriptor.MacroName, Attrs);
|
|
|
|
}
|
2014-10-13 04:46:07 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
void classifyAttrOnRoot(Record *Attr) {
|
|
|
|
bool result = classifyAttr(Attr);
|
|
|
|
assert(result && "failed to classify on root"); (void) result;
|
|
|
|
}
|
2014-10-13 04:46:07 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
void emitAttrRange(raw_ostream &OS) const {
|
|
|
|
OS << "ATTR_RANGE(" << Descriptor.TableGenName
|
|
|
|
<< ", " << getFirstAttr()->getName()
|
|
|
|
<< ", " << getLastAttr()->getName() << ")\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool classifyAttr(Record *Attr) {
|
|
|
|
// Check all the subclasses.
|
|
|
|
for (auto SubClass : SubClasses) {
|
|
|
|
if (SubClass->classifyAttr(Attr))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// It's not more specific than this class, but it might still belong here.
|
|
|
|
if (Attr->isSubClassOf(TheRecord)) {
|
|
|
|
Attrs.push_back(Attr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Record *getFirstAttr() const {
|
|
|
|
if (!SubClasses.empty())
|
|
|
|
return SubClasses.front()->getFirstAttr();
|
|
|
|
return Attrs.front();
|
|
|
|
}
|
|
|
|
|
|
|
|
Record *getLastAttr() const {
|
|
|
|
if (!Attrs.empty())
|
|
|
|
return Attrs.back();
|
|
|
|
return SubClasses.back()->getLastAttr();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// The entire hierarchy of attribute classes.
|
|
|
|
class AttrClassHierarchy {
|
|
|
|
std::vector<std::unique_ptr<AttrClass>> Classes;
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
public:
|
|
|
|
AttrClassHierarchy(RecordKeeper &Records) {
|
|
|
|
// Find records for all the classes.
|
|
|
|
for (auto &Descriptor : AttrClassDescriptors) {
|
|
|
|
Record *ClassRecord = Records.getClass(Descriptor.TableGenName);
|
|
|
|
AttrClass *Class = new AttrClass(Descriptor, ClassRecord);
|
|
|
|
Classes.emplace_back(Class);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link up the hierarchy.
|
|
|
|
for (auto &Class : Classes) {
|
|
|
|
if (AttrClass *SuperClass = findSuperClass(Class->TheRecord)) {
|
|
|
|
Class->SuperClass = SuperClass;
|
|
|
|
SuperClass->SubClasses.push_back(Class.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (auto i = Classes.begin(), e = Classes.end(); i != e; ++i) {
|
|
|
|
assert((i == Classes.begin()) == ((*i)->SuperClass == nullptr) &&
|
|
|
|
"only the first class should be a root class!");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void emitDefaultDefines(raw_ostream &OS) const {
|
|
|
|
for (auto &Class : Classes) {
|
|
|
|
Class->emitDefaultDefines(OS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void emitUndefs(raw_ostream &OS) const {
|
|
|
|
for (auto &Class : Classes) {
|
|
|
|
Class->emitUndefs(OS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void emitAttrLists(raw_ostream &OS) const {
|
|
|
|
// Just start from the root class.
|
|
|
|
Classes[0]->emitAttrList(OS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void emitAttrRanges(raw_ostream &OS) const {
|
|
|
|
for (auto &Class : Classes)
|
|
|
|
Class->emitAttrRange(OS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void classifyAttr(Record *Attr) {
|
|
|
|
// Add the attribute to the root class.
|
|
|
|
Classes[0]->classifyAttrOnRoot(Attr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
AttrClass *findClassByRecord(Record *R) const {
|
|
|
|
for (auto &Class : Classes) {
|
|
|
|
if (Class->TheRecord == R)
|
|
|
|
return Class.get();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AttrClass *findSuperClass(Record *R) const {
|
|
|
|
// TableGen flattens the superclass list, so we just need to walk it
|
|
|
|
// in reverse.
|
|
|
|
auto SuperClasses = R->getSuperClasses();
|
|
|
|
for (signed i = 0, e = SuperClasses.size(); i != e; ++i) {
|
|
|
|
auto SuperClass = findClassByRecord(SuperClasses[e - i - 1].first);
|
|
|
|
if (SuperClass) return SuperClass;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
2016-05-13 06:27:08 +08:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2016-03-01 08:18:05 +08:00
|
|
|
|
|
|
|
namespace clang {
|
2016-05-13 06:27:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
// Emits the enumeration list for attributes.
|
|
|
|
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
|
|
|
|
|
|
|
|
AttrClassHierarchy Hierarchy(Records);
|
|
|
|
|
|
|
|
// Add defaulting macro definitions.
|
|
|
|
Hierarchy.emitDefaultDefines(OS);
|
|
|
|
emitDefaultDefine(OS, "PRAGMA_SPELLING_ATTR", nullptr);
|
|
|
|
|
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
std::vector<Record *> PragmaAttrs;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (auto *Attr : Attrs) {
|
|
|
|
if (!Attr->getValueAsBit("ASTNode"))
|
2012-05-02 23:56:52 +08:00
|
|
|
continue;
|
2014-10-13 04:46:07 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
// Add the attribute to the ad-hoc groups.
|
2014-10-13 04:46:07 +08:00
|
|
|
if (AttrHasPragmaSpelling(Attr))
|
|
|
|
PragmaAttrs.push_back(Attr);
|
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
// Place it in the hierarchy.
|
|
|
|
Hierarchy.classifyAttr(Attr);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
// Emit the main attribute list.
|
|
|
|
Hierarchy.emitAttrLists(OS);
|
|
|
|
|
|
|
|
// Emit the ad hoc groups.
|
|
|
|
emitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
// Emit the attribute ranges.
|
|
|
|
OS << "#ifdef ATTR_RANGE\n";
|
|
|
|
Hierarchy.emitAttrRanges(OS);
|
|
|
|
OS << "#undef ATTR_RANGE\n";
|
|
|
|
OS << "#endif\n";
|
|
|
|
|
|
|
|
Hierarchy.emitUndefs(OS);
|
2014-10-13 04:46:07 +08:00
|
|
|
OS << "#undef PRAGMA_SPELLING_ATTR\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
// Emits the code to read an attribute from a precompiled header.
|
|
|
|
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute deserialization code", OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
Record *InhClass = Records.getClass("InheritableAttr");
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
|
|
|
|
ArgRecords;
|
2014-03-06 00:49:55 +08:00
|
|
|
std::vector<std::unique_ptr<Argument>> Args;
|
2011-10-06 21:03:08 +08:00
|
|
|
|
|
|
|
OS << " switch (Kind) {\n";
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2012-05-02 23:56:52 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " case attr::" << R.getName() << ": {\n";
|
|
|
|
if (R.isSubClassOf(InhClass))
|
2017-01-24 09:04:30 +08:00
|
|
|
OS << " bool isInherited = Record.readInt();\n";
|
|
|
|
OS << " bool isImplicit = Record.readInt();\n";
|
|
|
|
OS << " unsigned Spelling = Record.readInt();\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
ArgRecords = R.getValueAsListOfDefs("Args");
|
|
|
|
Args.clear();
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : ArgRecords) {
|
|
|
|
Args.emplace_back(createArgument(*Arg, R.getName()));
|
2014-03-06 00:49:55 +08:00
|
|
|
Args.back()->writePCHReadDecls(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
OS << " New = new (Context) " << R.getName() << "Attr(Range, Context";
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ri : Args) {
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << ", ";
|
2014-03-03 01:38:37 +08:00
|
|
|
ri->writePCHReadArgs(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << ", Spelling);\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
if (R.isSubClassOf(InhClass))
|
|
|
|
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << " New->setImplicit(isImplicit);\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " break;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
// Emits the code to write an attribute to a precompiled header.
|
|
|
|
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute serialization code", OS);
|
|
|
|
|
2011-10-06 21:03:08 +08:00
|
|
|
Record *InhClass = Records.getClass("InheritableAttr");
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
|
|
|
|
|
|
|
|
OS << " switch (A->getKind()) {\n";
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2012-05-02 23:56:52 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " case attr::" << R.getName() << ": {\n";
|
|
|
|
Args = R.getValueAsListOfDefs("Args");
|
|
|
|
if (R.isSubClassOf(InhClass) || !Args.empty())
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " const auto *SA = cast<" << R.getName()
|
2011-10-06 21:03:08 +08:00
|
|
|
<< "Attr>(A);\n";
|
|
|
|
if (R.isSubClassOf(InhClass))
|
|
|
|
OS << " Record.push_back(SA->isInherited());\n";
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << " Record.push_back(A->isImplicit());\n";
|
|
|
|
OS << " Record.push_back(A->getSpellingListIndex());\n";
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : Args)
|
|
|
|
createArgument(*Arg, R.getName())->writePCHWrite(OS);
|
2011-10-06 21:03:08 +08:00
|
|
|
OS << " break;\n";
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
|
2015-07-21 06:57:36 +08:00
|
|
|
// Generate a conditional expression to check if the current target satisfies
|
|
|
|
// the conditions for a TargetSpecificAttr record, and append the code for
|
|
|
|
// those checks to the Test string. If the FnName string pointer is non-null,
|
|
|
|
// append a unique suffix to distinguish this set of target checks from other
|
|
|
|
// TargetSpecificAttr records.
|
|
|
|
static void GenerateTargetSpecificAttrChecks(const Record *R,
|
|
|
|
std::vector<std::string> &Arches,
|
|
|
|
std::string &Test,
|
|
|
|
std::string *FnName) {
|
|
|
|
// It is assumed that there will be an llvm::Triple object
|
|
|
|
// named "T" and a TargetInfo object named "Target" within
|
|
|
|
// scope that can be used to determine whether the attribute exists in
|
|
|
|
// a given target.
|
|
|
|
Test += "(";
|
|
|
|
|
|
|
|
for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) {
|
|
|
|
std::string Part = *I;
|
|
|
|
Test += "T.getArch() == llvm::Triple::" + Part;
|
|
|
|
if (I + 1 != E)
|
|
|
|
Test += " || ";
|
|
|
|
if (FnName)
|
|
|
|
*FnName += Part;
|
|
|
|
}
|
|
|
|
Test += ")";
|
|
|
|
|
|
|
|
// If the attribute is specific to particular OSes, check those.
|
|
|
|
if (!R->isValueUnset("OSes")) {
|
|
|
|
// We know that there was at least one arch test, so we need to and in the
|
|
|
|
// OS tests.
|
|
|
|
Test += " && (";
|
|
|
|
std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes");
|
|
|
|
for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) {
|
|
|
|
std::string Part = *I;
|
|
|
|
|
|
|
|
Test += "T.getOS() == llvm::Triple::" + Part;
|
|
|
|
if (I + 1 != E)
|
|
|
|
Test += " || ";
|
|
|
|
if (FnName)
|
|
|
|
*FnName += Part;
|
|
|
|
}
|
|
|
|
Test += ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
// If one or more CXX ABIs are specified, check those as well.
|
|
|
|
if (!R->isValueUnset("CXXABIs")) {
|
|
|
|
Test += " && (";
|
|
|
|
std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
|
|
|
|
for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) {
|
|
|
|
std::string Part = *I;
|
|
|
|
Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
|
|
|
|
if (I + 1 != E)
|
|
|
|
Test += " || ";
|
|
|
|
if (FnName)
|
|
|
|
*FnName += Part;
|
|
|
|
}
|
|
|
|
Test += ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-31 21:14:44 +08:00
|
|
|
static void GenerateHasAttrSpellingStringSwitch(
|
|
|
|
const std::vector<Record *> &Attrs, raw_ostream &OS,
|
|
|
|
const std::string &Variety = "", const std::string &Scope = "") {
|
|
|
|
for (const auto *Attr : Attrs) {
|
2014-11-14 21:44:02 +08:00
|
|
|
// C++11-style attributes have specific version information associated with
|
|
|
|
// them. If the attribute has no scope, the version information must not
|
|
|
|
// have the default value (1), as that's incorrect. Instead, the unscoped
|
|
|
|
// attribute version information should be taken from the SD-6 standing
|
|
|
|
// document, which can be found at:
|
|
|
|
// https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
|
|
|
|
int Version = 1;
|
|
|
|
|
|
|
|
if (Variety == "CXX11") {
|
|
|
|
std::vector<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings");
|
|
|
|
for (const auto &Spelling : Spellings) {
|
|
|
|
if (Spelling->getValueAsString("Variety") == "CXX11") {
|
|
|
|
Version = static_cast<int>(Spelling->getValueAsInt("Version"));
|
|
|
|
if (Scope.empty() && Version == 1)
|
|
|
|
PrintError(Spelling->getLoc(), "C++ standard attributes must "
|
|
|
|
"have valid version information.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-10 06:57:44 +08:00
|
|
|
std::string Test;
|
2014-03-31 21:14:44 +08:00
|
|
|
if (Attr->isSubClassOf("TargetSpecificAttr")) {
|
|
|
|
const Record *R = Attr->getValueAsDef("Target");
|
2014-01-10 06:57:44 +08:00
|
|
|
std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
|
2015-10-07 07:40:43 +08:00
|
|
|
GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr);
|
2015-07-21 06:57:31 +08:00
|
|
|
|
2014-03-31 21:14:44 +08:00
|
|
|
// If this is the C++11 variety, also add in the LangOpts test.
|
|
|
|
if (Variety == "CXX11")
|
|
|
|
Test += " && LangOpts.CPlusPlus11";
|
|
|
|
} else if (Variety == "CXX11")
|
|
|
|
// C++11 mode should be checked against LangOpts, which is presumed to be
|
|
|
|
// present in the caller.
|
|
|
|
Test = "LangOpts.CPlusPlus11";
|
2011-10-06 21:03:08 +08:00
|
|
|
|
2014-11-14 21:44:02 +08:00
|
|
|
std::string TestStr =
|
2014-11-18 02:17:19 +08:00
|
|
|
!Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
|
2014-03-31 21:14:44 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &S : Spellings)
|
2014-03-31 21:14:44 +08:00
|
|
|
if (Variety.empty() || (Variety == S.variety() &&
|
|
|
|
(Scope.empty() || Scope == S.nameSpace())))
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " .Default(0);\n";
|
2014-03-31 21:14:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emits the list of spellings for attributes.
|
|
|
|
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Code to implement the __has_attribute logic", OS);
|
|
|
|
|
|
|
|
// Separate all of the attributes out into four group: generic, C++11, GNU,
|
|
|
|
// and declspecs. Then generate a big switch statement for each of them.
|
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
2016-09-03 10:55:10 +08:00
|
|
|
std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
|
2014-03-31 21:14:44 +08:00
|
|
|
std::map<std::string, std::vector<Record *>> CXX;
|
|
|
|
|
|
|
|
// Walk over the list of all attributes, and split them out based on the
|
|
|
|
// spelling variety.
|
|
|
|
for (auto *R : Attrs) {
|
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
|
|
|
|
for (const auto &SI : Spellings) {
|
2016-05-27 21:36:58 +08:00
|
|
|
const std::string &Variety = SI.variety();
|
2014-03-31 21:14:44 +08:00
|
|
|
if (Variety == "GNU")
|
|
|
|
GNU.push_back(R);
|
|
|
|
else if (Variety == "Declspec")
|
|
|
|
Declspec.push_back(R);
|
2016-09-03 10:55:10 +08:00
|
|
|
else if (Variety == "Microsoft")
|
|
|
|
Microsoft.push_back(R);
|
2014-06-14 01:57:25 +08:00
|
|
|
else if (Variety == "CXX11")
|
2014-03-31 21:14:44 +08:00
|
|
|
CXX[SI.nameSpace()].push_back(R);
|
2014-06-14 01:57:25 +08:00
|
|
|
else if (Variety == "Pragma")
|
|
|
|
Pragma.push_back(R);
|
2014-03-31 21:14:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-21 06:57:31 +08:00
|
|
|
OS << "const llvm::Triple &T = Target.getTriple();\n";
|
2014-03-31 21:14:44 +08:00
|
|
|
OS << "switch (Syntax) {\n";
|
|
|
|
OS << "case AttrSyntax::GNU:\n";
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " return llvm::StringSwitch<int>(Name)\n";
|
2014-03-31 21:14:44 +08:00
|
|
|
GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU");
|
|
|
|
OS << "case AttrSyntax::Declspec:\n";
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " return llvm::StringSwitch<int>(Name)\n";
|
2014-03-31 21:14:44 +08:00
|
|
|
GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
|
2016-09-03 10:55:10 +08:00
|
|
|
OS << "case AttrSyntax::Microsoft:\n";
|
|
|
|
OS << " return llvm::StringSwitch<int>(Name)\n";
|
|
|
|
GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft");
|
2014-06-14 01:57:25 +08:00
|
|
|
OS << "case AttrSyntax::Pragma:\n";
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " return llvm::StringSwitch<int>(Name)\n";
|
2014-06-14 01:57:25 +08:00
|
|
|
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
|
2014-03-31 21:14:44 +08:00
|
|
|
OS << "case AttrSyntax::CXX: {\n";
|
|
|
|
// C++11-style attributes are further split out based on the Scope.
|
2015-12-09 02:49:01 +08:00
|
|
|
for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) {
|
2014-03-31 21:14:44 +08:00
|
|
|
if (I != CXX.begin())
|
|
|
|
OS << " else ";
|
|
|
|
if (I->first.empty())
|
|
|
|
OS << "if (!Scope || Scope->getName() == \"\") {\n";
|
|
|
|
else
|
|
|
|
OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
|
2014-11-14 21:44:02 +08:00
|
|
|
OS << " return llvm::StringSwitch<int>(Name)\n";
|
2014-03-31 21:14:44 +08:00
|
|
|
GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
|
|
|
|
OS << "}";
|
|
|
|
}
|
|
|
|
OS << "\n}\n";
|
|
|
|
OS << "}\n";
|
2011-10-06 21:03:08 +08:00
|
|
|
}
|
|
|
|
|
2013-01-25 00:46:58 +08:00
|
|
|
void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Code to translate different attribute spellings "
|
|
|
|
"into internal identifiers", OS);
|
2013-01-25 00:46:58 +08:00
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
OS << " switch (AttrKind) {\n";
|
2013-01-25 00:46:58 +08:00
|
|
|
|
2013-12-15 21:05:48 +08:00
|
|
|
ParsedAttrMap Attrs = getParsedAttrList(Records);
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Attrs) {
|
2014-05-21 03:47:14 +08:00
|
|
|
const Record &R = *I.second;
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
2014-03-03 01:38:37 +08:00
|
|
|
OS << " case AT_" << I.first << ": {\n";
|
2013-11-27 09:46:48 +08:00
|
|
|
for (unsigned I = 0; I < Spellings.size(); ++ I) {
|
2014-06-14 01:57:25 +08:00
|
|
|
OS << " if (Name == \"" << Spellings[I].name() << "\" && "
|
|
|
|
<< "SyntaxUsed == "
|
|
|
|
<< StringSwitch<unsigned>(Spellings[I].variety())
|
|
|
|
.Case("GNU", 0)
|
|
|
|
.Case("CXX11", 1)
|
|
|
|
.Case("Declspec", 2)
|
2016-09-03 10:55:10 +08:00
|
|
|
.Case("Microsoft", 3)
|
|
|
|
.Case("Keyword", 4)
|
|
|
|
.Case("Pragma", 5)
|
2014-06-14 01:57:25 +08:00
|
|
|
.Default(0)
|
|
|
|
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
|
|
|
|
<< " return " << I << ";\n";
|
2013-01-25 00:46:58 +08:00
|
|
|
}
|
2013-11-27 09:46:48 +08:00
|
|
|
|
|
|
|
OS << " break;\n";
|
|
|
|
OS << " }\n";
|
2013-01-25 00:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
OS << " }\n";
|
2013-12-15 21:05:48 +08:00
|
|
|
OS << " return 0;\n";
|
2013-01-25 00:46:58 +08:00
|
|
|
}
|
|
|
|
|
2013-12-31 01:24:36 +08:00
|
|
|
// Emits code used by RecursiveASTVisitor to visit attributes
|
|
|
|
void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS);
|
|
|
|
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
|
|
|
// Write method declarations for Traverse* methods.
|
|
|
|
// We emit this here because we only generate methods for attributes that
|
|
|
|
// are declared as ASTNodes.
|
|
|
|
OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n";
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2013-12-31 01:24:36 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
OS << " bool Traverse"
|
|
|
|
<< R.getName() << "Attr(" << R.getName() << "Attr *A);\n";
|
|
|
|
OS << " bool Visit"
|
|
|
|
<< R.getName() << "Attr(" << R.getName() << "Attr *A) {\n"
|
|
|
|
<< " return true; \n"
|
2015-07-23 04:46:26 +08:00
|
|
|
<< " }\n";
|
2013-12-31 01:24:36 +08:00
|
|
|
}
|
|
|
|
OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n";
|
|
|
|
|
|
|
|
// Write individual Traverse* methods for each attribute class.
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2013-12-31 01:24:36 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
OS << "template <typename Derived>\n"
|
2013-12-31 05:03:02 +08:00
|
|
|
<< "bool VISITORCLASS<Derived>::Traverse"
|
2013-12-31 01:24:36 +08:00
|
|
|
<< R.getName() << "Attr(" << R.getName() << "Attr *A) {\n"
|
|
|
|
<< " if (!getDerived().VisitAttr(A))\n"
|
|
|
|
<< " return false;\n"
|
|
|
|
<< " if (!getDerived().Visit" << R.getName() << "Attr(A))\n"
|
|
|
|
<< " return false;\n";
|
|
|
|
|
|
|
|
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : ArgRecords)
|
|
|
|
createArgument(*Arg, R.getName())->writeASTVisitorTraversal(OS);
|
2013-12-31 01:24:36 +08:00
|
|
|
|
|
|
|
OS << " return true;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write generic Traverse routine
|
|
|
|
OS << "template <typename Derived>\n"
|
2013-12-31 05:03:02 +08:00
|
|
|
<< "bool VISITORCLASS<Derived>::TraverseAttr(Attr *A) {\n"
|
2013-12-31 01:24:36 +08:00
|
|
|
<< " if (!A)\n"
|
|
|
|
<< " return true;\n"
|
|
|
|
<< "\n"
|
2016-03-01 08:18:05 +08:00
|
|
|
<< " switch (A->getKind()) {\n";
|
2013-12-31 01:24:36 +08:00
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2013-12-31 01:24:36 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
OS << " case attr::" << R.getName() << ":\n"
|
|
|
|
<< " return getDerived().Traverse" << R.getName() << "Attr("
|
|
|
|
<< "cast<" << R.getName() << "Attr>(A));\n";
|
|
|
|
}
|
2016-03-01 10:09:20 +08:00
|
|
|
OS << " }\n"; // end switch
|
|
|
|
OS << " llvm_unreachable(\"bad attribute kind\");\n";
|
2013-12-31 01:24:36 +08:00
|
|
|
OS << "}\n"; // end function
|
|
|
|
OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n";
|
|
|
|
}
|
|
|
|
|
2017-03-24 02:51:54 +08:00
|
|
|
void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
|
|
|
|
raw_ostream &OS,
|
|
|
|
bool AppliesToDecl) {
|
2012-01-21 06:37:06 +08:00
|
|
|
|
2017-03-24 02:51:54 +08:00
|
|
|
OS << " switch (At->getKind()) {\n";
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2012-05-02 23:56:52 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " case attr::" << R.getName() << ": {\n";
|
2017-03-24 02:51:54 +08:00
|
|
|
bool ShouldClone = R.getValueAsBit("Clone") &&
|
|
|
|
(!AppliesToDecl ||
|
|
|
|
R.getValueAsBit("MeaningfulToClassTemplateDefinition"));
|
2012-05-15 22:09:55 +08:00
|
|
|
|
|
|
|
if (!ShouldClone) {
|
2015-09-30 04:56:43 +08:00
|
|
|
OS << " return nullptr;\n";
|
2012-05-15 22:09:55 +08:00
|
|
|
OS << " }\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " const auto *A = cast<"
|
2012-01-21 06:37:06 +08:00
|
|
|
<< R.getName() << "Attr>(At);\n";
|
|
|
|
bool TDependent = R.getValueAsBit("TemplateDependent");
|
|
|
|
|
|
|
|
if (!TDependent) {
|
|
|
|
OS << " return A->clone(C);\n";
|
|
|
|
OS << " }\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
|
2014-03-06 00:49:55 +08:00
|
|
|
std::vector<std::unique_ptr<Argument>> Args;
|
2012-01-21 06:37:06 +08:00
|
|
|
Args.reserve(ArgRecords.size());
|
|
|
|
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *ArgRecord : ArgRecords)
|
2014-03-06 00:49:55 +08:00
|
|
|
Args.emplace_back(createArgument(*ArgRecord, R.getName()));
|
2012-01-21 06:37:06 +08:00
|
|
|
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args)
|
2014-03-03 01:38:37 +08:00
|
|
|
ai->writeTemplateInstantiation(OS);
|
2014-03-06 00:49:55 +08:00
|
|
|
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C";
|
2014-03-06 00:49:55 +08:00
|
|
|
for (auto const &ai : Args) {
|
2012-01-21 06:37:06 +08:00
|
|
|
OS << ", ";
|
2014-03-03 01:38:37 +08:00
|
|
|
ai->writeTemplateInstantiationArgs(OS);
|
2012-01-21 06:37:06 +08:00
|
|
|
}
|
2014-01-16 21:03:14 +08:00
|
|
|
OS << ", A->getSpellingListIndex());\n }\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
}
|
|
|
|
OS << " } // end switch\n"
|
|
|
|
<< " llvm_unreachable(\"Unknown attribute!\");\n"
|
2017-03-24 02:51:54 +08:00
|
|
|
<< " return nullptr;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emits code to instantiate dependent attributes on templates.
|
|
|
|
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Template instantiation code for attributes", OS);
|
|
|
|
|
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
|
|
|
|
|
|
|
|
OS << "namespace clang {\n"
|
|
|
|
<< "namespace sema {\n\n"
|
|
|
|
<< "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
|
|
|
|
<< "Sema &S,\n"
|
|
|
|
<< " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
|
|
|
|
EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false);
|
|
|
|
OS << "}\n\n"
|
|
|
|
<< "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n"
|
|
|
|
<< " ASTContext &C, Sema &S,\n"
|
|
|
|
<< " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
|
|
|
|
EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true);
|
|
|
|
OS << "}\n\n"
|
2012-02-06 19:13:08 +08:00
|
|
|
<< "} // end namespace sema\n"
|
|
|
|
<< "} // end namespace clang\n";
|
2012-01-21 06:37:06 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 07:33:17 +08:00
|
|
|
// Emits the list of parsed attributes.
|
|
|
|
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
|
|
|
|
|
|
|
|
OS << "#ifndef PARSED_ATTR\n";
|
|
|
|
OS << "#define PARSED_ATTR(NAME) NAME\n";
|
|
|
|
OS << "#endif\n\n";
|
|
|
|
|
|
|
|
ParsedAttrMap Names = getParsedAttrList(Records);
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Names) {
|
|
|
|
OS << "PARSED_ATTR(" << I.first << ")\n";
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-01 00:37:04 +08:00
|
|
|
static bool isArgVariadic(const Record &R, StringRef AttrName) {
|
|
|
|
return createArgument(R, AttrName)->isVariadic();
|
|
|
|
}
|
|
|
|
|
2013-11-27 21:27:02 +08:00
|
|
|
static void emitArgInfo(const Record &R, std::stringstream &OS) {
|
2013-09-10 07:33:17 +08:00
|
|
|
// This function will count the number of arguments specified for the
|
|
|
|
// attribute and emit the number of required arguments followed by the
|
|
|
|
// number of optional arguments.
|
|
|
|
std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
|
|
|
|
unsigned ArgCount = 0, OptCount = 0;
|
2014-08-01 00:37:04 +08:00
|
|
|
bool HasVariadic = false;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : Args) {
|
2016-12-02 01:52:39 +08:00
|
|
|
// If the arg is fake, it's the user's job to supply it: general parsing
|
|
|
|
// logic shouldn't need to know anything about it.
|
|
|
|
if (Arg->getValueAsBit("Fake"))
|
|
|
|
continue;
|
2014-03-03 01:38:37 +08:00
|
|
|
Arg->getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
|
2014-08-01 00:37:04 +08:00
|
|
|
if (!HasVariadic && isArgVariadic(*Arg, R.getName()))
|
|
|
|
HasVariadic = true;
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
2014-08-01 00:37:04 +08:00
|
|
|
|
|
|
|
// If there is a variadic argument, we will set the optional argument count
|
|
|
|
// to its largest value. Since it's currently a 4-bit number, we set it to 15.
|
|
|
|
OS << ArgCount << ", " << (HasVariadic ? 15 : OptCount);
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
|
|
|
|
2013-11-27 21:27:02 +08:00
|
|
|
static void GenerateDefaultAppertainsTo(raw_ostream &OS) {
|
2013-12-03 03:36:42 +08:00
|
|
|
OS << "static bool defaultAppertainsTo(Sema &, const AttributeList &,";
|
2013-11-27 21:27:02 +08:00
|
|
|
OS << "const Decl *) {\n";
|
|
|
|
OS << " return true;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string CalculateDiagnostic(const Record &S) {
|
|
|
|
// If the SubjectList object has a custom diagnostic associated with it,
|
|
|
|
// return that directly.
|
|
|
|
std::string CustomDiag = S.getValueAsString("CustomDiag");
|
|
|
|
if (!CustomDiag.empty())
|
|
|
|
return CustomDiag;
|
|
|
|
|
|
|
|
// Given the list of subjects, determine what diagnostic best fits.
|
|
|
|
enum {
|
|
|
|
Func = 1U << 0,
|
|
|
|
Var = 1U << 1,
|
|
|
|
ObjCMethod = 1U << 2,
|
|
|
|
Param = 1U << 3,
|
|
|
|
Class = 1U << 4,
|
2013-11-28 04:14:30 +08:00
|
|
|
GenericRecord = 1U << 5,
|
2013-11-27 21:27:02 +08:00
|
|
|
Type = 1U << 6,
|
|
|
|
ObjCIVar = 1U << 7,
|
|
|
|
ObjCProp = 1U << 8,
|
|
|
|
ObjCInterface = 1U << 9,
|
|
|
|
Block = 1U << 10,
|
|
|
|
Namespace = 1U << 11,
|
2014-05-20 22:10:53 +08:00
|
|
|
Field = 1U << 12,
|
|
|
|
CXXMethod = 1U << 13,
|
2014-11-28 08:53:20 +08:00
|
|
|
ObjCProtocol = 1U << 14,
|
|
|
|
Enum = 1U << 15
|
2013-11-27 21:27:02 +08:00
|
|
|
};
|
|
|
|
uint32_t SubMask = 0;
|
|
|
|
|
|
|
|
std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects");
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Subject : Subjects) {
|
|
|
|
const Record &R = *Subject;
|
2013-11-29 22:57:58 +08:00
|
|
|
std::string Name;
|
|
|
|
|
|
|
|
if (R.isSubClassOf("SubsetSubject")) {
|
|
|
|
PrintError(R.getLoc(), "SubsetSubjects should use a custom diagnostic");
|
|
|
|
// As a fallback, look through the SubsetSubject to see what its base
|
|
|
|
// type is, and use that. This needs to be updated if SubsetSubjects
|
|
|
|
// are allowed within other SubsetSubjects.
|
|
|
|
Name = R.getValueAsDef("Base")->getName();
|
|
|
|
} else
|
|
|
|
Name = R.getName();
|
|
|
|
|
|
|
|
uint32_t V = StringSwitch<uint32_t>(Name)
|
2013-11-27 21:27:02 +08:00
|
|
|
.Case("Function", Func)
|
|
|
|
.Case("Var", Var)
|
|
|
|
.Case("ObjCMethod", ObjCMethod)
|
|
|
|
.Case("ParmVar", Param)
|
|
|
|
.Case("TypedefName", Type)
|
|
|
|
.Case("ObjCIvar", ObjCIVar)
|
|
|
|
.Case("ObjCProperty", ObjCProp)
|
2013-11-28 04:14:30 +08:00
|
|
|
.Case("Record", GenericRecord)
|
2013-11-27 21:27:02 +08:00
|
|
|
.Case("ObjCInterface", ObjCInterface)
|
2013-12-11 03:43:42 +08:00
|
|
|
.Case("ObjCProtocol", ObjCProtocol)
|
2013-11-27 21:27:02 +08:00
|
|
|
.Case("Block", Block)
|
|
|
|
.Case("CXXRecord", Class)
|
|
|
|
.Case("Namespace", Namespace)
|
|
|
|
.Case("Field", Field)
|
|
|
|
.Case("CXXMethod", CXXMethod)
|
2014-11-28 08:53:20 +08:00
|
|
|
.Case("Enum", Enum)
|
2013-11-27 21:27:02 +08:00
|
|
|
.Default(0);
|
|
|
|
if (!V) {
|
|
|
|
// Something wasn't in our mapping, so be helpful and let the developer
|
|
|
|
// know about it.
|
2014-03-03 01:38:37 +08:00
|
|
|
PrintFatalError(R.getLoc(), "Unknown subject type: " + R.getName());
|
2013-11-27 21:27:02 +08:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
SubMask |= V;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (SubMask) {
|
|
|
|
// For the simple cases where there's only a single entry in the mask, we
|
|
|
|
// don't have to resort to bit fiddling.
|
|
|
|
case Func: return "ExpectedFunction";
|
|
|
|
case Var: return "ExpectedVariable";
|
|
|
|
case Param: return "ExpectedParameter";
|
|
|
|
case Class: return "ExpectedClass";
|
2014-11-28 08:53:20 +08:00
|
|
|
case Enum: return "ExpectedEnum";
|
2013-11-27 21:27:02 +08:00
|
|
|
case CXXMethod:
|
|
|
|
// FIXME: Currently, this maps to ExpectedMethod based on existing code,
|
|
|
|
// but should map to something a bit more accurate at some point.
|
|
|
|
case ObjCMethod: return "ExpectedMethod";
|
|
|
|
case Type: return "ExpectedType";
|
|
|
|
case ObjCInterface: return "ExpectedObjectiveCInterface";
|
2013-12-11 03:43:42 +08:00
|
|
|
case ObjCProtocol: return "ExpectedObjectiveCProtocol";
|
2013-11-27 21:27:02 +08:00
|
|
|
|
2013-11-28 04:14:30 +08:00
|
|
|
// "GenericRecord" means struct, union or class; check the language options
|
|
|
|
// and if not compiling for C++, strip off the class part. Note that this
|
|
|
|
// relies on the fact that the context for this declares "Sema &S".
|
|
|
|
case GenericRecord:
|
2013-11-28 03:16:55 +08:00
|
|
|
return "(S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass : "
|
|
|
|
"ExpectedStructOrUnion)";
|
2013-11-27 21:27:02 +08:00
|
|
|
case Func | ObjCMethod | Block: return "ExpectedFunctionMethodOrBlock";
|
|
|
|
case Func | ObjCMethod | Class: return "ExpectedFunctionMethodOrClass";
|
|
|
|
case Func | Param:
|
|
|
|
case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter";
|
|
|
|
case Func | ObjCMethod: return "ExpectedFunctionOrMethod";
|
|
|
|
case Func | Var: return "ExpectedVariableOrFunction";
|
2013-12-03 01:07:07 +08:00
|
|
|
|
|
|
|
// If not compiling for C++, the class portion does not apply.
|
|
|
|
case Func | Var | Class:
|
|
|
|
return "(S.getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass : "
|
|
|
|
"ExpectedVariableOrFunction)";
|
|
|
|
|
2016-07-16 04:41:10 +08:00
|
|
|
case Func | Var | Class | ObjCInterface:
|
|
|
|
return "(S.getLangOpts().CPlusPlus"
|
|
|
|
" ? ((S.getLangOpts().ObjC1 || S.getLangOpts().ObjC2)"
|
|
|
|
" ? ExpectedFunctionVariableClassOrObjCInterface"
|
|
|
|
" : ExpectedFunctionVariableOrClass)"
|
|
|
|
" : ((S.getLangOpts().ObjC1 || S.getLangOpts().ObjC2)"
|
|
|
|
" ? ExpectedFunctionVariableOrObjCInterface"
|
|
|
|
" : ExpectedVariableOrFunction))";
|
|
|
|
|
2013-11-27 21:27:02 +08:00
|
|
|
case ObjCMethod | ObjCProp: return "ExpectedMethodOrProperty";
|
2014-07-17 04:28:10 +08:00
|
|
|
case ObjCProtocol | ObjCInterface:
|
|
|
|
return "ExpectedObjectiveCInterfaceOrProtocol";
|
2013-11-27 21:27:02 +08:00
|
|
|
case Field | Var: return "ExpectedFieldOrGlobalVar";
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintFatalError(S.getLoc(),
|
|
|
|
"Could not deduce diagnostic argument for Attr subjects");
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2014-01-16 21:55:42 +08:00
|
|
|
static std::string GetSubjectWithSuffix(const Record *R) {
|
2016-12-01 08:13:18 +08:00
|
|
|
const std::string &B = R->getName();
|
2014-01-16 21:55:42 +08:00
|
|
|
if (B == "DeclBase")
|
|
|
|
return "Decl";
|
|
|
|
return B + "Decl";
|
|
|
|
}
|
2015-10-07 07:40:43 +08:00
|
|
|
|
2013-11-29 22:57:58 +08:00
|
|
|
static std::string GenerateCustomAppertainsTo(const Record &Subject,
|
|
|
|
raw_ostream &OS) {
|
2016-12-04 13:55:09 +08:00
|
|
|
std::string FnName = "is" + Subject.getName().str();
|
2013-12-02 22:58:17 +08:00
|
|
|
|
2013-11-29 22:57:58 +08:00
|
|
|
// If this code has already been generated, simply return the previous
|
|
|
|
// instance of it.
|
|
|
|
static std::set<std::string> CustomSubjectSet;
|
2015-12-09 02:49:01 +08:00
|
|
|
auto I = CustomSubjectSet.find(FnName);
|
2013-11-29 22:57:58 +08:00
|
|
|
if (I != CustomSubjectSet.end())
|
|
|
|
return *I;
|
|
|
|
|
|
|
|
Record *Base = Subject.getValueAsDef("Base");
|
|
|
|
|
|
|
|
// Not currently support custom subjects within custom subjects.
|
|
|
|
if (Base->isSubClassOf("SubsetSubject")) {
|
|
|
|
PrintFatalError(Subject.getLoc(),
|
|
|
|
"SubsetSubjects within SubsetSubjects is not supported");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << "static bool " << FnName << "(const Decl *D) {\n";
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " if (const auto *S = dyn_cast<";
|
2014-01-16 21:55:42 +08:00
|
|
|
OS << GetSubjectWithSuffix(Base);
|
2014-01-16 22:32:03 +08:00
|
|
|
OS << ">(D))\n";
|
|
|
|
OS << " return " << Subject.getValueAsString("CheckCode") << ";\n";
|
|
|
|
OS << " return false;\n";
|
2013-11-29 22:57:58 +08:00
|
|
|
OS << "}\n\n";
|
|
|
|
|
|
|
|
CustomSubjectSet.insert(FnName);
|
|
|
|
return FnName;
|
|
|
|
}
|
|
|
|
|
2013-11-27 21:27:02 +08:00
|
|
|
static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|
|
|
// If the attribute does not contain a Subjects definition, then use the
|
|
|
|
// default appertainsTo logic.
|
|
|
|
if (Attr.isValueUnset("Subjects"))
|
2013-12-03 03:36:42 +08:00
|
|
|
return "defaultAppertainsTo";
|
2013-11-27 21:27:02 +08:00
|
|
|
|
|
|
|
const Record *SubjectObj = Attr.getValueAsDef("Subjects");
|
|
|
|
std::vector<Record*> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
|
|
|
|
|
|
|
|
// If the list of subjects is empty, it is assumed that the attribute
|
|
|
|
// appertains to everything.
|
|
|
|
if (Subjects.empty())
|
2013-12-03 03:36:42 +08:00
|
|
|
return "defaultAppertainsTo";
|
2013-11-27 21:27:02 +08:00
|
|
|
|
|
|
|
bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn");
|
|
|
|
|
|
|
|
// Otherwise, generate an appertainsTo check specific to this attribute which
|
|
|
|
// checks all of the given subjects against the Decl passed in. Return the
|
|
|
|
// name of that check to the caller.
|
2016-12-04 13:55:09 +08:00
|
|
|
std::string FnName = "check" + Attr.getName().str() + "AppertainsTo";
|
2013-11-27 21:27:02 +08:00
|
|
|
std::stringstream SS;
|
|
|
|
SS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr, ";
|
|
|
|
SS << "const Decl *D) {\n";
|
|
|
|
SS << " if (";
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) {
|
2013-11-29 22:57:58 +08:00
|
|
|
// If the subject has custom code associated with it, generate a function
|
|
|
|
// for it. The function cannot be inlined into this check (yet) because it
|
|
|
|
// requires the subject to be of a specific type, and were that information
|
|
|
|
// inlined here, it would not support an attribute with multiple custom
|
|
|
|
// subjects.
|
|
|
|
if ((*I)->isSubClassOf("SubsetSubject")) {
|
|
|
|
SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)";
|
|
|
|
} else {
|
2014-01-16 21:55:42 +08:00
|
|
|
SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
|
2013-11-29 22:57:58 +08:00
|
|
|
}
|
2013-11-27 21:27:02 +08:00
|
|
|
|
|
|
|
if (I + 1 != E)
|
|
|
|
SS << " && ";
|
|
|
|
}
|
|
|
|
SS << ") {\n";
|
|
|
|
SS << " S.Diag(Attr.getLoc(), diag::";
|
|
|
|
SS << (Warn ? "warn_attribute_wrong_decl_type" :
|
|
|
|
"err_attribute_wrong_decl_type");
|
|
|
|
SS << ")\n";
|
|
|
|
SS << " << Attr.getName() << ";
|
|
|
|
SS << CalculateDiagnostic(*SubjectObj) << ";\n";
|
|
|
|
SS << " return false;\n";
|
|
|
|
SS << " }\n";
|
|
|
|
SS << " return true;\n";
|
|
|
|
SS << "}\n\n";
|
|
|
|
|
|
|
|
OS << SS.str();
|
|
|
|
return FnName;
|
|
|
|
}
|
|
|
|
|
2013-12-03 03:30:36 +08:00
|
|
|
static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
|
|
|
|
OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
|
|
|
|
OS << "const AttributeList &) {\n";
|
|
|
|
OS << " return true;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string GenerateLangOptRequirements(const Record &R,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// If the attribute has an empty or unset list of language requirements,
|
|
|
|
// return the default handler.
|
|
|
|
std::vector<Record *> LangOpts = R.getValueAsListOfDefs("LangOpts");
|
|
|
|
if (LangOpts.empty())
|
|
|
|
return "defaultDiagnoseLangOpts";
|
|
|
|
|
|
|
|
// Generate the test condition, as well as a unique function name for the
|
|
|
|
// diagnostic test. The list of options should usually be short (one or two
|
|
|
|
// options), and the uniqueness isn't strictly necessary (it is just for
|
|
|
|
// codegen efficiency).
|
|
|
|
std::string FnName = "check", Test;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
|
2013-12-03 03:30:36 +08:00
|
|
|
std::string Part = (*I)->getValueAsString("Name");
|
2016-09-03 02:53:31 +08:00
|
|
|
if ((*I)->getValueAsBit("Negated")) {
|
|
|
|
FnName += "Not";
|
2014-11-28 08:53:20 +08:00
|
|
|
Test += "!";
|
2016-09-03 02:53:31 +08:00
|
|
|
}
|
2013-12-03 03:30:36 +08:00
|
|
|
Test += "S.LangOpts." + Part;
|
|
|
|
if (I + 1 != E)
|
|
|
|
Test += " || ";
|
|
|
|
FnName += Part;
|
|
|
|
}
|
|
|
|
FnName += "LangOpts";
|
|
|
|
|
|
|
|
// If this code has already been generated, simply return the previous
|
|
|
|
// instance of it.
|
|
|
|
static std::set<std::string> CustomLangOptsSet;
|
2015-12-09 02:49:01 +08:00
|
|
|
auto I = CustomLangOptsSet.find(FnName);
|
2013-12-03 03:30:36 +08:00
|
|
|
if (I != CustomLangOptsSet.end())
|
|
|
|
return *I;
|
|
|
|
|
|
|
|
OS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr) {\n";
|
|
|
|
OS << " if (" << Test << ")\n";
|
|
|
|
OS << " return true;\n\n";
|
|
|
|
OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) ";
|
|
|
|
OS << "<< Attr.getName();\n";
|
|
|
|
OS << " return false;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
|
|
|
|
CustomLangOptsSet.insert(FnName);
|
|
|
|
return FnName;
|
|
|
|
}
|
|
|
|
|
2014-01-10 06:48:32 +08:00
|
|
|
static void GenerateDefaultTargetRequirements(raw_ostream &OS) {
|
2015-07-21 06:57:31 +08:00
|
|
|
OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n";
|
2014-01-10 06:48:32 +08:00
|
|
|
OS << " return true;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string GenerateTargetRequirements(const Record &Attr,
|
|
|
|
const ParsedAttrMap &Dupes,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// If the attribute is not a target specific attribute, return the default
|
|
|
|
// target handler.
|
|
|
|
if (!Attr.isSubClassOf("TargetSpecificAttr"))
|
|
|
|
return "defaultTargetRequirements";
|
|
|
|
|
|
|
|
// Get the list of architectures to be tested for.
|
|
|
|
const Record *R = Attr.getValueAsDef("Target");
|
|
|
|
std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
|
|
|
|
if (Arches.empty()) {
|
|
|
|
PrintError(Attr.getLoc(), "Empty list of target architectures for a "
|
|
|
|
"target-specific attr");
|
|
|
|
return "defaultTargetRequirements";
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are other attributes which share the same parsed attribute kind,
|
|
|
|
// such as target-specific attributes with a shared spelling, collapse the
|
|
|
|
// duplicate architectures. This is required because a shared target-specific
|
|
|
|
// attribute has only one AttributeList::Kind enumeration value, but it
|
|
|
|
// applies to multiple target architectures. In order for the attribute to be
|
|
|
|
// considered valid, all of its architectures need to be included.
|
|
|
|
if (!Attr.isValueUnset("ParseKind")) {
|
|
|
|
std::string APK = Attr.getValueAsString("ParseKind");
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Dupes) {
|
|
|
|
if (I.first == APK) {
|
|
|
|
std::vector<std::string> DA = I.second->getValueAsDef("Target")
|
|
|
|
->getValueAsListOfStrings("Arches");
|
2016-12-01 08:13:18 +08:00
|
|
|
std::move(DA.begin(), DA.end(), std::back_inserter(Arches));
|
2014-01-10 06:48:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-21 06:57:36 +08:00
|
|
|
std::string FnName = "isTarget";
|
|
|
|
std::string Test;
|
|
|
|
GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName);
|
2015-07-21 06:57:31 +08:00
|
|
|
|
2014-01-10 06:48:32 +08:00
|
|
|
// If this code has already been generated, simply return the previous
|
|
|
|
// instance of it.
|
|
|
|
static std::set<std::string> CustomTargetSet;
|
2015-12-09 02:49:01 +08:00
|
|
|
auto I = CustomTargetSet.find(FnName);
|
2014-01-10 06:48:32 +08:00
|
|
|
if (I != CustomTargetSet.end())
|
|
|
|
return *I;
|
|
|
|
|
2015-07-21 06:57:31 +08:00
|
|
|
OS << "static bool " << FnName << "(const TargetInfo &Target) {\n";
|
|
|
|
OS << " const llvm::Triple &T = Target.getTriple();\n";
|
2014-01-10 06:48:32 +08:00
|
|
|
OS << " return " << Test << ";\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
|
|
|
|
CustomTargetSet.insert(FnName);
|
|
|
|
return FnName;
|
|
|
|
}
|
|
|
|
|
2014-01-25 05:32:49 +08:00
|
|
|
static void GenerateDefaultSpellingIndexToSemanticSpelling(raw_ostream &OS) {
|
|
|
|
OS << "static unsigned defaultSpellingIndexToSemanticSpelling("
|
|
|
|
<< "const AttributeList &Attr) {\n";
|
|
|
|
OS << " return UINT_MAX;\n";
|
|
|
|
OS << "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// If the attribute does not have a semantic form, we can bail out early.
|
|
|
|
if (!Attr.getValueAsBit("ASTNode"))
|
|
|
|
return "defaultSpellingIndexToSemanticSpelling";
|
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
|
2014-01-25 05:32:49 +08:00
|
|
|
|
|
|
|
// If there are zero or one spellings, or all of the spellings share the same
|
|
|
|
// name, we can also bail out early.
|
|
|
|
if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings))
|
|
|
|
return "defaultSpellingIndexToSemanticSpelling";
|
|
|
|
|
|
|
|
// Generate the enumeration we will use for the mapping.
|
|
|
|
SemanticSpellingMap SemanticToSyntacticMap;
|
|
|
|
std::string Enum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
|
2016-12-04 13:55:09 +08:00
|
|
|
std::string Name = Attr.getName().str() + "AttrSpellingMap";
|
2014-01-25 05:32:49 +08:00
|
|
|
|
|
|
|
OS << "static unsigned " << Name << "(const AttributeList &Attr) {\n";
|
|
|
|
OS << Enum;
|
|
|
|
OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n";
|
|
|
|
WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS);
|
|
|
|
OS << "}\n\n";
|
|
|
|
|
|
|
|
return Name;
|
|
|
|
}
|
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
static bool IsKnownToGCC(const Record &Attr) {
|
|
|
|
// Look at the spellings for this subject; if there are any spellings which
|
|
|
|
// claim to be known to GCC, the attribute is known to GCC.
|
2016-12-01 08:13:18 +08:00
|
|
|
return llvm::any_of(
|
|
|
|
GetFlattenedSpellings(Attr),
|
|
|
|
[](const FlattenedSpelling &S) { return S.knownToGCC(); });
|
2014-01-21 01:18:35 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 07:33:17 +08:00
|
|
|
/// Emits the parsed attribute helpers
|
|
|
|
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Parsed attribute helpers", OS);
|
|
|
|
|
2014-01-10 06:48:32 +08:00
|
|
|
// Get the list of parsed attributes, and accept the optional list of
|
|
|
|
// duplicates due to the ParseKind.
|
|
|
|
ParsedAttrMap Dupes;
|
|
|
|
ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes);
|
2013-09-10 07:33:17 +08:00
|
|
|
|
2014-01-25 05:32:49 +08:00
|
|
|
// Generate the default appertainsTo, target and language option diagnostic,
|
|
|
|
// and spelling list index mapping methods.
|
2013-11-27 21:27:02 +08:00
|
|
|
GenerateDefaultAppertainsTo(OS);
|
2013-12-03 03:30:36 +08:00
|
|
|
GenerateDefaultLangOptRequirements(OS);
|
2014-01-10 06:48:32 +08:00
|
|
|
GenerateDefaultTargetRequirements(OS);
|
2014-01-25 05:32:49 +08:00
|
|
|
GenerateDefaultSpellingIndexToSemanticSpelling(OS);
|
2013-11-27 21:27:02 +08:00
|
|
|
|
|
|
|
// Generate the appertainsTo diagnostic methods and write their names into
|
|
|
|
// another mapping. At the same time, generate the AttrInfoMap object
|
|
|
|
// contents. Due to the reliance on generated code, use separate streams so
|
|
|
|
// that code will not be interleaved.
|
|
|
|
std::stringstream SS;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
|
2014-01-10 06:48:32 +08:00
|
|
|
// TODO: If the attribute's kind appears in the list of duplicates, that is
|
|
|
|
// because it is a target-specific attribute that appears multiple times.
|
|
|
|
// It would be beneficial to test whether the duplicates are "similar
|
|
|
|
// enough" to each other to not cause problems. For instance, check that
|
2014-01-19 05:49:37 +08:00
|
|
|
// the spellings are identical, and custom parsing rules match, etc.
|
2014-01-10 06:48:32 +08:00
|
|
|
|
2013-09-10 07:33:17 +08:00
|
|
|
// We need to generate struct instances based off ParsedAttrInfo from
|
|
|
|
// AttributeList.cpp.
|
2013-11-27 21:27:02 +08:00
|
|
|
SS << " { ";
|
|
|
|
emitArgInfo(*I->second, SS);
|
|
|
|
SS << ", " << I->second->getValueAsBit("HasCustomParsing");
|
2014-01-10 06:48:32 +08:00
|
|
|
SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
|
|
|
|
SS << ", " << I->second->isSubClassOf("TypeAttr");
|
2016-03-08 08:32:55 +08:00
|
|
|
SS << ", " << I->second->isSubClassOf("StmtAttr");
|
2014-01-28 06:10:04 +08:00
|
|
|
SS << ", " << IsKnownToGCC(*I->second);
|
2013-11-27 21:27:02 +08:00
|
|
|
SS << ", " << GenerateAppertainsTo(*I->second, OS);
|
2013-12-03 03:30:36 +08:00
|
|
|
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
|
2014-01-10 06:48:32 +08:00
|
|
|
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
|
2014-01-25 05:32:49 +08:00
|
|
|
SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS);
|
2013-11-27 21:27:02 +08:00
|
|
|
SS << " }";
|
2013-09-10 07:33:17 +08:00
|
|
|
|
|
|
|
if (I + 1 != E)
|
2013-11-27 21:27:02 +08:00
|
|
|
SS << ",";
|
|
|
|
|
|
|
|
SS << " // AT_" << I->first << "\n";
|
2013-09-10 07:33:17 +08:00
|
|
|
}
|
2013-11-27 21:27:02 +08:00
|
|
|
|
|
|
|
OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
|
|
|
|
OS << SS.str();
|
2013-09-10 07:33:17 +08:00
|
|
|
OS << "};\n\n";
|
2012-03-07 08:12:16 +08:00
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
// Emits the kind list of parsed attributes
|
|
|
|
void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute name matcher", OS);
|
|
|
|
|
2014-01-14 05:42:39 +08:00
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
2016-09-03 10:55:10 +08:00
|
|
|
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
|
|
|
|
Keywords, Pragma;
|
2013-12-15 21:05:48 +08:00
|
|
|
std::set<std::string> Seen;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *A : Attrs) {
|
|
|
|
const Record &Attr = *A;
|
2013-11-27 09:46:48 +08:00
|
|
|
|
2012-03-07 08:12:16 +08:00
|
|
|
bool SemaHandler = Attr.getValueAsBit("SemaHandler");
|
2012-05-03 00:18:45 +08:00
|
|
|
bool Ignored = Attr.getValueAsBit("Ignored");
|
|
|
|
if (SemaHandler || Ignored) {
|
2014-01-14 05:42:39 +08:00
|
|
|
// Attribute spellings can be shared between target-specific attributes,
|
|
|
|
// and can be shared between syntaxes for the same attribute. For
|
|
|
|
// instance, an attribute can be spelled GNU<"interrupt"> for an ARM-
|
|
|
|
// specific attribute, or MSP430-specific attribute. Additionally, an
|
|
|
|
// attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport">
|
|
|
|
// for the same semantic attribute. Ultimately, we need to map each of
|
|
|
|
// these to a single AttributeList::Kind value, but the StringMatcher
|
|
|
|
// class cannot handle duplicate match strings. So we generate a list of
|
|
|
|
// string to match based on the syntax, and emit multiple string matchers
|
|
|
|
// depending on the syntax used.
|
2013-12-15 21:05:48 +08:00
|
|
|
std::string AttrName;
|
|
|
|
if (Attr.isSubClassOf("TargetSpecificAttr") &&
|
|
|
|
!Attr.isValueUnset("ParseKind")) {
|
|
|
|
AttrName = Attr.getValueAsString("ParseKind");
|
|
|
|
if (Seen.find(AttrName) != Seen.end())
|
|
|
|
continue;
|
|
|
|
Seen.insert(AttrName);
|
|
|
|
} else
|
|
|
|
AttrName = NormalizeAttrName(StringRef(Attr.getName())).str();
|
|
|
|
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &S : Spellings) {
|
2016-05-27 21:36:58 +08:00
|
|
|
const std::string &RawSpelling = S.name();
|
2014-05-07 14:21:57 +08:00
|
|
|
std::vector<StringMatcher::StringPair> *Matches = nullptr;
|
2016-05-27 21:36:58 +08:00
|
|
|
std::string Spelling;
|
|
|
|
const std::string &Variety = S.variety();
|
2014-01-14 05:42:39 +08:00
|
|
|
if (Variety == "CXX11") {
|
|
|
|
Matches = &CXX11;
|
2014-03-03 01:38:37 +08:00
|
|
|
Spelling += S.nameSpace();
|
2012-06-20 07:57:03 +08:00
|
|
|
Spelling += "::";
|
2014-01-14 05:42:39 +08:00
|
|
|
} else if (Variety == "GNU")
|
|
|
|
Matches = &GNU;
|
|
|
|
else if (Variety == "Declspec")
|
|
|
|
Matches = &Declspec;
|
2016-09-03 10:55:10 +08:00
|
|
|
else if (Variety == "Microsoft")
|
|
|
|
Matches = &Microsoft;
|
2014-01-14 05:42:39 +08:00
|
|
|
else if (Variety == "Keyword")
|
|
|
|
Matches = &Keywords;
|
2014-06-14 01:57:25 +08:00
|
|
|
else if (Variety == "Pragma")
|
|
|
|
Matches = &Pragma;
|
2012-06-19 00:13:52 +08:00
|
|
|
|
2014-01-14 05:42:39 +08:00
|
|
|
assert(Matches && "Unsupported spelling variety found");
|
|
|
|
|
2017-01-06 00:51:54 +08:00
|
|
|
if (Variety == "GNU")
|
|
|
|
Spelling += NormalizeGNUAttrSpelling(RawSpelling);
|
|
|
|
else
|
|
|
|
Spelling += RawSpelling;
|
|
|
|
|
2012-05-03 00:18:45 +08:00
|
|
|
if (SemaHandler)
|
2014-01-14 05:42:39 +08:00
|
|
|
Matches->push_back(StringMatcher::StringPair(Spelling,
|
|
|
|
"return AttributeList::AT_" + AttrName + ";"));
|
2012-05-03 00:18:45 +08:00
|
|
|
else
|
2014-01-14 05:42:39 +08:00
|
|
|
Matches->push_back(StringMatcher::StringPair(Spelling,
|
|
|
|
"return AttributeList::IgnoredAttribute;"));
|
2012-03-07 08:12:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-03 01:33:51 +08:00
|
|
|
|
2014-01-14 05:42:39 +08:00
|
|
|
OS << "static AttributeList::Kind getAttrKind(StringRef Name, ";
|
|
|
|
OS << "AttributeList::Syntax Syntax) {\n";
|
|
|
|
OS << " if (AttributeList::AS_GNU == Syntax) {\n";
|
|
|
|
StringMatcher("Name", GNU, OS).Emit();
|
|
|
|
OS << " } else if (AttributeList::AS_Declspec == Syntax) {\n";
|
|
|
|
StringMatcher("Name", Declspec, OS).Emit();
|
2016-09-03 10:55:10 +08:00
|
|
|
OS << " } else if (AttributeList::AS_Microsoft == Syntax) {\n";
|
|
|
|
StringMatcher("Name", Microsoft, OS).Emit();
|
2014-01-14 05:42:39 +08:00
|
|
|
OS << " } else if (AttributeList::AS_CXX11 == Syntax) {\n";
|
|
|
|
StringMatcher("Name", CXX11, OS).Emit();
|
2015-06-20 02:27:45 +08:00
|
|
|
OS << " } else if (AttributeList::AS_Keyword == Syntax || ";
|
|
|
|
OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n";
|
2014-01-14 05:42:39 +08:00
|
|
|
StringMatcher("Name", Keywords, OS).Emit();
|
2014-06-14 01:57:25 +08:00
|
|
|
OS << " } else if (AttributeList::AS_Pragma == Syntax) {\n";
|
|
|
|
StringMatcher("Name", Pragma, OS).Emit();
|
2014-01-14 05:42:39 +08:00
|
|
|
OS << " }\n";
|
|
|
|
OS << " return AttributeList::UnknownAttribute;\n"
|
2012-05-03 01:33:51 +08:00
|
|
|
<< "}\n";
|
2012-03-07 08:12:16 +08:00
|
|
|
}
|
|
|
|
|
2013-01-08 01:53:08 +08:00
|
|
|
// Emits the code to dump an attribute.
|
|
|
|
void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) {
|
2013-01-31 05:54:20 +08:00
|
|
|
emitSourceFileHeader("Attribute dumper", OS);
|
|
|
|
|
2016-03-01 08:18:05 +08:00
|
|
|
OS << " switch (A->getKind()) {\n";
|
2013-01-08 01:53:08 +08:00
|
|
|
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Attr : Attrs) {
|
|
|
|
const Record &R = *Attr;
|
2013-01-08 01:53:08 +08:00
|
|
|
if (!R.getValueAsBit("ASTNode"))
|
|
|
|
continue;
|
|
|
|
OS << " case attr::" << R.getName() << ": {\n";
|
2014-01-23 05:51:20 +08:00
|
|
|
|
|
|
|
// If the attribute has a semantically-meaningful name (which is determined
|
|
|
|
// by whether there is a Spelling enumeration for it), then write out the
|
|
|
|
// spelling used for the attribute.
|
2014-01-28 06:10:04 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
2014-01-23 05:51:20 +08:00
|
|
|
if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings))
|
|
|
|
OS << " OS << \" \" << A->getSpelling();\n";
|
|
|
|
|
2013-01-08 01:53:08 +08:00
|
|
|
Args = R.getValueAsListOfDefs("Args");
|
|
|
|
if (!Args.empty()) {
|
2015-12-09 02:49:01 +08:00
|
|
|
OS << " const auto *SA = cast<" << R.getName()
|
2013-01-08 01:53:08 +08:00
|
|
|
<< "Attr>(A);\n";
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *Arg : Args)
|
|
|
|
createArgument(*Arg, R.getName())->writeDump(OS);
|
2013-01-31 09:44:26 +08:00
|
|
|
|
2015-12-09 02:49:01 +08:00
|
|
|
for (const auto *AI : Args)
|
|
|
|
createArgument(*AI, R.getName())->writeDumpChildren(OS);
|
2013-01-08 01:53:08 +08:00
|
|
|
}
|
|
|
|
OS <<
|
|
|
|
" break;\n"
|
|
|
|
" }\n";
|
|
|
|
}
|
|
|
|
OS << " }\n";
|
|
|
|
}
|
|
|
|
|
2014-01-30 06:13:45 +08:00
|
|
|
void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS);
|
|
|
|
emitClangAttrArgContextList(Records, OS);
|
|
|
|
emitClangAttrIdentifierArgList(Records, OS);
|
|
|
|
emitClangAttrTypeArgList(Records, OS);
|
|
|
|
emitClangAttrLateParsedList(Records, OS);
|
|
|
|
}
|
|
|
|
|
2014-02-17 23:27:10 +08:00
|
|
|
class DocumentationData {
|
|
|
|
public:
|
2014-02-18 00:18:32 +08:00
|
|
|
const Record *Documentation;
|
|
|
|
const Record *Attribute;
|
2014-02-17 23:27:10 +08:00
|
|
|
|
2014-02-20 06:59:32 +08:00
|
|
|
DocumentationData(const Record &Documentation, const Record &Attribute)
|
|
|
|
: Documentation(&Documentation), Attribute(&Attribute) {}
|
2014-02-17 23:27:10 +08:00
|
|
|
};
|
|
|
|
|
2014-02-20 06:59:32 +08:00
|
|
|
static void WriteCategoryHeader(const Record *DocCategory,
|
2014-02-17 23:27:10 +08:00
|
|
|
raw_ostream &OS) {
|
2014-02-20 06:59:32 +08:00
|
|
|
const std::string &Name = DocCategory->getValueAsString("Name");
|
|
|
|
OS << Name << "\n" << std::string(Name.length(), '=') << "\n";
|
|
|
|
|
|
|
|
// If there is content, print that as well.
|
|
|
|
std::string ContentStr = DocCategory->getValueAsString("Content");
|
2015-04-11 05:37:21 +08:00
|
|
|
// Trim leading and trailing newlines and spaces.
|
|
|
|
OS << StringRef(ContentStr).trim();
|
|
|
|
|
2014-02-20 06:59:32 +08:00
|
|
|
OS << "\n\n";
|
2014-02-17 23:27:10 +08:00
|
|
|
}
|
|
|
|
|
2014-02-17 23:36:08 +08:00
|
|
|
enum SpellingKind {
|
|
|
|
GNU = 1 << 0,
|
|
|
|
CXX11 = 1 << 1,
|
|
|
|
Declspec = 1 << 2,
|
2016-09-03 10:55:10 +08:00
|
|
|
Microsoft = 1 << 3,
|
|
|
|
Keyword = 1 << 4,
|
|
|
|
Pragma = 1 << 5
|
2014-02-17 23:36:08 +08:00
|
|
|
};
|
|
|
|
|
2014-02-17 23:27:10 +08:00
|
|
|
static void WriteDocumentation(const DocumentationData &Doc,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// FIXME: there is no way to have a per-spelling category for the attribute
|
|
|
|
// documentation. This may not be a limiting factor since the spellings
|
|
|
|
// should generally be consistently applied across the category.
|
|
|
|
|
2014-02-18 00:18:32 +08:00
|
|
|
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Doc.Attribute);
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
// Determine the heading to be used for this attribute.
|
2014-02-18 00:18:32 +08:00
|
|
|
std::string Heading = Doc.Documentation->getValueAsString("Heading");
|
2014-02-21 22:14:04 +08:00
|
|
|
bool CustomHeading = !Heading.empty();
|
2014-02-17 23:27:10 +08:00
|
|
|
if (Heading.empty()) {
|
|
|
|
// If there's only one spelling, we can simply use that.
|
|
|
|
if (Spellings.size() == 1)
|
|
|
|
Heading = Spellings.begin()->name();
|
|
|
|
else {
|
|
|
|
std::set<std::string> Uniques;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = Spellings.begin(), E = Spellings.end();
|
|
|
|
I != E && Uniques.size() <= 1; ++I) {
|
2014-02-17 23:27:10 +08:00
|
|
|
std::string Spelling = NormalizeNameForSpellingComparison(I->name());
|
|
|
|
Uniques.insert(Spelling);
|
|
|
|
}
|
|
|
|
// If the semantic map has only one spelling, that is sufficient for our
|
|
|
|
// needs.
|
|
|
|
if (Uniques.size() == 1)
|
|
|
|
Heading = *Uniques.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the heading is still empty, it is an error.
|
|
|
|
if (Heading.empty())
|
2014-02-18 00:18:32 +08:00
|
|
|
PrintFatalError(Doc.Attribute->getLoc(),
|
2014-02-17 23:27:10 +08:00
|
|
|
"This attribute requires a heading to be specified");
|
|
|
|
|
|
|
|
// Gather a list of unique spellings; this is not the same as the semantic
|
|
|
|
// spelling for the attribute. Variations in underscores and other non-
|
|
|
|
// semantic characters are still acceptable.
|
|
|
|
std::vector<std::string> Names;
|
|
|
|
|
|
|
|
unsigned SupportedSpellings = 0;
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : Spellings) {
|
|
|
|
SpellingKind Kind = StringSwitch<SpellingKind>(I.variety())
|
2014-06-14 01:57:25 +08:00
|
|
|
.Case("GNU", GNU)
|
|
|
|
.Case("CXX11", CXX11)
|
|
|
|
.Case("Declspec", Declspec)
|
2016-09-03 10:55:10 +08:00
|
|
|
.Case("Microsoft", Microsoft)
|
2014-06-14 01:57:25 +08:00
|
|
|
.Case("Keyword", Keyword)
|
|
|
|
.Case("Pragma", Pragma);
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
// Mask in the supported spelling.
|
|
|
|
SupportedSpellings |= Kind;
|
|
|
|
|
|
|
|
std::string Name;
|
2014-03-03 01:38:37 +08:00
|
|
|
if (Kind == CXX11 && !I.nameSpace().empty())
|
|
|
|
Name = I.nameSpace() + "::";
|
|
|
|
Name += I.name();
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
// If this name is the same as the heading, do not add it.
|
|
|
|
if (Name != Heading)
|
|
|
|
Names.push_back(Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print out the heading for the attribute. If there are alternate spellings,
|
|
|
|
// then display those after the heading.
|
2014-02-21 22:14:04 +08:00
|
|
|
if (!CustomHeading && !Names.empty()) {
|
2014-02-17 23:27:10 +08:00
|
|
|
Heading += " (";
|
2014-03-03 01:38:37 +08:00
|
|
|
for (auto I = Names.begin(), E = Names.end(); I != E; ++I) {
|
2014-02-17 23:27:10 +08:00
|
|
|
if (I != Names.begin())
|
|
|
|
Heading += ", ";
|
|
|
|
Heading += *I;
|
|
|
|
}
|
|
|
|
Heading += ")";
|
|
|
|
}
|
|
|
|
OS << Heading << "\n" << std::string(Heading.length(), '-') << "\n";
|
|
|
|
|
|
|
|
if (!SupportedSpellings)
|
2014-02-18 00:18:32 +08:00
|
|
|
PrintFatalError(Doc.Attribute->getLoc(),
|
2014-02-17 23:27:10 +08:00
|
|
|
"Attribute has no supported spellings; cannot be "
|
|
|
|
"documented");
|
|
|
|
|
|
|
|
// List what spelling syntaxes the attribute supports.
|
|
|
|
OS << ".. csv-table:: Supported Syntaxes\n";
|
2014-06-14 01:57:25 +08:00
|
|
|
OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
|
|
|
|
OS << " \"Pragma\"\n\n";
|
2014-02-17 23:27:10 +08:00
|
|
|
OS << " \"";
|
|
|
|
if (SupportedSpellings & GNU) OS << "X";
|
|
|
|
OS << "\",\"";
|
|
|
|
if (SupportedSpellings & CXX11) OS << "X";
|
|
|
|
OS << "\",\"";
|
|
|
|
if (SupportedSpellings & Declspec) OS << "X";
|
|
|
|
OS << "\",\"";
|
|
|
|
if (SupportedSpellings & Keyword) OS << "X";
|
2014-06-25 20:48:06 +08:00
|
|
|
OS << "\", \"";
|
2014-06-14 01:57:25 +08:00
|
|
|
if (SupportedSpellings & Pragma) OS << "X";
|
2014-02-17 23:27:10 +08:00
|
|
|
OS << "\"\n\n";
|
|
|
|
|
|
|
|
// If the attribute is deprecated, print a message about it, and possibly
|
|
|
|
// provide a replacement attribute.
|
2014-02-18 00:18:32 +08:00
|
|
|
if (!Doc.Documentation->isValueUnset("Deprecated")) {
|
2014-02-17 23:27:10 +08:00
|
|
|
OS << "This attribute has been deprecated, and may be removed in a future "
|
|
|
|
<< "version of Clang.";
|
2014-02-18 00:18:32 +08:00
|
|
|
const Record &Deprecated = *Doc.Documentation->getValueAsDef("Deprecated");
|
2014-02-17 23:27:10 +08:00
|
|
|
std::string Replacement = Deprecated.getValueAsString("Replacement");
|
|
|
|
if (!Replacement.empty())
|
|
|
|
OS << " This attribute has been superseded by ``"
|
|
|
|
<< Replacement << "``.";
|
|
|
|
OS << "\n\n";
|
|
|
|
}
|
|
|
|
|
2014-02-18 00:18:32 +08:00
|
|
|
std::string ContentStr = Doc.Documentation->getValueAsString("Content");
|
2014-02-17 23:27:10 +08:00
|
|
|
// Trim leading and trailing newlines and spaces.
|
2015-04-11 05:37:21 +08:00
|
|
|
OS << StringRef(ContentStr).trim();
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
OS << "\n\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
|
|
|
|
// Get the documentation introduction paragraph.
|
|
|
|
const Record *Documentation = Records.getDef("GlobalDocumentation");
|
|
|
|
if (!Documentation) {
|
|
|
|
PrintFatalError("The Documentation top-level definition is missing, "
|
|
|
|
"no documentation will be generated.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-20 06:59:32 +08:00
|
|
|
OS << Documentation->getValueAsString("Intro") << "\n";
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
// Gather the Documentation lists from each of the attributes, based on the
|
|
|
|
// category provided.
|
|
|
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
2014-03-03 01:38:37 +08:00
|
|
|
std::map<const Record *, std::vector<DocumentationData>> SplitDocs;
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *A : Attrs) {
|
|
|
|
const Record &Attr = *A;
|
2014-02-17 23:27:10 +08:00
|
|
|
std::vector<Record *> Docs = Attr.getValueAsListOfDefs("Documentation");
|
2014-05-21 03:47:14 +08:00
|
|
|
for (const auto *D : Docs) {
|
|
|
|
const Record &Doc = *D;
|
2014-02-20 06:59:32 +08:00
|
|
|
const Record *Category = Doc.getValueAsDef("Category");
|
2014-02-17 23:27:10 +08:00
|
|
|
// If the category is "undocumented", then there cannot be any other
|
|
|
|
// documentation categories (otherwise, the attribute would become
|
|
|
|
// documented).
|
2014-02-20 06:59:32 +08:00
|
|
|
std::string Cat = Category->getValueAsString("Name");
|
|
|
|
bool Undocumented = Cat == "Undocumented";
|
2014-02-17 23:27:10 +08:00
|
|
|
if (Undocumented && Docs.size() > 1)
|
|
|
|
PrintFatalError(Doc.getLoc(),
|
|
|
|
"Attribute is \"Undocumented\", but has multiple "
|
|
|
|
"documentation categories");
|
|
|
|
|
|
|
|
if (!Undocumented)
|
2014-02-20 06:59:32 +08:00
|
|
|
SplitDocs[Category].push_back(DocumentationData(Doc, Attr));
|
2014-02-17 23:27:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Having split the attributes out based on what documentation goes where,
|
|
|
|
// we can begin to generate sections of documentation.
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &I : SplitDocs) {
|
|
|
|
WriteCategoryHeader(I.first, OS);
|
2014-02-17 23:27:10 +08:00
|
|
|
|
|
|
|
// Walk over each of the attributes in the category and write out their
|
|
|
|
// documentation.
|
2014-03-03 01:38:37 +08:00
|
|
|
for (const auto &Doc : I.second)
|
|
|
|
WriteDocumentation(Doc, OS);
|
2014-02-17 23:27:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-13 13:12:41 +08:00
|
|
|
} // end namespace clang
|