]> granicus.if.org Git - clang/commitdiff
Clean up the __has_attribute implementation without modifying its behavior.
authorAaron Ballman <aaron@aaronballman.com>
Thu, 27 Mar 2014 20:19:24 +0000 (20:19 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Thu, 27 Mar 2014 20:19:24 +0000 (20:19 +0000)
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

13 files changed:
include/clang/Basic/Attributes.h [new file with mode: 0644]
include/clang/Basic/CMakeLists.txt
include/clang/Basic/Makefile
include/clang/CMakeLists.txt
include/clang/Lex/CMakeLists.txt [deleted file]
include/clang/Lex/Makefile [deleted file]
include/clang/Makefile
lib/Basic/Attributes.cpp [new file with mode: 0644]
lib/Basic/CMakeLists.txt
lib/Lex/PPMacroExpansion.cpp
utils/TableGen/ClangAttrEmitter.cpp
utils/TableGen/TableGen.cpp
utils/TableGen/TableGenBackends.h

diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h
new file mode 100644 (file)
index 0000000..48242fe
--- /dev/null
@@ -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
index 274b94da8eda144b9597e7181aaaba05cccbdb59..98e8efda821a97c7540b0910584cf30edb5c6330 100644 (file)
@@ -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
   SOURCE arm_neon.td
index 6a3313325216fbabaf314c32004fda1a5aa5950a..a9358f06f5b9e86b31d1d813cefed65a1f533108 100644 (file)
@@ -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, $@) $<
index 71c37fda7891ca5cfafc9f8b22b572f4b25aeb14..1d8aecd3b24e41540ffdc6211abaa9e5b1a9d971 100644 (file)
@@ -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 (file)
index c41884e..0000000
+++ /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 (file)
index 762b9a2..0000000
+++ /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)/../../ $<
index 5f2077d2f04159f33c44f982c3da5780e6568e6a..5ba2dd2991b824282544c8059ffddfdee8c90bad 100644 (file)
@@ -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 (file)
index 0000000..555c8f8
--- /dev/null
@@ -0,0 +1,20 @@
+#include "clang/Basic/Attributes.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace clang {
+
+bool 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;
+}
+
+} // end namespace clang
index d248d3dc8275a7b8148d1bf9ef59be1514ac4de8..0448fdb0d41bd46c606b5d789f178d32b4c1a667 100644 (file)
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_clang_library(clangBasic
+  Attributes.cpp
   Builtins.cpp
   CharInfo.cpp
   Diagnostic.cpp
index 917d434c4839244e769a5e84d0f78c025517b8b3..62a89c03e185b5ea30aeb3b7c071241110120887 100644 (file)
@@ -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<bool>(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 {
index a0749ebaf29edd3cdd0dc624d5fd59503cc657c2..5780284fccdec2086152fee0fa9af7416ad6d57a 100644 (file)
@@ -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) {
index 6737f7774989551bc8a3b3cb7d1b7be1829c61ed..4484e65097cfd778c7ac99bc2bd9bf2a420fbf89 100644 (file)
@@ -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);
index f8e11a66eb05353a0f9e7269fee39c8f62393f47..7e05496647d96ec3b64e92e5abbe651754bd0a80 100644 (file)
@@ -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);