From: Aaron Ballman Date: Mon, 9 Sep 2013 23:33:17 +0000 (+0000) Subject: Attribute tablegen now understands that attribute arguments can be optional. This... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bbb3b3237df2284f6f3c34798944fcfa4b43fd34;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190368 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index f6ebaea2bb..19d6848943 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -42,39 +42,40 @@ def NonBitField : SubsetSubjectisBitField()}]>; // A single argument to an attribute -class Argument { +class Argument { string Name = name; + bit Optional = optional; } -class BoolArgument : Argument; -class IdentifierArgument : Argument; -class IntArgument : Argument; -class StringArgument : Argument; -class ExprArgument : Argument; -class FunctionArgument : Argument; -class TypeArgument : Argument; -class UnsignedArgument : Argument; -class SourceLocArgument : Argument; -class VariadicUnsignedArgument : Argument; -class VariadicExprArgument : Argument; +class BoolArgument : Argument; +class IdentifierArgument : Argument; +class IntArgument : Argument; +class StringArgument : Argument; +class ExprArgument : Argument; +class FunctionArgument : Argument; +class TypeArgument : Argument; +class UnsignedArgument : Argument; +class SourceLocArgument : Argument; +class VariadicUnsignedArgument : Argument; +class VariadicExprArgument : Argument; // A version of the form major.minor[.subminor]. -class VersionArgument : Argument; +class VersionArgument : Argument; // 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 : Argument; +class AlignedArgument : Argument; // An integer argument with a default value -class DefaultIntArgument : IntArgument { +class DefaultIntArgument : IntArgument { 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 values, - list enums> : Argument { + list enums, bit opt = 0> : Argument { string Type = type; list Values = values; list 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 : InheritableAttr { 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 diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 1ff3fe6c51..583f61933b 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -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 diff --git a/include/clang/Sema/CMakeLists.txt b/include/clang/Sema/CMakeLists.txt index 6b5d222b5d..5a48b901d2 100644 --- a/include/clang/Sema/CMakeLists.txt +++ b/include/clang/Sema/CMakeLists.txt @@ -17,3 +17,8 @@ clang_tablegen(AttrSpellingListIndex.inc -gen-clang-attr-spelling-index -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) diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 451b01c2ec..8755a501c9 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -145,3 +145,28 @@ unsigned AttributeList::getAttributeSpellingListIndex() const { } +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; +} diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 836d125978..5e0914086c 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -60,6 +60,7 @@ add_dependencies(clangSema ClangAttrList ClangAttrParsedAttrList ClangAttrParsedAttrKinds + ClangAttrParsedAttrImpl ClangAttrSpellingListIndex ClangAttrTemplateInstantiate ClangCommentNodes diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 0a6cee900b..0a35127980 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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 &S, Decl *D, 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 &S, Decl *D, 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(D)) { S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) @@ -612,9 +603,6 @@ static void handleScopedLockableAttr(Sema &S, Decl *D, static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) << Attr.getName() << ThreadExpectedFunctionOrMethod; @@ -627,9 +615,6 @@ static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D, static void handleNoSanitizeAddressAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; @@ -643,9 +628,6 @@ static void handleNoSanitizeAddressAttr(Sema &S, Decl *D, static void handleNoSanitizeMemory(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; @@ -658,9 +640,6 @@ static void handleNoSanitizeMemory(Sema &S, Decl *D, static void handleNoSanitizeThread(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; @@ -922,9 +901,6 @@ static void handleUnlockFunAttr(Sema &S, Decl *D, static void handleLockReturnedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) << Attr.getName() << ThreadExpectedFunctionOrMethod; @@ -968,9 +944,6 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, } 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 &S, const CXXMethodDecl *MD, } static void handleConsumesAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedMethod; @@ -1040,8 +1011,6 @@ static void handleConsumesAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedMethod; @@ -1058,8 +1027,6 @@ static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D, static void handleTestsConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedMethod; @@ -1076,8 +1043,6 @@ static void handleTestsConsumedAttr(Sema &S, Decl *D, static void handleTestsUnconsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedMethod; @@ -1094,8 +1059,6 @@ static void handleTestsUnconsumedAttr(Sema &S, Decl *D, 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 &S, Scope *scope, Decl *D, } 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(D)) TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); else if (FieldDecl *FD = dyn_cast(D)) { @@ -1197,10 +1156,6 @@ static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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(D)) if (MD->isInstanceMethod()) { @@ -1240,10 +1195,6 @@ static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { } 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, Decl *D, const AttributeList &Attr) { } 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(Attr.getArgAsExpr(0)->IgnoreParenCasts()); @@ -1647,10 +1594,6 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // Check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; @@ -1663,10 +1606,6 @@ static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // Check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -1684,10 +1623,6 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // Check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -1705,10 +1640,6 @@ static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // Check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -1722,10 +1653,6 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // Check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -1739,10 +1666,6 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D, 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(Arg); @@ -1774,10 +1697,6 @@ static void handleTLSModelAttr(Sema &S, Decl *D, } 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(D)) { QualType RetTy = FD->getResultType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { @@ -1792,10 +1711,6 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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(Sema &S, Decl *D, // 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(D)) { ValueDecl *VD = dyn_cast(D); if (VD == 0 || (!VD->getType()->isBlockPointerType() @@ -1979,10 +1890,6 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, } static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D) && !isFunctionOrMethod(D) && !isa(D) && !isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -1997,10 +1904,6 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleReturnsTwiceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -2013,10 +1916,6 @@ static void handleReturnsTwiceAttr(Sema &S, Decl *D, } 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(D)) { if (VD->hasLocalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used"; @@ -2125,9 +2024,6 @@ static void handleAttrWithMessage(Sema &S, Decl *D, 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 &S, Decl *D, 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 handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D, 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, Decl *D, const AttributeList &Attr, 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(Sema &S, Decl *decl, return; } - if (!checkAttributeNumArgs(S, Attr, 1)) - return; - IdentifierLoc *IL = Attr.getArgAsIdent(0); StringRef param = IL->Ident->getName(); @@ -2540,9 +2423,6 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, static void handleObjCExceptionAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - ObjCInterfaceDecl *OCI = dyn_cast(D); if (OCI == 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) @@ -2556,8 +2436,6 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D, } static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; if (TypedefNameDecl *TD = dyn_cast(D)) { QualType T = TD->getUnderlyingType(); if (!T->isCARCBridgableType()) { @@ -2588,9 +2466,6 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { static void handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function); return; @@ -2607,9 +2482,6 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { << 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, Decl *D, const AttributeList &Attr) { } 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(D)) RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context)); else @@ -2734,10 +2602,6 @@ static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isFunction(D) && !isa(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionMethodOrClass; @@ -2762,10 +2626,6 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) } static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D) && !isa(D)) { if (isa(D)) { D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context)); @@ -2784,11 +2644,6 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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, Decl *D, const AttributeList &Attr) { // 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 *D, SourceRange Range, } 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, Decl *D, const AttributeList &Attr) { static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (NoThrowAttr *Existing = D->getAttr()) { if (Existing->getLocation().isInvalid()) Existing->setRange(Attr.getRange()); @@ -2969,9 +2811,6 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (ConstAttr *Existing = D->getAttr()) { if (Existing->getLocation().isInvalid()) Existing->setRange(Attr.getRange()); @@ -2983,10 +2822,6 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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, Decl *D, const AttributeList &Attr) { return; } - if (!checkAttributeNumArgs(S, Attr, 1)) - return; - VarDecl *VD = dyn_cast(D); if (!VD || !VD->hasLocalStorage()) { @@ -3054,9 +2886,6 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { /// 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 &S, Decl *D, 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, Decl *D, const AttributeList &Attr) { << 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, Decl *D, const AttributeList &Attr) { 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(D); @@ -3424,10 +3241,6 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } 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(ArgExpr); @@ -3629,9 +3442,6 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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 *D, const AttributeList &Attr) { } 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(D)) { if (!VD->hasGlobalStorage()) S.Diag(Attr.getLoc(), @@ -3816,11 +3622,6 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -3834,11 +3635,6 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -3852,9 +3648,6 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -3894,10 +3687,6 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -3929,11 +3718,6 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -3950,10 +3734,6 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -3969,10 +3749,6 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (!checkAttributeNumArgs(S, Attr, 0)) - return; - FunctionDecl *Fn = dyn_cast(D); if (Fn == 0) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -4680,10 +4456,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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(Arg); if (!Str || !Str->isAscii()) { @@ -4771,6 +4543,29 @@ static void handleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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, Scope *scope, Decl *D, 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; diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c index 9791826e1b..f74916db94 100644 --- a/test/Sema/attr-mode.c +++ b/test/Sema/attr-mode.c @@ -13,11 +13,12 @@ int i16_2_test[sizeof(i16_1) == 2 ? 1 : -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))); diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index fdc4904f3c..e217d69c13 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -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 &Arg, StringRef Attr, break; } } + + if (Ptr && Arg.getValueAsBit("Optional")) + Ptr->setOptional(true); + return Ptr; } @@ -926,10 +954,13 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { 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 &Records, raw_ostream &OS) { } 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(RecordKeeper &Records, raw_ostream &OS) { << "} // 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 > 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 Attrs = Records.getAllDerivedDefinitions("Attr"); - + ParsedAttrMap R; for (std::vector::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { Record &Attr = **I; @@ -1428,16 +1489,69 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { 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 Args = R.getValueAsListOfDefs("Args"); + unsigned ArgCount = 0, OptCount = 0; + for (std::vector::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 diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 429b6fb311..e6c703fc66 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -34,6 +34,7 @@ enum ActionType { GenClangAttrLateParsedList, GenClangAttrTemplateInstantiate, GenClangAttrParsedAttrList, + GenClangAttrParsedAttrImpl, GenClangAttrParsedAttrKinds, GenClangAttrDump, GenClangDiagsDefs, @@ -81,12 +82,15 @@ cl::opt 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, RecordKeeper &Records) { case GenClangAttrParsedAttrList: EmitClangAttrParsedAttrList(Records, OS); break; + case GenClangAttrParsedAttrImpl: + EmitClangAttrParsedAttrImpl(Records, OS); + break; case GenClangAttrParsedAttrKinds: EmitClangAttrParsedAttrKinds(Records, OS); break; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index b641732b81..d95d0afff1 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -40,6 +40,7 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS); 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);