summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2014-03-27 20:19:24 +0000
committerAaron Ballman <aaron@aaronballman.com>2014-03-27 20:19:24 +0000
commitaf55a6bbeea1c29624830af45fced83349edafa2 (patch)
tree14ad7d920a15a17a06922d360f519fcadaf0543c /utils
parentebece3658833fd3e7423738fe3a63b7ff4a4fb09 (diff)
Clean up the __has_attribute implementation without modifying its behavior.
Replaces the tablegen-driven AttrSpellings.inc, which lived in the lexing layer with AttrHasAttributeImpl.inc, which lives in the basic layer. Updates the preprocessor to call through to this new functionality which can take additional information into account (such as scopes and syntaxes). Expose the ability for parts of the compiler to ask whether an attribute is supported for a given spelling (including scope), syntax, triple and language options. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204952 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp90
-rw-r--r--utils/TableGen/TableGen.cpp9
-rw-r--r--utils/TableGen/TableGenBackends.h2
3 files changed, 81 insertions, 20 deletions
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index a0749ebaf2..5780284fcc 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -1720,22 +1720,16 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
OS << " }\n";
}
-// Emits the list of spellings for attributes.
-void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("llvm::StringSwitch code to match attributes based on "
- "the target triple, T", OS);
-
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
- for (auto I : Attrs) {
- Record &Attr = *I;
-
+static void GenerateHasAttrSpellingStringSwitch(
+ const std::vector<Record *> &Attrs, raw_ostream &OS,
+ const std::string &Variety = "", const std::string &Scope = "") {
+ for (const auto *Attr : Attrs) {
// It is assumed that there will be an llvm::Triple object named T within
// scope that can be used to determine whether the attribute exists in
// a given target.
std::string Test;
- if (Attr.isSubClassOf("TargetSpecificAttr")) {
- const Record *R = Attr.getValueAsDef("Target");
+ if (Attr->isSubClassOf("TargetSpecificAttr")) {
+ const Record *R = Attr->getValueAsDef("Target");
std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
Test += "(";
@@ -1760,13 +1754,79 @@ void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
}
Test += ")";
}
- } else
+
+ // 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";
+ else
Test = "true";
- std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
for (const auto &S : Spellings)
- OS << ".Case(\"" << S.name() << "\", " << Test << ")\n";
+ if (Variety.empty() || (Variety == S.variety() &&
+ (Scope.empty() || Scope == S.nameSpace())))
+ OS << " .Case(\"" << S.name() << "\", " << Test << ")\n";
+ }
+ OS << " .Default(false);\n";
+}
+
+// Emits the list of spellings for attributes.
+void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Code to implement the __has_attribute logic", OS);
+
+ // Separate all of the attributes out into four group: generic, C++11, GNU,
+ // and declspecs. Then generate a big switch statement for each of them.
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ std::vector<Record *> Declspec, GNU;
+ 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) {
+ std::string Variety = SI.variety();
+ if (Variety == "GNU")
+ GNU.push_back(R);
+ else if (Variety == "Declspec")
+ Declspec.push_back(R);
+ else if (Variety == "CXX11") {
+ CXX[SI.nameSpace()].push_back(R);
+ }
+ }
+ }
+
+ OS << "switch (Syntax) {\n";
+ OS << "case AttrSyntax::Generic:\n";
+ OS << " return llvm::StringSwitch<bool>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(Attrs, OS);
+ OS << "case AttrSyntax::GNU:\n";
+ OS << " return llvm::StringSwitch<bool>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU");
+ OS << "case AttrSyntax::Declspec:\n";
+ OS << " return llvm::StringSwitch<bool>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
+ OS << "case AttrSyntax::CXX: {\n";
+ // C++11-style attributes are further split out based on the Scope.
+ for (std::map<std::string, std::vector<Record *>>::iterator I = CXX.begin(),
+ E = CXX.end();
+ I != E; ++I) {
+ if (I != CXX.begin())
+ OS << " else ";
+ if (I->first.empty())
+ OS << "if (!Scope || Scope->getName() == \"\") {\n";
+ else
+ OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
+ OS << " return llvm::StringSwitch<bool>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
+ OS << "}";
}
+ OS << "\n}\n";
+ OS << "}\n";
}
void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 6737f77749..4484e65097 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -29,7 +29,7 @@ enum ActionType {
GenClangAttrList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
- GenClangAttrSpellingList,
+ GenClangAttrHasAttributeImpl,
GenClangAttrSpellingListIndex,
GenClangAttrASTVisitor,
GenClangAttrTemplateInstantiate,
@@ -72,7 +72,8 @@ cl::opt<ActionType> Action(
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
"Generate clang PCH attribute writer"),
- clEnumValN(GenClangAttrSpellingList, "gen-clang-attr-spelling-list",
+ clEnumValN(GenClangAttrHasAttributeImpl,
+ "gen-clang-attr-has-attribute-impl",
"Generate a clang attribute spelling list"),
clEnumValN(GenClangAttrSpellingListIndex,
"gen-clang-attr-spelling-index",
@@ -159,8 +160,8 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrPCHWrite:
EmitClangAttrPCHWrite(Records, OS);
break;
- case GenClangAttrSpellingList:
- EmitClangAttrSpellingList(Records, OS);
+ case GenClangAttrHasAttributeImpl:
+ EmitClangAttrHasAttrImpl(Records, OS);
break;
case GenClangAttrSpellingListIndex:
EmitClangAttrSpellingListIndex(Records, OS);
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index f8e11a66eb..7e05496647 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -35,7 +35,7 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
-void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);