From 3056e7cbc99ea69d655b110e4c6ceb92079522f6 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Mon, 31 Mar 2014 13:14:44 +0000 Subject: [PATCH] Reapplying r204952 a second time. 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@205181 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attributes.h | 39 +++++++++++++ include/clang/Basic/CMakeLists.txt | 6 ++ include/clang/Basic/Makefile | 7 +++ include/clang/CMakeLists.txt | 1 - include/clang/Lex/CMakeLists.txt | 5 -- include/clang/Lex/Makefile | 13 ----- include/clang/Makefile | 2 +- lib/Basic/Attributes.cpp | 17 ++++++ lib/Basic/CMakeLists.txt | 1 + lib/Lex/PPMacroExpansion.cpp | 18 +----- utils/TableGen/ClangAttrEmitter.cpp | 90 ++++++++++++++++++++++++----- utils/TableGen/TableGen.cpp | 9 +-- utils/TableGen/TableGenBackends.h | 2 +- 13 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 include/clang/Basic/Attributes.h delete mode 100644 include/clang/Lex/CMakeLists.txt delete mode 100644 include/clang/Lex/Makefile create mode 100644 lib/Basic/Attributes.cpp diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h new file mode 100644 index 0000000000..48242fe641 --- /dev/null +++ b/include/clang/Basic/Attributes.h @@ -0,0 +1,39 @@ +//===--- Attributes.h - Attributes header -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ATTRIBUTES_H +#define LLVM_CLANG_BASIC_ATTRIBUTES_H + +#include "llvm/ADT/Triple.h" +#include "clang/Basic/LangOptions.h" + +namespace clang { + +class IdentifierInfo; + +enum class AttrSyntax { + /// Is the attribute identifier generally known for any syntax? + Generic, + /// Is the identifier known as a GNU-style attribute? + GNU, + /// Is the identifier known as a __declspec-style attribute? + Declspec, + // Is the identifier known as a C++-style attribute? + CXX +}; + +/// \brief Return true if we recognize and implement the attribute specified by +/// the given information. +bool HasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, + const IdentifierInfo *Attr, const llvm::Triple &T, + const LangOptions &LangOpts); + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_ATTRIBUTES_H diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt index 546afd87c9..e4929b5b52 100644 --- a/include/clang/Basic/CMakeLists.txt +++ b/include/clang/Basic/CMakeLists.txt @@ -28,6 +28,12 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list SOURCE Attr.td TARGET ClangAttrList) +clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrHasAttributeImpl + ) + # ARM NEON clang_tablegen(arm_neon.inc -gen-arm-neon-sema -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile index 2c8dde44ea..5579a99900 100644 --- a/include/clang/Basic/Makefile +++ b/include/clang/Basic/Makefile @@ -6,6 +6,7 @@ BUILT_SOURCES = \ DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \ DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \ DiagnosticSerializationKinds.inc \ + AttrHasAttributeImpl.inc \ DiagnosticIndexName.inc DiagnosticGroups.inc AttrList.inc arm_neon.inc \ Version.inc @@ -48,6 +49,12 @@ $(ObjDir)/AttrList.inc.tmp : Attr.td $(CLANG_TBLGEN) $(ObjDir)/.dir $(Verb) $(ClangTableGen) -gen-clang-attr-list -o $(call SYSPATH, $@) \ -I $(PROJ_SRC_DIR)/../.. $< +$(ObjDir)/AttrHasAttributeImpl.inc.tmp : Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang __has_attribute implementation with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-has-attribute-impl -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< + $(ObjDir)/arm_neon.inc.tmp : arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang arm_neon.inc with tblgen" $(Verb) $(ClangTableGen) -gen-arm-neon-sema -o $(call SYSPATH, $@) \ diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt index 71c37fda78..1d8aecd3b2 100644 --- a/include/clang/CMakeLists.txt +++ b/include/clang/CMakeLists.txt @@ -1,7 +1,6 @@ add_subdirectory(AST) add_subdirectory(Basic) add_subdirectory(Driver) -add_subdirectory(Lex) add_subdirectory(Parse) add_subdirectory(Sema) add_subdirectory(Serialization) diff --git a/include/clang/Lex/CMakeLists.txt b/include/clang/Lex/CMakeLists.txt deleted file mode 100644 index c41884efb4..0000000000 --- a/include/clang/Lex/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -clang_tablegen(AttrSpellings.inc -gen-clang-attr-spelling-list - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE ../Basic/Attr.td - TARGET ClangAttrSpellings - ) diff --git a/include/clang/Lex/Makefile b/include/clang/Lex/Makefile deleted file mode 100644 index 762b9a2587..0000000000 --- a/include/clang/Lex/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -CLANG_LEVEL := ../../.. -TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic -BUILT_SOURCES = AttrSpellings.inc - -TABLEGEN_INC_FILES_COMMON = 1 - -include $(CLANG_LEVEL)/Makefile - -$(ObjDir)/AttrSpellings.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ - $(ObjDir)/.dir - $(Echo) "Building Clang attribute spellings with tblgen" - $(Verb) $(ClangTableGen) -gen-clang-attr-spelling-list -o $(call SYSPATH, $@) \ - -I $(PROJ_SRC_DIR)/../../ $< diff --git a/include/clang/Makefile b/include/clang/Makefile index 5f2077d2f0..5ba2dd2991 100644 --- a/include/clang/Makefile +++ b/include/clang/Makefile @@ -1,5 +1,5 @@ CLANG_LEVEL := ../.. -DIRS := AST Basic Driver Lex Parse Sema Serialization +DIRS := AST Basic Driver Parse Sema Serialization include $(CLANG_LEVEL)/Makefile diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp new file mode 100644 index 0000000000..c882bc226d --- /dev/null +++ b/lib/Basic/Attributes.cpp @@ -0,0 +1,17 @@ +#include "clang/Basic/Attributes.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +bool clang::HasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, + const IdentifierInfo *Attr, const llvm::Triple &T, + const LangOptions &LangOpts) { + StringRef Name = Attr->getName(); + // Normalize the attribute name, __foo__ becomes foo. + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + Name = Name.substr(2, Name.size() - 4); + +#include "clang/Basic/AttrHasAttributeImpl.inc" + + return false; +} diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index d248d3dc82..0448fdb0d4 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangBasic + Attributes.cpp Builtins.cpp CharInfo.cpp Diagnostic.cpp diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 917d434c48..62a89c03e1 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Attributes.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -1047,20 +1048,6 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { .Default(false); } -/// HasAttribute - Return true if we recognize and implement the attribute -/// specified by the given identifier. -static bool HasAttribute(const IdentifierInfo *II, const llvm::Triple &T) { - StringRef Name = II->getName(); - // Normalize the attribute name, __foo__ becomes foo. - if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) - Name = Name.substr(2, Name.size() - 4); - - // FIXME: Do we need to handle namespaces here? - return llvm::StringSwitch(Name) -#include "clang/Lex/AttrSpellings.inc" - .Default(false); -} - /// EvaluateHasIncludeCommon - Process a '__has_include("path")' /// or '__has_include_next("path")' expression. /// Returns true if successful. @@ -1399,7 +1386,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) - Value = HasAttribute(FeatureII, getTargetInfo().getTriple()); + Value = HasAttribute(AttrSyntax::Generic, nullptr, FeatureII, + getTargetInfo().getTriple(), getLangOpts()); else if (II == Ident__has_extension) Value = HasExtension(*this, FeatureII); else { diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index a0749ebaf2..e03afe4ecc 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 Attrs = Records.getAllDerivedDefinitions("Attr"); - - for (auto I : Attrs) { - Record &Attr = *I; - +static void GenerateHasAttrSpellingStringSwitch( + const std::vector &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 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 Spellings = GetFlattenedSpellings(Attr); + std::vector 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 Attrs = Records.getAllDerivedDefinitions("Attr"); + std::vector Declspec, GNU; + std::map> CXX; + + // Walk over the list of all attributes, and split them out based on the + // spelling variety. + for (auto *R : Attrs) { + std::vector 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(Name)\n"; + GenerateHasAttrSpellingStringSwitch(Attrs, OS); + OS << "case AttrSyntax::GNU:\n"; + OS << " return llvm::StringSwitch(Name)\n"; + GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU"); + OS << "case AttrSyntax::Declspec:\n"; + OS << " return llvm::StringSwitch(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>::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(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 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); -- 2.40.0