r190368 - Attribute tablegen now understands that attribute arguments can be optional. This allows for automated checking of the number of arguments expected vs number of arguments given for attributes. Greatly reduces the amount of manual checking required.

Aaron Ballman aaron at aaronballman.com
Mon Sep 9 16:33:17 PDT 2013


Author: aaronballman
Date: Mon Sep  9 18:33:17 2013
New Revision: 190368

URL: http://llvm.org/viewvc/llvm-project?rev=190368&view=rev
Log:
Attribute tablegen now understands that attribute arguments can be optional.  This allows for automated checking of the number of arguments expected vs number of arguments given for attributes.  Greatly reduces the amount of manual checking required.

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/Sema/attr-mode.c
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
    cfe/trunk/utils/TableGen/TableGen.cpp
    cfe/trunk/utils/TableGen/TableGenBackends.h

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Sep  9 18:33:17 2013
@@ -42,39 +42,40 @@ def NonBitField : SubsetSubject<Field, "
                                 [{!S->isBitField()}]>;
 
 // A single argument to an attribute
-class Argument<string name> {
+class Argument<string name, bit optional> {
   string Name = name;
+  bit Optional = optional;
 }
 
-class BoolArgument<string name> : Argument<name>;
-class IdentifierArgument<string name> : Argument<name>;
-class IntArgument<string name> : Argument<name>;
-class StringArgument<string name> : Argument<name>;
-class ExprArgument<string name> : Argument<name>;
-class FunctionArgument<string name> : Argument<name>;
-class TypeArgument<string name> : Argument<name>;
-class UnsignedArgument<string name> : Argument<name>;
-class SourceLocArgument<string name> : Argument<name>;
-class VariadicUnsignedArgument<string name> : Argument<name>;
-class VariadicExprArgument<string name> : Argument<name>;
+class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IdentifierArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IntArgument<string name, bit opt = 0> : Argument<name, opt>;
+class StringArgument<string name, bit opt = 0> : Argument<name, opt>;
+class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
+class FunctionArgument<string name, bit opt = 0> : Argument<name, opt>;
+class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
+class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
+class SourceLocArgument<string name, bit opt = 0> : Argument<name, opt>;
+class VariadicUnsignedArgument<string name> : Argument<name, 1>;
+class VariadicExprArgument<string name> : Argument<name, 1>;
 
 // A version of the form major.minor[.subminor].
-class VersionArgument<string name> : Argument<name>;
+class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
 
 // This one's a doozy, so it gets its own special type
 // It can be an unsigned integer, or a type. Either can
 // be dependent.
-class AlignedArgument<string name> : Argument<name>;
+class AlignedArgument<string name, bit opt = 0> : Argument<name, opt>;
 
 // An integer argument with a default value
-class DefaultIntArgument<string name, int default> : IntArgument<name> {
+class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
   int Default = default;
 }
 
 // This argument is more complex, it includes the enumerator type name,
 // a list of strings to accept, and a list of enumerators to map them to.
 class EnumArgument<string name, string type, list<string> values,
-                         list<string> enums> : Argument<name> {
+                   list<string> enums, bit opt = 0> : Argument<name, opt> {
   string Type = type;
   list<string> Values = values;
   list<string> Enums = enums;
@@ -122,6 +123,10 @@ class Attr {
   bit Ignored = 0;
   // Set to true if each of the spellings is a distinct attribute.
   bit DistinctSpellings = 0;
+  // Set to true if the attribute's parsing does not match its semantic
+  // content. Eg) It parses 3 args, but semantically takes 4 args.  Opts out of
+  // common attribute error checking.
+  bit HasCustomParsing = 0;
   // Any additional text that should be included verbatim in the class.
   code AdditionalMembers = [{}];
 }
@@ -168,7 +173,7 @@ def Aligned : InheritableAttr {
   let Spellings = [GNU<"aligned">, Declspec<"align">, CXX11<"gnu", "aligned">,
                    Keyword<"alignas">, Keyword<"_Alignas">];
   let Subjects = [NonBitField, NormalVar, Tag];
-  let Args = [AlignedArgument<"Alignment">];
+  let Args = [AlignedArgument<"Alignment", 1>];
   let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
                    Accessor<"isC11", [Keyword<"_Alignas">]>,
                    Accessor<"isAlignas", [Keyword<"alignas">,
@@ -223,6 +228,7 @@ def Availability : InheritableAttr {
              .Case("macosx", "OS X")
              .Default(llvm::StringRef());
 } }];
+  let HasCustomParsing = 1;
 }
 
 def Blocks : InheritableAttr {
@@ -296,7 +302,7 @@ def Const : InheritableAttr {
 
 def Constructor : InheritableAttr {
   let Spellings = [GNU<"constructor">, CXX11<"gnu", "constructor">];
-  let Args = [IntArgument<"Priority">];
+  let Args = [IntArgument<"Priority", 1>];
 }
 
 def CUDAConstant : InheritableAttr {
@@ -346,12 +352,12 @@ def OpenCLImageAccess : Attr {
 
 def Deprecated : InheritableAttr {
   let Spellings = [GNU<"deprecated">, CXX11<"gnu", "deprecated">];
-  let Args = [StringArgument<"Message">];
+  let Args = [StringArgument<"Message", 1>];
 }
 
 def Destructor : InheritableAttr {
   let Spellings = [GNU<"destructor">, CXX11<"gnu", "destructor">];
-  let Args = [IntArgument<"Priority">];
+  let Args = [IntArgument<"Priority", 1>];
 }
 
 def ExtVectorType : Attr {
@@ -409,7 +415,7 @@ def IBOutlet : InheritableAttr {
 
 def IBOutletCollection : InheritableAttr {
   let Spellings = [GNU<"iboutletcollection">];
-  let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
+  let Args = [TypeArgument<"Interface", 1>, SourceLocArgument<"InterfaceLoc">];
 }
 
 def Malloc : InheritableAttr {
@@ -513,7 +519,7 @@ def NoThrow : InheritableAttr {
 def NSBridged : InheritableAttr {
   let Spellings = [GNU<"ns_bridged">];
   let Subjects = [Record];
-  let Args = [IdentifierArgument<"BridgedType">];
+  let Args = [IdentifierArgument<"BridgedType", 1>];
 }
 
 def NSReturnsRetained : InheritableAttr {
@@ -678,7 +684,7 @@ def TransparentUnion : InheritableAttr {
 
 def Unavailable : InheritableAttr {
   let Spellings = [GNU<"unavailable">];
-  let Args = [StringArgument<"Message">];
+  let Args = [StringArgument<"Message", 1>];
 }
 
 def ArcWeakrefUnavailable : InheritableAttr {
@@ -724,6 +730,7 @@ def VectorSize : TypeAttr {
 def VecTypeHint : InheritableAttr {
   let Spellings = [GNU<"vec_type_hint">];
   let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
+  let HasCustomParsing = 1;
 }
 
 def Visibility : InheritableAttr {
@@ -768,6 +775,8 @@ def WeakImport : InheritableAttr {
 
 def WeakRef : InheritableAttr {
   let Spellings = [GNU<"weakref">, CXX11<"gnu", "weakref">];
+  // A WeakRef that has an argument is treated as being an AliasAttr
+  let Args = [StringArgument<"Aliasee", 1>];
 }
 
 def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr {
@@ -969,6 +978,7 @@ def ArgumentWithTypeTag : InheritableAtt
               UnsignedArgument<"TypeTagIdx">,
               BoolArgument<"IsPointer">];
   let Subjects = [Function];
+  let HasCustomParsing = 1;
 }
 
 def TypeTagForDatatype : InheritableAttr {
@@ -978,6 +988,7 @@ def TypeTagForDatatype : InheritableAttr
               BoolArgument<"LayoutCompatible">,
               BoolArgument<"MustBeNull">];
   let Subjects = [Var];
+  let HasCustomParsing = 1;
 }
 
 // Microsoft-related attributes

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Mon Sep  9 18:33:17 2013
@@ -463,6 +463,10 @@ public:
   /// defined in Attr.td. This index is used by an attribute
   /// to pretty print itself.
   unsigned getAttributeSpellingListIndex() const;
+
+  bool hasCustomParsing() const;
+  unsigned getMinArgs() const;
+  unsigned getMaxArgs() const;
 };
 
 /// A factory, from which one makes pools, from which one creates

Modified: cfe/trunk/include/clang/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CMakeLists.txt?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/Sema/CMakeLists.txt Mon Sep  9 18:33:17 2013
@@ -17,3 +17,8 @@ clang_tablegen(AttrSpellingListIndex.inc
   -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
   SOURCE ../Basic/Attr.td
   TARGET ClangAttrSpellingListIndex)
+
+clang_tablegen(AttrParsedAttrImpl.inc -gen-clang-attr-parsed-attr-impl
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE ../Basic/Attr.td
+  TARGET ClangAttrParsedAttrImpl)

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Mon Sep  9 18:33:17 2013
@@ -145,3 +145,28 @@ unsigned AttributeList::getAttributeSpel
 
 }
 
+struct ParsedAttrInfo {
+  unsigned NumArgs : 4;
+  unsigned OptArgs : 4;
+  unsigned HasCustomParsing : 1;
+};
+
+namespace {
+  #include "clang/Sema/AttrParsedAttrImpl.inc"
+}
+
+const ParsedAttrInfo& getInfo(const AttributeList& A) {
+  return AttrInfoMap[A.getKind()];
+}
+
+unsigned AttributeList::getMinArgs() const {
+  return getInfo(*this).NumArgs;
+}
+
+unsigned AttributeList::getMaxArgs() const {
+  return getMinArgs() + getInfo(*this).OptArgs;
+}
+
+bool AttributeList::hasCustomParsing() const {
+  return getInfo(*this).HasCustomParsing;
+}

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Mon Sep  9 18:33:17 2013
@@ -60,6 +60,7 @@ add_dependencies(clangSema
   ClangAttrList
   ClangAttrParsedAttrList
   ClangAttrParsedAttrKinds
+  ClangAttrParsedAttrImpl
   ClangAttrSpellingListIndex
   ClangAttrTemplateInstantiate
   ClangCommentNodes

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Sep  9 18:33:17 2013
@@ -497,9 +497,6 @@ enum ThreadAttributeDeclKind {
 
 static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
                                       const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return false;
-
   // D must be either a member field or global (potentially shared) variable.
   if (!mayBeSharedVariable(D)) {
     S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -535,9 +532,6 @@ static void handlePtGuardedVarAttr(Sema
 static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
                                      const AttributeList &Attr,
                                      Expr* &Arg) {
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return false;
-
   // D must be either a member field or global (potentially shared) variable.
   if (!mayBeSharedVariable(D)) {
     S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -580,9 +574,6 @@ static void handlePtGuardedByAttr(Sema &
 
 static bool checkLockableAttrCommon(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return false;
-
   // FIXME: Lockable structs for C code.
   if (!isa<RecordDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -612,9 +603,6 @@ static void handleScopedLockableAttr(Sem
 
 static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
                                          const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
       << Attr.getName() << ThreadExpectedFunctionOrMethod;
@@ -627,9 +615,6 @@ static void handleNoThreadSafetyAnalysis
 
 static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
                                       const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
@@ -643,9 +628,6 @@ static void handleNoSanitizeAddressAttr(
 
 static void handleNoSanitizeMemory(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
@@ -658,9 +640,6 @@ static void handleNoSanitizeMemory(Sema
 
 static void handleNoSanitizeThread(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
@@ -922,9 +901,6 @@ static void handleUnlockFunAttr(Sema &S,
 
 static void handleLockReturnedAttr(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
       << Attr.getName() << ThreadExpectedFunctionOrMethod;
@@ -968,9 +944,6 @@ static void handleLocksExcludedAttr(Sema
 }
 
 static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   ConsumableAttr::ConsumedState DefaultState;
 
   if (Attr.isArgIdent(0)) {
@@ -1022,8 +995,6 @@ static bool checkForConsumableClass(Sema
 }
 
 static void handleConsumesAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
   if (!isa<CXXMethodDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
       Attr.getName() << ExpectedMethod;
@@ -1040,8 +1011,6 @@ static void handleConsumesAttr(Sema &S,
 
 static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D,
                                              const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
   if (!isa<CXXMethodDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
       Attr.getName() << ExpectedMethod;
@@ -1058,8 +1027,6 @@ static void handleCallableWhenUnconsumed
 
 static void handleTestsConsumedAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
   if (!isa<CXXMethodDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
       Attr.getName() << ExpectedMethod;
@@ -1076,8 +1043,6 @@ static void handleTestsConsumedAttr(Sema
 
 static void handleTestsUnconsumedAttr(Sema &S, Decl *D,
                                       const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
   if (!isa<CXXMethodDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
       Attr.getName() << ExpectedMethod;
@@ -1094,8 +1059,6 @@ static void handleTestsUnconsumedAttr(Se
 
 static void handleReturnTypestateAttr(Sema &S, Decl *D,
                                       const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 1)) return;
-  
   ReturnTypestateAttr::ConsumedState ReturnState;
   
   if (Attr.isArgIdent(0)) {
@@ -1165,10 +1128,6 @@ static void handleExtVectorTypeAttr(Sema
 }
 
 static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (TagDecl *TD = dyn_cast<TagDecl>(D))
     TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
   else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
@@ -1197,10 +1156,6 @@ static void handleMsStructAttr(Sema &S,
 }
 
 static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   // The IBAction attributes only apply to instance methods.
   if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
     if (MD->isInstanceMethod()) {
@@ -1240,10 +1195,6 @@ static bool checkIBOutletCommon(Sema &S,
 }
 
 static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-  
   if (!checkIBOutletCommon(S, D, Attr))
     return;
 
@@ -1620,10 +1571,6 @@ static void handleWeakRefAttr(Sema &S, D
 }
 
 static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   StringLiteral *Str = 0;
   if (Attr.isArgExpr(0))
     Str = dyn_cast<StringLiteral>(Attr.getArgAsExpr(0)->IgnoreParenCasts());
@@ -1647,10 +1594,6 @@ static void handleAliasAttr(Sema &S, Dec
 }
 
 static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
@@ -1663,10 +1606,6 @@ static void handleMinSizeAttr(Sema &S, D
 }
 
 static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -1684,10 +1623,6 @@ static void handleColdAttr(Sema &S, Decl
 }
 
 static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -1705,10 +1640,6 @@ static void handleHotAttr(Sema &S, Decl
 }
 
 static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -1722,10 +1653,6 @@ static void handleNakedAttr(Sema &S, Dec
 
 static void handleAlwaysInlineAttr(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -1739,10 +1666,6 @@ static void handleAlwaysInlineAttr(Sema
 
 static void handleTLSModelAttr(Sema &S, Decl *D,
                                const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   Expr *Arg = Attr.getArgAsExpr(0);
   Arg = Arg->IgnoreParenCasts();
   StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
@@ -1774,10 +1697,6 @@ static void handleTLSModelAttr(Sema &S,
 }
 
 static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     QualType RetTy = FD->getResultType();
     if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
@@ -1792,10 +1711,6 @@ static void handleMallocAttr(Sema &S, De
 }
 
 static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   D->addAttr(::new (S.Context)
              MayAliasAttr(Attr.getRange(), S.Context,
                           Attr.getAttributeSpellingListIndex()));
@@ -1856,10 +1771,6 @@ static void handleAnalyzerNoReturnAttr(S
   
   // The checking path for 'noreturn' and 'analyzer_noreturn' are different
   // because 'analyzer_noreturn' does not impact the type.
-  
-  if(!checkAttributeNumArgs(S, Attr, 0))
-      return;
-  
   if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
     ValueDecl *VD = dyn_cast<ValueDecl>(D);
     if (VD == 0 || (!VD->getType()->isBlockPointerType()
@@ -1979,10 +1890,6 @@ static void handleDependencyAttr(Sema &S
 }
 
 static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
       !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1997,10 +1904,6 @@ static void handleUnusedAttr(Sema &S, De
 
 static void handleReturnsTwiceAttr(Sema &S, Decl *D,
                                    const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -2013,10 +1916,6 @@ static void handleReturnsTwiceAttr(Sema
 }
 
 static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
     if (VD->hasLocalStorage()) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
@@ -2125,9 +2024,6 @@ static void handleAttrWithMessage(Sema &
 
 static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, 
                                             const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-  
   D->addAttr(::new (S.Context)
              ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
                                        Attr.getAttributeSpellingListIndex()));
@@ -2141,9 +2037,6 @@ static void handleObjCRootClassAttr(Sema
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-  
   D->addAttr(::new (S.Context)
              ObjCRootClassAttr(Attr.getRange(), S.Context,
                                Attr.getAttributeSpellingListIndex()));
@@ -2156,9 +2049,6 @@ static void handleObjCRequiresPropertyDe
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-  
   D->addAttr(::new (S.Context)
              ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
                                           Attr.getAttributeSpellingListIndex()));
@@ -2434,10 +2324,6 @@ static void handleVisibilityAttr(Sema &S
     return;
   }
 
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   // Check that the argument is a string literal.
   StringLiteral *Str = 0;
   if (Attr.isArgExpr(0))
@@ -2500,9 +2386,6 @@ static void handleObjCMethodFamilyAttr(S
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   IdentifierLoc *IL = Attr.getArgAsIdent(0);
 
   StringRef param = IL->Ident->getName();
@@ -2540,9 +2423,6 @@ static void handleObjCMethodFamilyAttr(S
 
 static void handleObjCExceptionAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
   if (OCI == 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
@@ -2556,8 +2436,6 @@ static void handleObjCExceptionAttr(Sema
 }
 
 static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
   if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
     QualType T = TD->getUnderlyingType();
     if (!T->isCARCBridgableType()) {
@@ -2588,9 +2466,6 @@ static void handleObjCNSObject(Sema &S,
 
 static void
 handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
     return;
@@ -2607,9 +2482,6 @@ static void handleBlocksAttr(Sema &S, De
       << Attr.getName() << 1 << AANT_ArgumentIdentifier;
     return;
   }
-  
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
 
   IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
   BlocksAttr::BlockType type;
@@ -2723,10 +2595,6 @@ static void handleSentinelAttr(Sema &S,
 }
 
 static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
     RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context));
   else
@@ -2734,10 +2602,6 @@ static void handleWarnUnusedAttr(Sema &S
 }
 
 static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionMethodOrClass;
@@ -2762,10 +2626,6 @@ static void handleWarnUnusedResult(Sema
 }
 
 static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
     if (isa<CXXRecordDecl>(D)) {
       D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
@@ -2784,11 +2644,6 @@ static void handleWeakAttr(Sema &S, Decl
 }
 
 static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
-
   // weak_import only applies to variable & function declarations.
   bool isDef = false;
   if (!D->canBeWeakImported(isDef)) {
@@ -2814,12 +2669,6 @@ static void handleWeakImportAttr(Sema &S
 // Handles reqd_work_group_size and work_group_size_hint.
 static void handleWorkGroupSize(Sema &S, Decl *D,
                                 const AttributeList &Attr) {
-  assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize 
-      || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
-
-  // Attribute has 3 arguments.
-  if (!checkAttributeNumArgs(S, Attr, 3)) return;
-
   unsigned WGSize[3];
   for (unsigned i = 0; i < 3; ++i) {
     Expr *E = Attr.getArgAsExpr(i);
@@ -2918,10 +2767,6 @@ SectionAttr *Sema::mergeSectionAttr(Decl
 }
 
 static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // Attribute has no arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   // Make sure that there is a string literal as the sections's single
   // argument.
   Expr *ArgExpr = Attr.getArgAsExpr(0);
@@ -2955,9 +2800,6 @@ static void handleSectionAttr(Sema &S, D
 
 
 static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-  
   if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
     if (Existing->getLocation().isInvalid())
       Existing->setRange(Attr.getRange());
@@ -2969,9 +2811,6 @@ static void handleNothrowAttr(Sema &S, D
 }
 
 static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
    if (Existing->getLocation().isInvalid())
      Existing->setRange(Attr.getRange());
@@ -2983,10 +2822,6 @@ static void handleConstAttr(Sema &S, Dec
 }
 
 static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   D->addAttr(::new (S.Context)
              PureAttr(Attr.getRange(), S.Context,
                       Attr.getAttributeSpellingListIndex()));
@@ -2999,9 +2834,6 @@ static void handleCleanupAttr(Sema &S, D
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   VarDecl *VD = dyn_cast<VarDecl>(D);
 
   if (!VD || !VD->hasLocalStorage()) {
@@ -3054,9 +2886,6 @@ static void handleCleanupAttr(Sema &S, D
 /// Handle __attribute__((format_arg((idx)))) attribute based on
 /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
 static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -3156,10 +2985,6 @@ static void handleInitPriorityAttr(Sema
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 1)) {
-    Attr.setInvalid();
-    return;
-  }
   Expr *priorityExpr = Attr.getArgAsExpr(0);
   
   llvm::APSInt priority(32);
@@ -3216,9 +3041,6 @@ static void handleFormatAttr(Sema &S, De
       << Attr.getName() << 1 << AANT_ArgumentIdentifier;
     return;
   }
-  
-  if (!checkAttributeNumArgs(S, Attr, 3))
-    return;
 
   if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -3356,11 +3178,6 @@ static void handleFormatAttr(Sema &S, De
 
 static void handleTransparentUnionAttr(Sema &S, Decl *D,
                                        const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
-
   // Try to find the underlying union declaration.
   RecordDecl *RD = 0;
   TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
@@ -3424,10 +3241,6 @@ static void handleTransparentUnionAttr(S
 }
 
 static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   Expr *ArgExpr = Attr.getArgAsExpr(0);
   StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
 
@@ -3629,9 +3442,6 @@ static void handleModeAttr(Sema &S, Decl
     return;
   }
   
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
   StringRef Str = Name->getName();
 
@@ -3794,10 +3604,6 @@ static void handleModeAttr(Sema &S, Decl
 }
 
 static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
     if (!VD->hasGlobalStorage())
       S.Diag(Attr.getLoc(),
@@ -3816,11 +3622,6 @@ static void handleNoDebugAttr(Sema &S, D
 }
 
 static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -3834,11 +3635,6 @@ static void handleNoInlineAttr(Sema &S,
 
 static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
                                            const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
-
   if (!isa<FunctionDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunction;
@@ -3852,9 +3648,6 @@ static void handleNoInstrumentFunctionAt
 
 static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (S.LangOpts.CUDA) {
-    if (!checkAttributeNumArgs(S, Attr, 0))
-      return;
-
     if (!isa<VarDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
         << Attr.getName() << ExpectedVariable;
@@ -3894,10 +3687,6 @@ static void handleDeviceAttr(Sema &S, De
 
 static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (S.LangOpts.CUDA) {
-    // check the attribute arguments.
-    if (!checkAttributeNumArgs(S, Attr, 0))
-      return;
-
     if (!isa<FunctionDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
         << Attr.getName() << ExpectedFunction;
@@ -3929,11 +3718,6 @@ static void handleGlobalAttr(Sema &S, De
 
 static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (S.LangOpts.CUDA) {
-    // check the attribute arguments.
-    if (!checkAttributeNumArgs(S, Attr, 0))
-      return;
-
-
     if (!isa<FunctionDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
         << Attr.getName() << ExpectedFunction;
@@ -3950,10 +3734,6 @@ static void handleHostAttr(Sema &S, Decl
 
 static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (S.LangOpts.CUDA) {
-    // check the attribute arguments.
-    if (!checkAttributeNumArgs(S, Attr, 0))
-      return;
-
     if (!isa<VarDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
         << Attr.getName() << ExpectedVariable;
@@ -3969,10 +3749,6 @@ static void handleSharedAttr(Sema &S, De
 }
 
 static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 0))
-    return;
-
   FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
   if (Fn == 0) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -4680,10 +4456,6 @@ static void handleUuidAttr(Sema &S, Decl
   if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland))
     return;
 
-  // check the attribute arguments.
-  if (!checkAttributeNumArgs(S, Attr, 1))
-    return;
-
   Expr *Arg = Attr.getArgAsExpr(0);
   StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
   if (!Str || !Str->isAscii()) {
@@ -4771,6 +4543,29 @@ static void handleSelectAnyAttr(Sema &S,
                            Attr.getAttributeSpellingListIndex()));
 }
 
+/// 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.
+static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
+                                          const AttributeList &Attr) {
+  // Several attributes carry different semantics than the parsing requires, so
+  // those are opted out of the common handling.
+  //
+  // 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)
+    return false;
+
+  // If there are no optional arguments, then checking for the argument count
+  // is trivial.
+  if (Attr.getMinArgs() == Attr.getMaxArgs() &&
+      !checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
+    return true;
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Top Level Sema Entry Points
 //===----------------------------------------------------------------------===//
@@ -4789,6 +4584,9 @@ static void ProcessDeclAttribute(Sema &S
   if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
     return;
 
+  if (handleCommonAttributeFeatures(S, scope, D, Attr))
+    return;
+
   switch (Attr.getKind()) {
   case AttributeList::AT_IBAction:    handleIBAction(S, D, Attr); break;
   case AttributeList::AT_IBOutlet:    handleIBOutlet(S, D, Attr); break;

Modified: cfe/trunk/test/Sema/attr-mode.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-mode.c?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-mode.c (original)
+++ cfe/trunk/test/Sema/attr-mode.c Mon Sep  9 18:33:17 2013
@@ -13,11 +13,12 @@ int i16_2_test[sizeof(i16_1) == 2 ? 1 :
 typedef float f64 __attribute((mode(DF)));
 int f64_test[sizeof(f64) == 8 ? 1 : -1];
 
-typedef int invalid_1 __attribute((mode)); // expected-error{{'mode' attribute requires an identifier}}
-typedef int invalid_2 __attribute((mode())); // expected-error{{'mode' attribute requires an identifier}}
+typedef int invalid_1 __attribute((mode)); // expected-error{{'mode' attribute takes one argument}}
+typedef int invalid_2 __attribute((mode())); // expected-error{{'mode' attribute takes one argument}}
 typedef int invalid_3 __attribute((mode(II))); // expected-error{{unknown machine mode}}
 typedef struct {int i,j,k;} invalid_4 __attribute((mode(SI))); // expected-error{{mode attribute only supported for integer and floating-point types}}
 typedef float invalid_5 __attribute((mode(SI))); // expected-error{{type of machine mode does not match type of base type}}
+typedef int invalid_6 __attribute__((mode(12)));  // expected-error{{'mode' attribute requires an identifier}}
 
 typedef unsigned unwind_word __attribute((mode(unwind_word)));
 

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Mon Sep  9 18:33:17 2013
@@ -13,6 +13,7 @@
 
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringMatcher.h"
 #include "llvm/TableGen/TableGenBackend.h"
@@ -95,11 +96,12 @@ namespace {
   class Argument {
     std::string lowerName, upperName;
     StringRef attrName;
+    bool isOpt;
 
   public:
     Argument(Record &Arg, StringRef Attr)
       : lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
-        attrName(Attr) {
+        attrName(Attr), isOpt(false) {
       if (!lowerName.empty()) {
         lowerName[0] = std::tolower(lowerName[0]);
         upperName[0] = std::toupper(upperName[0]);
@@ -111,6 +113,9 @@ namespace {
     StringRef getUpperName() const { return upperName; }
     StringRef getAttrName() const { return attrName; }
 
+    bool isOptional() const { return isOpt; }
+    void setOptional(bool set) { isOpt = set; }
+
     // These functions print the argument contents formatted in different ways.
     virtual void writeAccessors(raw_ostream &OS) const = 0;
     virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
@@ -119,6 +124,7 @@ namespace {
     virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
     virtual void writeCtorBody(raw_ostream &OS) const {}
     virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
+    virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0;
     virtual void writeCtorParameters(raw_ostream &OS) const = 0;
     virtual void writeDeclarations(raw_ostream &OS) const = 0;
     virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
@@ -154,6 +160,9 @@ namespace {
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << getLowerName() << "(" << getUpperName() << ")";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << getLowerName() << "()";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << type << " " << getUpperName();
     }
@@ -246,6 +255,9 @@ namespace {
          << getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
          << "Length])";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << getLowerName() << "Length(0)," << getLowerName() << "(0)";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << "llvm::StringRef " << getUpperName();
     }
@@ -347,6 +359,9 @@ namespace {
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << "is" << getLowerName() << "Expr(false)";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
     }
@@ -440,6 +455,9 @@ namespace {
          << getLowerName() << "(new (Ctx, 16) " << getType() << "["
          << getLowerName() << "Size])";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << getLowerName() << "Size(0), " << getLowerName() << "(0)";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << getType() << " *" << getUpperName() << ", unsigned "
          << getUpperName() << "Size";
@@ -520,6 +538,9 @@ namespace {
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << getLowerName() << "(" << getUpperName() << ")";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << getLowerName() << "(" << type << "(0))";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << type << " " << getUpperName();
     }
@@ -590,6 +611,9 @@ namespace {
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << getLowerName() << "(" << getUpperName() << ")";
     }
+    void writeCtorDefaultInitializers(raw_ostream &OS) const {
+      OS << getLowerName() << "()";
+    }
     void writeCtorParameters(raw_ostream &OS) const {
       OS << "VersionTuple " << getUpperName();
     }
@@ -738,6 +762,10 @@ static Argument *createArgument(Record &
         break;
     }
   }
+
+  if (Ptr && Arg.getValueAsBit("Optional"))
+    Ptr->setOptional(true);
+
   return Ptr;
 }
 
@@ -926,10 +954,13 @@ void EmitClangAttrClass(RecordKeeper &Re
     OS << "\n public:\n";
     OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
     
+    bool HasOpt = false;
     for (ai = Args.begin(); ai != ae; ++ai) {
       OS << "              , ";
       (*ai)->writeCtorParameters(OS);
       OS << "\n";
+      if ((*ai)->isOptional())
+        HasOpt = true;
     }
 
     OS << "              , ";
@@ -952,6 +983,41 @@ void EmitClangAttrClass(RecordKeeper &Re
     }
     OS << "  }\n\n";
 
+    // If there are optional arguments, write out a constructor that elides the
+    // optional arguments as well.
+    if (HasOpt) {
+      OS << "  " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+      for (ai = Args.begin(); ai != ae; ++ai) {
+        if (!(*ai)->isOptional()) {
+          OS << "              , ";
+          (*ai)->writeCtorParameters(OS);
+          OS << "\n";
+        }
+      }
+
+      OS << "              , ";
+      OS << "unsigned SI = 0\n";
+
+      OS << "             )\n";
+      OS << "    : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
+
+      for (ai = Args.begin(); ai != ae; ++ai) {
+        OS << "              , ";
+        (*ai)->writeCtorDefaultInitializers(OS);
+        OS << "\n";
+      }
+
+      OS << "  {\n";
+  
+      for (ai = Args.begin(); ai != ae; ++ai) {
+        if (!(*ai)->isOptional()) {
+          (*ai)->writeCtorBody(OS);
+          OS << "\n";
+        }
+      }
+      OS << "  }\n\n";
+    }
+
     OS << "  virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
     OS << "  virtual void printPretty(raw_ostream &OS,\n"
        << "                           const PrintingPolicy &Policy) const;\n";
@@ -1402,16 +1468,11 @@ void EmitClangAttrTemplateInstantiate(Re
      << "} // end namespace clang\n";
 }
 
-// Emits the list of parsed attributes.
-void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
-  emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap;
 
-  OS << "#ifndef PARSED_ATTR\n";
-  OS << "#define PARSED_ATTR(NAME) NAME\n";
-  OS << "#endif\n\n";
-  
+static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) {
   std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
+  ParsedAttrMap R;
   for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
        I != E; ++I) {
     Record &Attr = **I;
@@ -1428,16 +1489,69 @@ void EmitClangAttrParsedAttrList(RecordK
           std::string AttrName = (*I)->getValueAsString("Name");
 
           StringRef Spelling = NormalizeAttrName(AttrName);
-
-          OS << "PARSED_ATTR(" << Spelling << ")\n";
+          R.push_back(std::make_pair(Spelling.str(), &Attr));
         }
       } else {
         StringRef AttrName = Attr.getName();
         AttrName = NormalizeAttrName(AttrName);
-        OS << "PARSED_ATTR(" << AttrName << ")\n";
+        R.push_back(std::make_pair(AttrName.str(), *I));
       }
     }
   }
+  return R;
+}
+
+// Emits the list of parsed attributes.
+void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
+  emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+
+  OS << "#ifndef PARSED_ATTR\n";
+  OS << "#define PARSED_ATTR(NAME) NAME\n";
+  OS << "#endif\n\n";
+  
+  ParsedAttrMap Names = getParsedAttrList(Records);
+  for (ParsedAttrMap::iterator I = Names.begin(), E = Names.end(); I != E;
+       ++I) {
+    OS << "PARSED_ATTR(" << I->first << ")\n";
+  }
+}
+
+static void emitArgInfo(const Record &R, raw_ostream &OS) {
+  // This function will count the number of arguments specified for the
+  // attribute and emit the number of required arguments followed by the
+  // number of optional arguments.
+  std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
+  unsigned ArgCount = 0, OptCount = 0;
+  for (std::vector<Record *>::const_iterator I = Args.begin(), E = Args.end();
+       I != E; ++I) {
+    const Record &Arg = **I;
+    Arg.getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
+  }
+  OS << ArgCount << ", " << OptCount;
+}
+
+/// Emits the parsed attribute helpers
+void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+  emitSourceFileHeader("Parsed attribute helpers", OS);
+
+  ParsedAttrMap Attrs = getParsedAttrList(Records);
+
+  OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
+  for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E;
+       ++I) {
+    // We need to generate struct instances based off ParsedAttrInfo from
+    // AttributeList.cpp.
+    OS << "  { ";
+    emitArgInfo(*I->second, OS);
+    OS << ", " << I->second->getValueAsBit("HasCustomParsing");
+    OS << " }";
+
+    if (I + 1 != E)
+      OS << ",";
+    
+    OS << "  // AT_" << I->first << "\n";
+  }
+  OS << "};\n\n";
 }
 
 // Emits the kind list of parsed attributes

Modified: cfe/trunk/utils/TableGen/TableGen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGen.cpp?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGen.cpp (original)
+++ cfe/trunk/utils/TableGen/TableGen.cpp Mon Sep  9 18:33:17 2013
@@ -34,6 +34,7 @@ enum ActionType {
   GenClangAttrLateParsedList,
   GenClangAttrTemplateInstantiate,
   GenClangAttrParsedAttrList,
+  GenClangAttrParsedAttrImpl,
   GenClangAttrParsedAttrKinds,
   GenClangAttrDump,
   GenClangDiagsDefs,
@@ -81,12 +82,15 @@ cl::opt<ActionType> Action(
         clEnumValN(GenClangAttrTemplateInstantiate,
                    "gen-clang-attr-template-instantiate",
                    "Generate a clang template instantiate code"),
-        clEnumValN(GenClangAttrParsedAttrList,
-                   "gen-clang-attr-parsed-attr-list",
-                   "Generate a clang parsed attribute list"),
-        clEnumValN(GenClangAttrParsedAttrKinds,
-                   "gen-clang-attr-parsed-attr-kinds",
-                   "Generate a clang parsed attribute kinds"),
+                    clEnumValN(GenClangAttrParsedAttrList,
+                               "gen-clang-attr-parsed-attr-list",
+                               "Generate a clang parsed attribute list"),
+                    clEnumValN(GenClangAttrParsedAttrImpl,
+                               "gen-clang-attr-parsed-attr-impl",
+                               "Generate the clang parsed attribute helpers"),
+                    clEnumValN(GenClangAttrParsedAttrKinds,
+                               "gen-clang-attr-parsed-attr-kinds",
+                               "Generate a clang parsed attribute kinds"),
         clEnumValN(GenClangAttrDump, "gen-clang-attr-dump",
                    "Generate clang attribute dumper"),
         clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
@@ -167,6 +171,9 @@ bool ClangTableGenMain(raw_ostream &OS,
   case GenClangAttrParsedAttrList:
     EmitClangAttrParsedAttrList(Records, OS);
     break;
+  case GenClangAttrParsedAttrImpl:
+    EmitClangAttrParsedAttrImpl(Records, OS);
+    break;
   case GenClangAttrParsedAttrKinds:
     EmitClangAttrParsedAttrKinds(Records, OS);
     break;

Modified: cfe/trunk/utils/TableGen/TableGenBackends.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGenBackends.h?rev=190368&r1=190367&r2=190368&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGenBackends.h (original)
+++ cfe/trunk/utils/TableGen/TableGenBackends.h Mon Sep  9 18:33:17 2013
@@ -40,6 +40,7 @@ void EmitClangAttrSpellingListIndex(Reco
 void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS);
 void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS);
 





More information about the cfe-commits mailing list