r198896 - Removing the notion of TargetAttributesSema and replacing it with one where the parsed attributes are responsible for knowing their target-specific nature, instead of letting Sema figure it out. This is necessary so that __has_attribute can eventually determine whether a parsed attribute applies to the given target or not.

Aaron Ballman aaron at aaronballman.com
Thu Jan 9 14:48:33 PST 2014


Author: aaronballman
Date: Thu Jan  9 16:48:32 2014
New Revision: 198896

URL: http://llvm.org/viewvc/llvm-project?rev=198896&view=rev
Log:
Removing the notion of TargetAttributesSema and replacing it with one where the parsed attributes are responsible for knowing their target-specific nature, instead of letting Sema figure it out. This is necessary so that __has_attribute can eventually determine whether a parsed attribute applies to the given target or not.

Removed:
    cfe/trunk/lib/Sema/TargetAttributesSema.cpp
    cfe/trunk/lib/Sema/TargetAttributesSema.h
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaStmtAttr.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jan  9 16:48:32 2014
@@ -142,6 +142,21 @@ def MicrosoftExt : LangOpt<"MicrosoftExt
 def Borland : LangOpt<"Borland">;
 def CUDA : LangOpt<"CUDA">;
 
+// Defines targets for target-specific attributes. The list of strings should
+// specify architectures for which the target applies, based off the ArchType
+// enumeration in Triple.h.
+class TargetArch<list<string> arches> {
+  list<string> Arches = arches;
+  list<string> OSes;
+}
+def TargetARM : TargetArch<["arm", "thumb"]>;
+def TargetMSP430 : TargetArch<["msp430"]>;
+def TargetX86 : TargetArch<["x86"]>;
+def TargetX86Win : TargetArch<["x86", "x86_64"]> {
+  let OSes = ["Win32", "MinGW32"];
+}
+def TargetMips : TargetArch<["mips", "mipsel"]>;
+
 class Attr {
   // The various ways in which an attribute can be spelled in source
   list<Spelling> Spellings;
@@ -187,10 +202,10 @@ class TypeAttr : Attr {
 /// An inheritable attribute is inherited by later redeclarations.
 class InheritableAttr : Attr;
 
-/// A target-specific attribute that is meant to be processed via
-/// TargetAttributesSema::ProcessDeclAttribute.  This class is meant to be used
-/// as a mixin with InheritableAttr or Attr depending on the attribute's needs.
-class TargetSpecificAttr {
+/// A target-specific attribute.  This class is meant to be used as a mixin
+/// with InheritableAttr or Attr depending on the attribute's needs.
+class TargetSpecificAttr<TargetArch target> {
+  TargetArch Target = target;
   // Attributes are generally required to have unique spellings for their names
   // so that the parser can determine what kind of attribute it has parsed.
   // However, target-specific attributes are special in that the attribute only
@@ -269,7 +284,7 @@ def Annotate : InheritableParamAttr {
   let Args = [StringArgument<"Annotation">];
 }
 
-def ARMInterrupt : InheritableAttr, TargetSpecificAttr {
+def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
   // NOTE: If you add any additional spellings, MSP430Interrupt's spellings
   // must match.
   let Spellings = [GNU<"interrupt">];
@@ -547,7 +562,7 @@ def MSABI : InheritableAttr {
 //  let Subjects = [Function, ObjCMethod];
 }
 
-def MSP430Interrupt : InheritableAttr, TargetSpecificAttr {
+def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
   // NOTE: If you add any additional spellings, ARMInterrupt's spellings must
   // match.
   let Spellings = [GNU<"interrupt">];
@@ -556,7 +571,7 @@ def MSP430Interrupt : InheritableAttr, T
   let HasCustomParsing = 1;
 }
 
-def Mips16 : InheritableAttr, TargetSpecificAttr {
+def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
   let Spellings = [GNU<"mips16">, CXX11<"gnu", "mips16">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
 }
@@ -600,7 +615,7 @@ def NoInline : InheritableAttr {
   let Subjects = SubjectList<[Function]>;
 }
 
-def NoMips16 : InheritableAttr, TargetSpecificAttr {
+def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
   let Spellings = [GNU<"nomips16">, CXX11<"gnu", "nomips16">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
 }
@@ -952,8 +967,11 @@ def WeakRef : InheritableAttr {
   let Subjects = SubjectList<[Var, Function], ErrorDiag>;
 }
 
-def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr {
-  let Spellings = [];
+def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
+  let Spellings = [GNU<"force_align_arg_pointer">];
+  // Technically, this appertains to a FunctionDecl, but the target-specific
+  // code silently allows anything function-like (such as typedefs or function
+  // pointers), but does not apply the attribute to them.
 }
 
 // Attribute to disable AddressSanitizer (or equivalent) checks.
@@ -1232,12 +1250,12 @@ def MsStruct : InheritableAttr {
   let Subjects = SubjectList<[Record]>;
 }
 
-def DLLExport : InheritableAttr, TargetSpecificAttr {
+def DLLExport : InheritableAttr, TargetSpecificAttr<TargetX86Win> {
   let Spellings = [Declspec<"dllexport">];
   let Subjects = SubjectList<[Function, Var]>;
 }
 
-def DLLImport : InheritableAttr, TargetSpecificAttr {
+def DLLImport : InheritableAttr, TargetSpecificAttr<TargetX86Win> {
   let Spellings = [Declspec<"dllimport">];
   // Technically, the subjects for DllImport are Function and Var, but there is
   // custom semantic handling required when MicrosoftExt is true.

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Jan  9 16:48:32 2014
@@ -20,6 +20,7 @@
 #include "clang/Sema/Ownership.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Support/Allocator.h"
 #include <cassert>
 
@@ -484,11 +485,15 @@ public:
   /// to pretty print itself.
   unsigned getAttributeSpellingListIndex() const;
 
+  bool isTargetSpecificAttr() const;
+  bool isTypeAttr() const;
+
   bool hasCustomParsing() const;
   unsigned getMinArgs() const;
   unsigned getMaxArgs() const;
   bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
   bool diagnoseLangOpts(class Sema &S) const;
+  bool existsInTarget(llvm::Triple T) const;
 };
 
 /// A factory, from which one makes pools, from which one creates

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan  9 16:48:32 2014
@@ -152,7 +152,6 @@ namespace clang {
   class Stmt;
   class StringLiteral;
   class SwitchStmt;
-  class TargetAttributesSema;
   class TemplateArgument;
   class TemplateArgumentList;
   class TemplateArgumentLoc;
@@ -204,7 +203,6 @@ typedef std::pair<llvm::PointerUnion<con
 class Sema {
   Sema(const Sema &) LLVM_DELETED_FUNCTION;
   void operator=(const Sema &) LLVM_DELETED_FUNCTION;
-  mutable const TargetAttributesSema* TheTargetAttributesSema;
 
   ///\brief Source of additional semantic information.
   ExternalSemaSource *ExternalSource;
@@ -875,7 +873,6 @@ public:
 
   DiagnosticsEngine &getDiagnostics() const { return Diags; }
   SourceManager &getSourceManager() const { return SourceMgr; }
-  const TargetAttributesSema &getTargetAttributesSema() const;
   Preprocessor &getPreprocessor() const { return PP; }
   ASTContext &getASTContext() const { return Context; }
   ASTConsumer &getASTConsumer() const { return Consumer; }

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Jan  9 16:48:32 2014
@@ -156,10 +156,13 @@ struct ParsedAttrInfo {
   unsigned NumArgs : 4;
   unsigned OptArgs : 4;
   unsigned HasCustomParsing : 1;
+  unsigned IsTargetSpecific : 1;
+  unsigned IsType : 1;
 
   bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
                                const Decl *);
   bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
+  bool (*ExistsInTarget)(llvm::Triple T);
 };
 
 namespace {
@@ -189,3 +192,15 @@ bool AttributeList::diagnoseAppertainsTo
 bool AttributeList::diagnoseLangOpts(Sema &S) const {
   return getInfo(*this).DiagLangOpts(S, *this);
 }
+
+bool AttributeList::isTargetSpecificAttr() const {
+  return getInfo(*this).IsTargetSpecific;
+}
+
+bool AttributeList::isTypeAttr() const {
+  return getInfo(*this).IsType;
+}
+
+bool AttributeList::existsInTarget(llvm::Triple T) const {
+  return getInfo(*this).ExistsInTarget(T);
+}

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Thu Jan  9 16:48:32 2014
@@ -47,7 +47,6 @@ add_clang_library(clangSema
   SemaTemplateInstantiateDecl.cpp
   SemaTemplateVariadic.cpp
   SemaType.cpp
-  TargetAttributesSema.cpp
   TypeLocBuilder.cpp
   )
 

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Jan  9 16:48:32 2014
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/DeclCXX.h"
@@ -70,7 +69,7 @@ void Sema::ActOnTranslationUnitScope(Sco
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
            TranslationUnitKind TUKind,
            CodeCompleteConsumer *CodeCompleter)
-  : TheTargetAttributesSema(0), ExternalSource(0),
+  : ExternalSource(0),
     isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
     LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
@@ -209,7 +208,6 @@ Sema::~Sema() {
     delete I->second;
   if (PackContext) FreePackedContext();
   if (VisContext) FreeVisContext();
-  delete TheTargetAttributesSema;
   MSStructPragmaOn = false;
   // Kill all the active scopes.
   for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I)

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jan  9 16:48:32 2014
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
@@ -205,7 +204,6 @@ static bool checkAttributeNumArgs(Sema &
   return true;
 }
 
-
 /// \brief Check if the attribute has at least as many args as Num. May
 /// output an error.
 static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
@@ -3174,8 +3172,7 @@ bool Sema::CheckCallingConvAttr(const At
     return true;
   }
 
-  // TODO: diagnose uses of these conventions on the wrong target. Or, better
-  // move to TargetAttributesSema one day.
+  // TODO: diagnose uses of these conventions on the wrong target.
   switch (attr.getKind()) {
   case AttributeList::AT_CDecl: CC = CC_C; break;
   case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
@@ -3712,6 +3709,179 @@ static void handleUuidAttr(Sema &S, Decl
                                         Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleARMInterruptAttr(Sema &S, Decl *D,
+                                   const AttributeList &Attr) {
+  // Check the attribute arguments.
+  if (Attr.getNumArgs() > 1) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+      << Attr.getName() << 1;
+    return;
+  }
+
+  StringRef Str;
+  SourceLocation ArgLoc;
+
+  if (Attr.getNumArgs() == 0)
+    Str = "";
+  else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
+    return;
+
+  ARMInterruptAttr::InterruptType Kind;
+  if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+      << Attr.getName() << Str << ArgLoc;
+    return;
+  }
+
+  unsigned Index = Attr.getAttributeSpellingListIndex();
+  D->addAttr(::new (S.Context)
+             ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
+}
+
+static void handleMSP430InterruptAttr(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  if (!checkAttributeNumArgs(S, Attr, 1))
+    return;
+
+  if (!Attr.isArgExpr(0)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
+      << AANT_ArgumentIntegerConstant;
+    return;    
+  }
+
+  // FIXME: Check for decl - it should be void ()(void).
+
+  Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+  llvm::APSInt NumParams(32);
+  if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+      << Attr.getName() << AANT_ArgumentIntegerConstant
+      << NumParamsExpr->getSourceRange();
+    return;
+  }
+
+  unsigned Num = NumParams.getLimitedValue(255);
+  if ((Num & 1) || Num > 30) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+      << Attr.getName() << (int)NumParams.getSExtValue()
+      << NumParamsExpr->getSourceRange();
+    return;
+  }
+
+  D->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
+  D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  // Dispatch the interrupt attribute based on the current target.
+  if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
+    handleMSP430InterruptAttr(S, D, Attr);
+  else
+    handleARMInterruptAttr(S, D, Attr);
+}
+
+static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
+                                              const AttributeList& Attr) {
+  // If we try to apply it to a function pointer, don't warn, but don't
+  // do anything, either. It doesn't matter anyway, because there's nothing
+  // special about calling a force_align_arg_pointer function.
+  ValueDecl *VD = dyn_cast<ValueDecl>(D);
+  if (VD && VD->getType()->isFunctionPointerType())
+    return;
+  // Also don't warn on function pointer typedefs.
+  TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
+  if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
+    TD->getUnderlyingType()->isFunctionType()))
+    return;
+  // Attribute can only be applied to function types.
+  if (!isa<FunctionDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << /* function */0;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
+    S.Context));
+}
+
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
+                                        unsigned AttrSpellingListIndex) {
+  if (D->hasAttr<DLLExportAttr>()) {
+    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
+    return NULL;
+  }
+
+  if (D->hasAttr<DLLImportAttr>())
+    return NULL;
+
+  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    if (VD->hasDefinition()) {
+      // dllimport cannot be applied to definitions.
+      Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
+        << "dllimport";
+      return NULL;
+    }
+  }
+
+  return ::new (Context)DLLImportAttr(Range, Context,
+                                      AttrSpellingListIndex);
+}
+
+static void handleDLLImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  // Attribute can be applied only to functions or variables.
+  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+  if (!FD && !isa<VarDecl>(D)) {
+    // Apparently Visual C++ thinks it is okay to not emit a warning
+    // in this case, so only emit a warning when -fms-extensions is not
+    // specified.
+    if (!S.getLangOpts().MicrosoftExt)
+      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << 2 /*variable and function*/;
+    return;
+  }
+
+  // Currently, the dllimport attribute is ignored for inlined functions.
+  // Warning is emitted.
+  if (FD && FD->isInlineSpecified()) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+    return;
+  }
+
+  unsigned Index = Attr.getAttributeSpellingListIndex();
+  DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
+  if (NewAttr)
+    D->addAttr(NewAttr);
+}
+
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
+                                        unsigned AttrSpellingListIndex) {
+  if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
+    Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
+    D->dropAttr<DLLImportAttr>();
+  }
+
+  if (D->hasAttr<DLLExportAttr>())
+    return NULL;
+
+  return ::new (Context)DLLExportAttr(Range, Context,
+                                      AttrSpellingListIndex);
+}
+
+static void handleDLLExportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  // Currently, the dllexport attribute is ignored for inlined functions, unless
+  // the -fkeep-inline-functions flag has been used. Warning is emitted;
+  if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) {
+    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+    return;
+  }
+
+  unsigned Index = Attr.getAttributeSpellingListIndex();
+  DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
+  if (NewAttr)
+    D->addAttr(NewAttr);
+}
+
 /// Handles semantic checking for features that are common to all attributes,
 /// such as checking whether a parameter was properly specified, or the correct
 /// number of arguments were passed, etc.
@@ -3723,8 +3893,7 @@ static bool handleCommonAttributeFeature
   // We also bail on unknown and ignored attributes because those are handled
   // as part of the target-specific handling logic.
   if (Attr.hasCustomParsing() ||
-      Attr.getKind() == AttributeList::UnknownAttribute ||
-      Attr.getKind() == AttributeList::IgnoredAttribute)
+      Attr.getKind() == AttributeList::UnknownAttribute)
     return false;
 
   // Check whether the attribute requires specific language extensions to be
@@ -3755,7 +3924,7 @@ static bool handleCommonAttributeFeature
 static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
                                  const AttributeList &Attr,
                                  bool IncludeCXX11Attributes) {
-  if (Attr.isInvalid())
+  if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute)
     return;
 
   // Ignore C++11 attributes on declarator chunks: they appertain to the type
@@ -3763,28 +3932,42 @@ static void ProcessDeclAttribute(Sema &S
   if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
     return;
 
+  // Unknown attributes are automatically warned on. Target-specific attributes
+  // which do not apply to the current target architecture are treated as
+  // though they were unknown attributes.
+  if (Attr.getKind() == AttributeList::UnknownAttribute ||
+      !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) {
+    S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ?
+            diag::warn_unhandled_ms_attribute_ignored :
+            diag::warn_unknown_attribute_ignored) << Attr.getName();
+    return;
+  }
+  
   if (handleCommonAttributeFeatures(S, scope, D, Attr))
     return;
 
   switch (Attr.getKind()) {
+  default:
+      // Type attributes are handled elsewhere; silently move on.
+    assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+  break;
+  case AttributeList::AT_Interrupt:
+    handleInterruptAttr(S, D, Attr); break;
+  case AttributeList::AT_X86ForceAlignArgPointer:
+    handleX86ForceAlignArgPointerAttr(S, D, Attr); break;
+  case AttributeList::AT_DLLExport:
+    handleDLLExportAttr(S, D, Attr); break;
+  case AttributeList::AT_DLLImport:
+    handleDLLImportAttr(S, D, Attr); break;
+  case AttributeList::AT_Mips16:
+    handleSimpleAttribute<Mips16Attr>(S, D, Attr); break;
+  case AttributeList::AT_NoMips16:
+    handleSimpleAttribute<NoMips16Attr>(S, D, Attr); break;
   case AttributeList::AT_IBAction:
     handleSimpleAttribute<IBActionAttr>(S, D, Attr); break;
   case AttributeList::AT_IBOutlet:    handleIBOutlet(S, D, Attr); break;
   case AttributeList::AT_IBOutletCollection:
     handleIBOutletCollection(S, D, Attr); break;
-  case AttributeList::AT_AddressSpace:
-  case AttributeList::AT_ObjCGC:
-  case AttributeList::AT_VectorSize:
-  case AttributeList::AT_NeonVectorType:
-  case AttributeList::AT_NeonPolyVectorType:
-  case AttributeList::AT_Ptr32:
-  case AttributeList::AT_Ptr64:
-  case AttributeList::AT_SPtr:
-  case AttributeList::AT_UPtr:
-  case AttributeList::AT_Regparm:
-    // Ignore these, these are type attributes, handled by
-    // ProcessTypeAttributes.
-    break;
   case AttributeList::AT_Alias:       handleAliasAttr       (S, D, Attr); break;
   case AttributeList::AT_Aligned:     handleAlignedAttr     (S, D, Attr); break;
   case AttributeList::AT_AlwaysInline:
@@ -3946,9 +4129,6 @@ static void ProcessDeclAttribute(Sema &S
   case AttributeList::AT_NoDebug:     handleNoDebugAttr     (S, D, Attr); break;
   case AttributeList::AT_NoInline:
     handleSimpleAttribute<NoInlineAttr>(S, D, Attr); break;
-  case AttributeList::IgnoredAttribute:
-    // Just ignore
-    break;
   case AttributeList::AT_NoInstrumentFunction:  // Interacts with -pg.
     handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); break;
   case AttributeList::AT_StdCall:
@@ -4078,15 +4258,6 @@ static void ProcessDeclAttribute(Sema &S
   case AttributeList::AT_TypeTagForDatatype:
     handleTypeTagForDatatypeAttr(S, D, Attr);
     break;
-
-  default:
-    // Ask target about the attribute.
-    const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
-    if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
-      S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? 
-             diag::warn_unhandled_ms_attribute_ignored : 
-             diag::warn_unknown_attribute_ignored) << Attr.getName();
-    break;
   }
 }
 

Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Thu Jan  9 16:48:32 2014
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Lexer.h"

Removed: cfe/trunk/lib/Sema/TargetAttributesSema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TargetAttributesSema.cpp?rev=198895&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/TargetAttributesSema.cpp (original)
+++ cfe/trunk/lib/Sema/TargetAttributesSema.cpp (removed)
@@ -1,295 +0,0 @@
-//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains semantic analysis implementation for target-specific
-// attributes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "TargetAttributesSema.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Sema/SemaInternal.h"
-#include "llvm/ADT/Triple.h"
-
-using namespace clang;
-
-TargetAttributesSema::~TargetAttributesSema() {}
-bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
-                                    const AttributeList &Attr, Sema &S) const {
-  return false;
-}
-
-static void HandleARMInterruptAttr(Decl *d,
-                                   const AttributeList &Attr, Sema &S) {
-  // Check the attribute arguments.
-  if (Attr.getNumArgs() > 1) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
-      << Attr.getName() << 1;
-    return;
-  }
-
-  StringRef Str;
-  SourceLocation ArgLoc;
-
-  if (Attr.getNumArgs() == 0)
-    Str = "";
-  else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
-    return;
-
-  ARMInterruptAttr::InterruptType Kind;
-  if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
-        << Attr.getName() << Str << ArgLoc;
-    return;
-  }
-
-  unsigned Index = Attr.getAttributeSpellingListIndex();
-  d->addAttr(::new (S.Context)
-             ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
-}
-
-namespace {
-  class ARMAttributesSema : public TargetAttributesSema {
-  public:
-    ARMAttributesSema() { }
-    bool ProcessDeclAttribute(Scope *scope, Decl *D,
-                              const AttributeList &Attr, Sema &S) const {
-      if (Attr.getKind() == AttributeList::AT_Interrupt) {
-        HandleARMInterruptAttr(D, Attr, S);
-        return true;
-      }
-      return false;
-    }
-  };
-}
-
-static void HandleMSP430InterruptAttr(Decl *d,
-                                      const AttributeList &Attr, Sema &S) {
-  if (Attr.getNumArgs() != 1) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
-      << Attr.getName() << 1;
-    return;
-  }
-
-  if (!Attr.isArgExpr(0)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
-      << AANT_ArgumentIntegerConstant;
-    return;
-  }
-
-  // FIXME: Check for decl - it should be void ()(void).
-  Expr *NumParamsExpr = Attr.getArgAsExpr(0);
-  llvm::APSInt NumParams(32);
-  if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
-      << Attr.getName() << AANT_ArgumentIntegerConstant
-      << NumParamsExpr->getSourceRange();
-    return;
-  }
-
-  unsigned Num = NumParams.getLimitedValue(255);
-  if ((Num & 1) || Num > 30) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
-      << Attr.getName() << (int)NumParams.getSExtValue()
-      << NumParamsExpr->getSourceRange();
-    return;
-  }
-
-  d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
-  d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
-}
-
-namespace {
-  class MSP430AttributesSema : public TargetAttributesSema {
-  public:
-    MSP430AttributesSema() { }
-    bool ProcessDeclAttribute(Scope *scope, Decl *D,
-                              const AttributeList &Attr, Sema &S) const {
-      if (Attr.getKind() == AttributeList::AT_Interrupt) {
-        HandleMSP430InterruptAttr(D, Attr, S);
-        return true;
-      }
-      return false;
-    }
-  };
-}
-
-static void HandleX86ForceAlignArgPointerAttr(Decl *D,
-                                              const AttributeList& Attr,
-                                              Sema &S) {
-  // If we try to apply it to a function pointer, don't warn, but don't
-  // do anything, either. It doesn't matter anyway, because there's nothing
-  // special about calling a force_align_arg_pointer function.
-  ValueDecl *VD = dyn_cast<ValueDecl>(D);
-  if (VD && VD->getType()->isFunctionPointerType())
-    return;
-  // Also don't warn on function pointer typedefs.
-  TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
-  if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
-             TD->getUnderlyingType()->isFunctionType()))
-    return;
-  // Attribute can only be applied to function types.
-  if (!isa<FunctionDecl>(D)) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << Attr.getName() << /* function */0;
-    return;
-  }
-
-  D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
-                                                           S.Context));
-}
-
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
-                                        unsigned AttrSpellingListIndex) {
-  if (D->hasAttr<DLLExportAttr>()) {
-    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
-    return NULL;
-  }
-
-  if (D->hasAttr<DLLImportAttr>())
-    return NULL;
-
-  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-    if (VD->hasDefinition()) {
-      // dllimport cannot be applied to definitions.
-      Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
-        << "dllimport";
-      return NULL;
-    }
-  }
-
-  return ::new (Context) DLLImportAttr(Range, Context,
-                                       AttrSpellingListIndex);
-}
-
-static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
-  // Attribute can be applied only to functions or variables.
-  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
-  if (!FD && !isa<VarDecl>(D)) {
-    // Apparently Visual C++ thinks it is okay to not emit a warning
-    // in this case, so only emit a warning when -fms-extensions is not
-    // specified.
-    if (!S.getLangOpts().MicrosoftExt)
-      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << Attr.getName() << 2 /*variable and function*/;
-    return;
-  }
-
-  // Currently, the dllimport attribute is ignored for inlined functions.
-  // Warning is emitted.
-  if (FD && FD->isInlineSpecified()) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
-    return;
-  }
-
-  unsigned Index = Attr.getAttributeSpellingListIndex();
-  DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
-  if (NewAttr)
-    D->addAttr(NewAttr);
-}
-
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
-                                        unsigned AttrSpellingListIndex) {
-  if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
-    Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
-    D->dropAttr<DLLImportAttr>();
-  }
-
-  if (D->hasAttr<DLLExportAttr>())
-    return NULL;
-
-  return ::new (Context) DLLExportAttr(Range, Context,
-                                       AttrSpellingListIndex);
-}
-
-static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
-  // Currently, the dllexport attribute is ignored for inlined functions, unless
-  // the -fkeep-inline-functions flag has been used. Warning is emitted;
-  if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) {
-    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
-    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
-    return;
-  }
-
-  unsigned Index = Attr.getAttributeSpellingListIndex();
-  DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
-  if (NewAttr)
-    D->addAttr(NewAttr);
-}
-
-namespace {
-  class X86AttributesSema : public TargetAttributesSema {
-  public:
-    X86AttributesSema() { }
-    bool ProcessDeclAttribute(Scope *scope, Decl *D,
-                              const AttributeList &Attr, Sema &S) const {
-      const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
-      if (Triple.getOS() == llvm::Triple::Win32 ||
-          Triple.getOS() == llvm::Triple::MinGW32) {
-        switch (Attr.getKind()) {
-        case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S);
-                                          return true;
-        case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
-                                          return true;
-        default:                          break;
-        }
-      }
-      if (Triple.getArch() != llvm::Triple::x86_64 &&
-          (Attr.getName()->getName() == "force_align_arg_pointer" ||
-           Attr.getName()->getName() == "__force_align_arg_pointer__")) {
-        HandleX86ForceAlignArgPointerAttr(D, Attr, S);
-        return true;
-      }
-      return false;
-    }
-  };
-}
-
-namespace {
-  class MipsAttributesSema : public TargetAttributesSema {
-  public:
-    MipsAttributesSema() { }
-    bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
-                              Sema &S) const {
-      if (Attr.getKind() == AttributeList::AT_Mips16) {
-        D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
-          Attr.getAttributeSpellingListIndex()));
-        return true;
-      } else if (Attr.getKind() == AttributeList::AT_NoMips16) {
-        D->addAttr(::new (S.Context) NoMips16Attr(Attr.getRange(), S.Context,
-                                        Attr.getAttributeSpellingListIndex()));
-        return true;
-      }
-      return false;
-    }
-  };
-}
-
-const TargetAttributesSema &Sema::getTargetAttributesSema() const {
-  if (TheTargetAttributesSema)
-    return *TheTargetAttributesSema;
-
-  const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
-  switch (Triple.getArch()) {
-  case llvm::Triple::arm:
-  case llvm::Triple::thumb:
-    return *(TheTargetAttributesSema = new ARMAttributesSema);
-  case llvm::Triple::msp430:
-    return *(TheTargetAttributesSema = new MSP430AttributesSema);
-  case llvm::Triple::x86:
-  case llvm::Triple::x86_64:
-    return *(TheTargetAttributesSema = new X86AttributesSema);
-  case llvm::Triple::mips:
-  case llvm::Triple::mipsel:
-    return *(TheTargetAttributesSema = new MipsAttributesSema);
-  default:
-    return *(TheTargetAttributesSema = new TargetAttributesSema);
-  }
-}

Removed: cfe/trunk/lib/Sema/TargetAttributesSema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TargetAttributesSema.h?rev=198895&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/TargetAttributesSema.h (original)
+++ cfe/trunk/lib/Sema/TargetAttributesSema.h (removed)
@@ -1,27 +0,0 @@
-//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_SEMA_TARGETSEMA_H
-#define CLANG_SEMA_TARGETSEMA_H
-
-namespace clang {
-  class Scope;
-  class Decl;
-  class AttributeList;
-  class Sema;
-
-  class TargetAttributesSema {
-  public:
-    virtual ~TargetAttributesSema();
-    virtual bool ProcessDeclAttribute(Scope *scope, Decl *D,
-                                      const AttributeList &Attr, Sema &S) const;
-  };
-}
-
-#endif

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=198896&r1=198895&r2=198896&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu Jan  9 16:48:32 2014
@@ -74,7 +74,8 @@ static StringRef NormalizeAttrSpelling(S
 
 typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap;
 
-static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) {
+static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records,
+                                       ParsedAttrMap *Dupes = 0) {
   std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
   std::set<std::string> Seen;
   ParsedAttrMap R;
@@ -89,8 +90,11 @@ static ParsedAttrMap getParsedAttrList(c
 
         // If this attribute has already been handled, it does not need to be
         // handled again.
-        if (Seen.find(AN) != Seen.end())
+        if (Seen.find(AN) != Seen.end()) {
+          if (Dupes)
+            Dupes->push_back(std::make_pair(AN, *I));
           continue;
+        }
         Seen.insert(AN);
       } else
         AN = NormalizeAttrName(Attr.getName()).str();
@@ -2063,15 +2067,111 @@ static std::string GenerateLangOptRequir
   return FnName;
 }
 
+static void GenerateDefaultTargetRequirements(raw_ostream &OS) {
+  OS << "static bool defaultTargetRequirements(llvm::Triple) {\n";
+  OS << "  return true;\n";
+  OS << "}\n\n";
+}
+
+static std::string GenerateTargetRequirements(const Record &Attr,
+                                              const ParsedAttrMap &Dupes,
+                                              raw_ostream &OS) {
+  // If the attribute is not a target specific attribute, return the default
+  // target handler.
+  if (!Attr.isSubClassOf("TargetSpecificAttr"))
+    return "defaultTargetRequirements";
+
+  // Get the list of architectures to be tested for.
+  const Record *R = Attr.getValueAsDef("Target");
+  std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+  if (Arches.empty()) {
+    PrintError(Attr.getLoc(), "Empty list of target architectures for a "
+                              "target-specific attr");
+    return "defaultTargetRequirements";
+  }
+
+  // If there are other attributes which share the same parsed attribute kind,
+  // such as target-specific attributes with a shared spelling, collapse the
+  // duplicate architectures. This is required because a shared target-specific
+  // attribute has only one AttributeList::Kind enumeration value, but it
+  // applies to multiple target architectures. In order for the attribute to be
+  // considered valid, all of its architectures need to be included.
+  if (!Attr.isValueUnset("ParseKind")) {
+    std::string APK = Attr.getValueAsString("ParseKind");
+    for (ParsedAttrMap::const_iterator I = Dupes.begin(), E = Dupes.end();
+         I != E; ++I) {
+      if (I->first == APK) {
+        std::vector<std::string> DA = I->second->getValueAsDef("Target")->
+                                            getValueAsListOfStrings("Arches");
+        std::copy(DA.begin(), DA.end(), std::back_inserter(Arches));
+      }
+    }
+  }
+
+  std::string FnName = "isTarget", Test = "(";
+  for (std::vector<std::string>::const_iterator I = Arches.begin(),
+       E = Arches.end(); I != E; ++I) {
+    std::string Part = *I;
+    Test += "Arch == llvm::Triple::" + Part;
+    if (I + 1 != E)
+      Test += " || ";
+    FnName += Part;
+  }
+  Test += ")";
+
+  // If the target also requires OS testing, generate those tests as well.
+  bool UsesOS = false;
+  if (!R->isValueUnset("OSes")) {
+    UsesOS = true;
+    
+    // We know that there was at least one arch test, so we need to and in the
+    // OS tests.
+    Test += " && (";
+    std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes");
+    for (std::vector<std::string>::const_iterator I = OSes.begin(),
+         E = OSes.end(); I != E; ++I) {
+      std::string Part = *I;
+
+      Test += "OS == llvm::Triple::" + Part;
+      if (I + 1 != E)
+        Test += " || ";
+      FnName += Part;
+    }
+    Test += ")";
+  }
+
+  // If this code has already been generated, simply return the previous
+  // instance of it.
+  static std::set<std::string> CustomTargetSet;
+  std::set<std::string>::iterator I = CustomTargetSet.find(FnName);
+  if (I != CustomTargetSet.end())
+    return *I;
+
+  OS << "static bool " << FnName << "(llvm::Triple T) {\n";
+  OS << "  llvm::Triple::ArchType Arch = T.getArch();\n";
+  if (UsesOS)
+    OS << "  llvm::Triple::OSType OS = T.getOS();\n";
+  OS << "  return " << Test << ";\n";
+  OS << "}\n\n";
+
+  CustomTargetSet.insert(FnName);
+  return FnName;
+}
+
 /// Emits the parsed attribute helpers
 void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
   emitSourceFileHeader("Parsed attribute helpers", OS);
 
-  ParsedAttrMap Attrs = getParsedAttrList(Records);
+  // Get the list of parsed attributes, and accept the optional list of
+  // duplicates due to the ParseKind.
+  ParsedAttrMap Dupes;
+  ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes);
 
-  // Generate the default appertainsTo and language option diagnostic methods.
+  // Generate the default appertainsTo, target and language option diagnostic
+  // methods.
   GenerateDefaultAppertainsTo(OS);
   GenerateDefaultLangOptRequirements(OS);
+  GenerateDefaultTargetRequirements(OS);
 
   // Generate the appertainsTo diagnostic methods and write their names into
   // another mapping. At the same time, generate the AttrInfoMap object
@@ -2080,13 +2180,22 @@ void EmitClangAttrParsedAttrImpl(RecordK
   std::stringstream SS;
   for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E;
        ++I) {
+    // TODO: If the attribute's kind appears in the list of duplicates, that is
+    // because it is a target-specific attribute that appears multiple times.
+    // It would be beneficial to test whether the duplicates are "similar
+    // enough" to each other to not cause problems. For instance, check that
+    // the spellings are identicial, and custom parsing rules match, etc.
+
     // We need to generate struct instances based off ParsedAttrInfo from
     // AttributeList.cpp.
     SS << "  { ";
     emitArgInfo(*I->second, SS);
     SS << ", " << I->second->getValueAsBit("HasCustomParsing");
+    SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
+    SS << ", " << I->second->isSubClassOf("TypeAttr");
     SS << ", " << GenerateAppertainsTo(*I->second, OS);
     SS << ", " << GenerateLangOptRequirements(*I->second, OS);
+    SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
     SS << " }";
 
     if (I + 1 != E)





More information about the cfe-commits mailing list