diff --git a/clang/include/clang/Basic/Attributes.h b/clang/include/clang/Basic/Attributes.h new file mode 100644 index 000000000000..48242fe641be --- /dev/null +++ b/clang/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/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 546afd87c908..e4929b5b52b9 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/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/clang/include/clang/Basic/Makefile b/clang/include/clang/Basic/Makefile index 2c8dde44ea15..5579a9990051 100644 --- a/clang/include/clang/Basic/Makefile +++ b/clang/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/clang/include/clang/CMakeLists.txt b/clang/include/clang/CMakeLists.txt index 71c37fda7891..1d8aecd3b24e 100644 --- a/clang/include/clang/CMakeLists.txt +++ b/clang/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/clang/include/clang/Lex/CMakeLists.txt b/clang/include/clang/Lex/CMakeLists.txt deleted file mode 100644 index c41884efb4b8..000000000000 --- a/clang/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/clang/include/clang/Lex/Makefile b/clang/include/clang/Lex/Makefile deleted file mode 100644 index 762b9a258758..000000000000 --- a/clang/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/clang/include/clang/Makefile b/clang/include/clang/Makefile index 5f2077d2f041..5ba2dd2991b8 100644 --- a/clang/include/clang/Makefile +++ b/clang/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/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp new file mode 100644 index 000000000000..c882bc226d47 --- /dev/null +++ b/clang/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/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index d248d3dc8275..0448fdb0d41b 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 917d434c4839..62a89c03e185 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index a0749ebaf29e..e03afe4eccf8 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/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/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 6737f7774989..4484e65097cf 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/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/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index f8e11a66eb05..7e05496647d9 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/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);