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.

llvm-svn: 205181
diff --git a/clang/include/clang/Basic/Attributes.h b/clang/include/clang/Basic/Attributes.h
new file mode 100644
index 0000000..48242fe
--- /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 546afd8..e4929b5 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -28,6 +28,12 @@
   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 2c8dde4..5579a99 100644
--- a/clang/include/clang/Basic/Makefile
+++ b/clang/include/clang/Basic/Makefile
@@ -6,6 +6,7 @@
 	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 @@
 	$(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 71c37fd..1d8aecd 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 c41884ef..0000000
--- 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 762b9a2..0000000
--- 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 5f2077d..5ba2dd2 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 0000000..c882bc2
--- /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 d248d3d..0448fdb 100644
--- a/clang/lib/Basic/CMakeLists.txt
+++ b/clang/lib/Basic/CMakeLists.txt
@@ -4,6 +4,7 @@
   )
 
 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 917d434..62a89c0 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 @@
            .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 @@
       // 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 a0749eb..e03afe4 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1720,22 +1720,16 @@
   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 @@
         }
         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/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index 6737f77..4484e65 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -29,7 +29,7 @@
   GenClangAttrList,
   GenClangAttrPCHRead,
   GenClangAttrPCHWrite,
-  GenClangAttrSpellingList,
+  GenClangAttrHasAttributeImpl,
   GenClangAttrSpellingListIndex,
   GenClangAttrASTVisitor,
   GenClangAttrTemplateInstantiate,
@@ -72,7 +72,8 @@
                    "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 @@
   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 f8e11a6..7e05496 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -35,7 +35,7 @@
 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);