(I had to revert this since it caused https://bugs.llvm.org/show_bug.cgi?id=36620)
On Fri, Mar 2, 2018 at 2:03 PM, Joel E. Denny via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: jdenny > Date: Fri Mar 2 11:03:22 2018 > New Revision: 326602 > > URL: http://llvm.org/viewvc/llvm-project?rev=326602&view=rev > Log: > [Attr] Fix parameter indexing for several attributes > > The patch fixes a number of bugs related to parameter indexing in > attributes: > > * Parameter indices in some attributes (argument_with_type_tag, > pointer_with_type_tag, nonnull, ownership_takes, ownership_holds, > and ownership_returns) are specified in source as one-origin > including any C++ implicit this parameter, were stored as > zero-origin excluding any this parameter, and were erroneously > printing (-ast-print) and confusingly dumping (-ast-dump) as the > stored values. > > * For alloc_size, the C++ implicit this parameter was not subtracted > correctly in Sema, leading to assert failures or to silent failures > of __builtin_object_size to compute a value. > > * For argument_with_type_tag, pointer_with_type_tag, and > ownership_returns, the C++ implicit this parameter was not added > back to parameter indices in some diagnostics. > > This patch fixes the above bugs and aims to prevent similar bugs in > the future by introducing careful mechanisms for handling parameter > indices in attributes. ParamIdx stores a parameter index and is > designed to hide the stored encoding while providing accessors that > require each use (such as printing) to make explicit the encoding that > is needed. Attribute declarations declare parameter index arguments > as [Variadic]ParamIdxArgument, which are exposed as ParamIdx[*]. This > patch rewrites all attribute arguments that are processed by > checkFunctionOrMethodParameterIndex in SemaDeclAttr.cpp to be declared > as [Variadic]ParamIdxArgument. The only exception is xray_log_args's > argument, which is encoded as a count not an index. > > Differential Revision: https://reviews.llvm.org/D43248 > > Added: > cfe/trunk/test/Sema/attr-ownership.cpp > Modified: > cfe/trunk/include/clang/AST/Attr.h > cfe/trunk/include/clang/Basic/Attr.td > cfe/trunk/lib/AST/ExprConstant.cpp > cfe/trunk/lib/CodeGen/CGCall.cpp > cfe/trunk/lib/Sema/SemaChecking.cpp > cfe/trunk/lib/Sema/SemaDecl.cpp > cfe/trunk/lib/Sema/SemaDeclAttr.cpp > cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp > cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp > cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp > cfe/trunk/test/CodeGenCXX/alloc-size.cpp > cfe/trunk/test/Misc/ast-dump-attr.cpp > cfe/trunk/test/Sema/attr-print.cpp > cfe/trunk/test/Sema/error-type-safety.cpp > cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp > > Modified: cfe/trunk/include/clang/AST/Attr.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/AST/Attr.h?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/AST/Attr.h (original) > +++ cfe/trunk/include/clang/AST/Attr.h Fri Mar 2 11:03:22 2018 > @@ -195,6 +195,120 @@ public: > } > }; > > +/// A single parameter index whose accessors require each use to make > explicit > +/// the parameter index encoding needed. > +class ParamIdx { > + // Idx is exposed only via accessors that specify specific encodings. > + unsigned Idx : 30; > + unsigned HasThis : 1; > + unsigned IsValid : 1; > + > + void assertComparable(const ParamIdx &I) const { > + assert(isValid() && I.isValid() && > + "ParamIdx must be valid to be compared"); > + // It's possible to compare indices from separate functions, but so > far > + // it's not proven useful. Moreover, it might be confusing because a > + // comparison on the results of getASTIndex might be inconsistent > with a > + // comparison on the ParamIdx objects themselves. > + assert(HasThis == I.HasThis && > + "ParamIdx must be for the same function to be compared"); > + } > + > +public: > + /// Construct an invalid parameter index (\c isValid returns false and > + /// accessors fail an assert). > + ParamIdx() : Idx(0), HasThis(false), IsValid(false) {} > + > + /// \param Idx is the parameter index as it is normally specified in > + /// attributes in the source: one-origin including any C++ implicit this > + /// parameter. > + /// > + /// \param D is the declaration containing the parameters. It is used > to > + /// determine if there is a C++ implicit this parameter. > + ParamIdx(unsigned Idx, const Decl *D) > + : Idx(Idx), HasThis(false), IsValid(true) { > + if (const auto *FD = dyn_cast<FunctionDecl>(D)) > + HasThis = FD->isCXXInstanceMember(); > + } > + > + /// \param Idx is the parameter index as it is normally specified in > + /// attributes in the source: one-origin including any C++ implicit this > + /// parameter. > + /// > + /// \param HasThis specifies whether the function has a C++ implicit > this > + /// parameter. > + ParamIdx(unsigned Idx, bool HasThis) > + : Idx(Idx), HasThis(HasThis), IsValid(true) {} > + > + /// Is this parameter index valid? > + bool isValid() const { return IsValid; } > + > + /// Is there a C++ implicit this parameter? > + bool hasThis() const { > + assert(isValid() && "ParamIdx must be valid"); > + return HasThis; > + } > + > + /// Get the parameter index as it would normally be encoded for > attributes at > + /// the source level of representation: one-origin including any C++ > implicit > + /// this parameter. > + /// > + /// This encoding thus makes sense for diagnostics, pretty printing, and > + /// constructing new attributes from a source-like specification. > + unsigned getSourceIndex() const { > + assert(isValid() && "ParamIdx must be valid"); > + return Idx; > + } > + > + /// Get the parameter index as it would normally be encoded at the AST > level > + /// of representation: zero-origin not including any C++ implicit this > + /// parameter. > + /// > + /// This is the encoding primarily used in Sema. However, in > diagnostics, > + /// Sema uses \c getSourceIndex instead. > + unsigned getASTIndex() const { > + assert(isValid() && "ParamIdx must be valid"); > + assert(Idx >= 1 + HasThis && > + "stored index must be base-1 and not specify C++ implicit > this"); > + return Idx - 1 - HasThis; > + } > + > + /// Get the parameter index as it would normally be encoded at the LLVM > level > + /// of representation: zero-origin including any C++ implicit this > parameter. > + /// > + /// This is the encoding primarily used in CodeGen. > + unsigned getLLVMIndex() const { > + assert(isValid() && "ParamIdx must be valid"); > + assert(Idx >= 1 && "stored index must be base-1"); > + return Idx - 1; > + } > + > + bool operator==(const ParamIdx &I) const { > + assertComparable(I); > + return Idx == I.Idx; > + } > + bool operator!=(const ParamIdx &I) const { > + assertComparable(I); > + return Idx != I.Idx; > + } > + bool operator<(const ParamIdx &I) const { > + assertComparable(I); > + return Idx < I.Idx; > + } > + bool operator>(const ParamIdx &I) const { > + assertComparable(I); > + return Idx > I.Idx; > + } > + bool operator<=(const ParamIdx &I) const { > + assertComparable(I); > + return Idx <= I.Idx; > + } > + bool operator>=(const ParamIdx &I) const { > + assertComparable(I); > + return Idx >= I.Idx; > + } > +}; > + > #include "clang/AST/Attrs.inc" > > inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, > > Modified: cfe/trunk/include/clang/Basic/Attr.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Basic/Attr.td?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Basic/Attr.td (original) > +++ cfe/trunk/include/clang/Basic/Attr.td Fri Mar 2 11:03:22 2018 > @@ -166,6 +166,12 @@ class VariadicUnsignedArgument<string na > class VariadicExprArgument<string name> : Argument<name, 1>; > class VariadicStringArgument<string name> : Argument<name, 1>; > > +// Like VariadicUnsignedArgument except values are ParamIdx. > +class VariadicParamIdxArgument<string name> : Argument<name, 1>; > + > +// Like VariadicParamIdxArgument but for a single function parameter > index. > +class ParamIdxArgument<string name, bit opt = 0> : Argument<name, opt>; > + > // A version of the form major.minor[.subminor]. > class VersionArgument<string name, bit opt = 0> : Argument<name, opt>; > > @@ -611,6 +617,12 @@ def XRayInstrument : InheritableAttr { > def XRayLogArgs : InheritableAttr { > let Spellings = [Clang<"xray_log_args">]; > let Subjects = SubjectList<[Function, ObjCMethod]>; > + // This argument is a count not an index, so it has the same encoding > (base > + // 1 including C++ implicit this parameter) at the source and LLVM > levels of > + // representation, so ParamIdxArgument is inappropriate. It is never > used > + // at the AST level of representation, so it never needs to be adjusted > not > + // to include any C++ implicit this parameter. Thus, we just store it > and > + // use it as an unsigned that never needs adjustment. > let Args = [UnsignedArgument<"ArgumentCount">]; > let Documentation = [XRayDocs]; > } > @@ -1018,7 +1030,8 @@ def EmptyBases : InheritableAttr, Target > def AllocSize : InheritableAttr { > let Spellings = [GCC<"alloc_size">]; > let Subjects = SubjectList<[Function]>; > - let Args = [IntArgument<"ElemSizeParam">, IntArgument<"NumElemsParam", > 1>]; > + let Args = [ParamIdxArgument<"ElemSizeParam">, > + ParamIdxArgument<"NumElemsParam", /*opt*/ 1>]; > let TemplateDependent = 1; > let Documentation = [AllocSizeDocs]; > } > @@ -1105,7 +1118,7 @@ def Format : InheritableAttr { > > def FormatArg : InheritableAttr { > let Spellings = [GCC<"format_arg">]; > - let Args = [IntArgument<"FormatIdx">]; > + let Args = [ParamIdxArgument<"FormatIdx">]; > let Subjects = SubjectList<[ObjCMethod, HasFunctionProto]>; > let Documentation = [Undocumented]; > } > @@ -1385,16 +1398,16 @@ def NonNull : InheritableParamAttr { > let Spellings = [GCC<"nonnull">]; > let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], > WarnDiag, > "functions, methods, and parameters">; > - let Args = [VariadicUnsignedArgument<"Args">]; > - let AdditionalMembers = > -[{bool isNonNull(unsigned idx) const { > - if (!args_size()) > - return true; > - for (const auto &V : args()) > - if (V == idx) > + let Args = [VariadicParamIdxArgument<"Args">]; > + let AdditionalMembers = [{ > + bool isNonNull(unsigned IdxAST) const { > + if (!args_size()) > return true; > - return false; > - } }]; > + return args_end() != std::find_if( > + args_begin(), args_end(), > + [=](const ParamIdx &Idx) { return Idx.getASTIndex() == IdxAST; > }); > + } > + }]; > // FIXME: We should merge duplicates into a single nonnull attribute. > let InheritEvenIfAlreadyPresent = 1; > let Documentation = [NonNullDocs]; > @@ -1452,7 +1465,7 @@ def AssumeAligned : InheritableAttr { > def AllocAlign : InheritableAttr { > let Spellings = [GCC<"alloc_align">]; > let Subjects = SubjectList<[HasFunctionProto]>; > - let Args = [IntArgument<"ParamIndex">]; > + let Args = [ParamIdxArgument<"ParamIndex">]; > let Documentation = [AllocAlignDocs]; > } > > @@ -1661,7 +1674,8 @@ def Ownership : InheritableAttr { > Returns; > } > }]; > - let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<" > Args">]; > + let Args = [IdentifierArgument<"Module">, > + VariadicParamIdxArgument<"Args">]; > let Subjects = SubjectList<[HasFunctionProto]>; > let Documentation = [Undocumented]; > } > @@ -2486,8 +2500,8 @@ def ArgumentWithTypeTag : InheritableAtt > Clang<"pointer_with_type_tag">]; > let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; > let Args = [IdentifierArgument<"ArgumentKind">, > - UnsignedArgument<"ArgumentIdx">, > - UnsignedArgument<"TypeTagIdx">, > + ParamIdxArgument<"ArgumentIdx">, > + ParamIdxArgument<"TypeTagIdx">, > BoolArgument<"IsPointer", /*opt*/0, /*fake*/1>]; > let Documentation = [ArgumentWithTypeTagDocs, PointerWithTypeTagDocs]; > } > > Modified: cfe/trunk/lib/AST/ExprConstant.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ > ExprConstant.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/AST/ExprConstant.cpp (original) > +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Mar 2 11:03:22 2018 > @@ -5463,9 +5463,8 @@ static bool getBytesReturnedByAllocSizeC > llvm::APInt &Result) { > const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); > > - // alloc_size args are 1-indexed, 0 means not present. > - assert(AllocSize && AllocSize->getElemSizeParam() != 0); > - unsigned SizeArgNo = AllocSize->getElemSizeParam() - 1; > + assert(AllocSize && AllocSize->elemSizeParam().isValid()); > + unsigned SizeArgNo = AllocSize->elemSizeParam().getASTIndex(); > unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); > if (Call->getNumArgs() <= SizeArgNo) > return false; > @@ -5483,14 +5482,13 @@ static bool getBytesReturnedByAllocSizeC > if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) > return false; > > - if (!AllocSize->getNumElemsParam()) { > + if (!AllocSize->numElemsParam().isValid()) { > Result = std::move(SizeOfElem); > return true; > } > > APSInt NumberOfElems; > - // Argument numbers start at 1 > - unsigned NumArgNo = AllocSize->getNumElemsParam() - 1; > + unsigned NumArgNo = AllocSize->numElemsParam().getASTIndex(); > if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) > return false; > > > Modified: cfe/trunk/lib/CodeGen/CGCall.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ > CGCall.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri Mar 2 11:03:22 2018 > @@ -1847,10 +1847,9 @@ void CodeGenModule::ConstructAttributeLi > HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>(); > if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) { > Optional<unsigned> NumElemsParam; > - // alloc_size args are base-1, 0 means not present. > - if (unsigned N = AllocSize->getNumElemsParam()) > - NumElemsParam = N - 1; > - FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam() - 1, > + if (AllocSize->numElemsParam().isValid()) > + NumElemsParam = AllocSize->numElemsParam().getLLVMIndex(); > + FuncAttrs.addAllocSizeAttr(AllocSize->elemSizeParam(). > getLLVMIndex(), > NumElemsParam); > } > } > @@ -4395,7 +4394,7 @@ RValue CodeGenFunction::EmitCall(const C > OffsetValue); > } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) { > llvm::Value *ParamVal = > - CallArgs[AA->getParamIndex() - 1].RV.getScalarVal(); > + CallArgs[AA->paramIndex().getLLVMIndex()].RV.getScalarVal(); > EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal); > } > } > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaChecking.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Mar 2 11:03:22 2018 > @@ -2619,12 +2619,13 @@ static void CheckNonNullArguments(Sema & > return; > } > > - for (unsigned Val : NonNull->args()) { > - if (Val >= Args.size()) > + for (const ParamIdx &Idx : NonNull->args()) { > + unsigned IdxAST = Idx.getASTIndex(); > + if (IdxAST >= Args.size()) > continue; > if (NonNullArgs.empty()) > NonNullArgs.resize(Args.size()); > - NonNullArgs.set(Val); > + NonNullArgs.set(IdxAST); > } > } > } > @@ -5002,12 +5003,7 @@ checkFormatStringExpr(Sema &S, const Exp > const CallExpr *CE = cast<CallExpr>(E); > if (const NamedDecl *ND = > dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) > { > if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { > - unsigned ArgIndex = FA->getFormatIdx(); > - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) > - if (MD->isInstance()) > - --ArgIndex; > - const Expr *Arg = CE->getArg(ArgIndex - 1); > - > + const Expr *Arg = CE->getArg(FA->formatIdx().getASTIndex()); > return checkFormatStringExpr(S, Arg, Args, > HasVAListArg, format_idx, > firstDataArg, > Type, CallType, InFunctionCall, > @@ -5032,8 +5028,7 @@ checkFormatStringExpr(Sema &S, const Exp > const auto *ME = cast<ObjCMessageExpr>(E); > if (const auto *ND = ME->getMethodDecl()) { > if (const auto *FA = ND->getAttr<FormatArgAttr>()) { > - unsigned ArgIndex = FA->getFormatIdx(); > - const Expr *Arg = ME->getArg(ArgIndex - 1); > + const Expr *Arg = ME->getArg(FA->formatIdx().getASTIndex()); > return checkFormatStringExpr( > S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, > CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, > Offset); > @@ -10086,8 +10081,8 @@ void Sema::DiagnoseAlwaysNonNullPointer( > return; > } > > - for (unsigned ArgNo : NonNull->args()) { > - if (ArgNo == ParamNo) { > + for (const ParamIdx &ArgNo : NonNull->args()) { > + if (ArgNo.getASTIndex() == ParamNo) { > ComplainAboutNonnullParamOrCall(NonNull); > return; > } > @@ -12242,13 +12237,13 @@ void Sema::CheckArgumentWithTypeTag(cons > bool IsPointerAttr = Attr->getIsPointer(); > > // Retrieve the argument representing the 'type_tag'. > - if (Attr->getTypeTagIdx() >= ExprArgs.size()) { > - // Add 1 to display the user's specified value. > + unsigned TypeTagIdxAST = Attr->typeTagIdx().getASTIndex(); > + if (TypeTagIdxAST >= ExprArgs.size()) { > Diag(CallSiteLoc, diag::err_tag_index_out_of_range) > - << 0 << Attr->getTypeTagIdx() + 1; > + << 0 << Attr->typeTagIdx().getSourceIndex(); > return; > } > - const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; > + const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST]; > bool FoundWrongKind; > TypeTagData TypeInfo; > if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, > @@ -12262,13 +12257,13 @@ void Sema::CheckArgumentWithTypeTag(cons > } > > // Retrieve the argument representing the 'arg_idx'. > - if (Attr->getArgumentIdx() >= ExprArgs.size()) { > - // Add 1 to display the user's specified value. > + unsigned ArgumentIdxAST = Attr->argumentIdx().getASTIndex(); > + if (ArgumentIdxAST >= ExprArgs.size()) { > Diag(CallSiteLoc, diag::err_tag_index_out_of_range) > - << 1 << Attr->getArgumentIdx() + 1; > + << 1 << Attr->argumentIdx().getSourceIndex(); > return; > } > - const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; > + const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST]; > if (IsPointerAttr) { > // Skip implicit cast of pointer to `void *' (as a function argument). > if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>( > ArgumentExpr)) > > Modified: cfe/trunk/lib/Sema/SemaDecl.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaDecl.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Mar 2 11:03:22 2018 > @@ -13176,7 +13176,7 @@ void Sema::AddKnownFunctionAttributes(Fu > // We already have a __builtin___CFStringMakeConstantString, > // but builds that use -fno-constant-cfstrings don't go through that. > if (!FD->hasAttr<FormatArgAttr>()) > - FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1, > + FD->addAttr(FormatArgAttr::CreateImplicit(Context, ParamIdx(1, FD), > FD->getLocation())); > } > } > > Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaDeclAttr.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Mar 2 11:03:22 2018 > @@ -311,7 +311,7 @@ static bool checkAttrMutualExclusion(Sem > template <typename AttrInfo> > static bool checkFunctionOrMethodParameterIndex( > Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, > - const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) { > + const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = > false) { > assert(isFunctionOrMethodOrBlock(D)); > > // In C++ the implicit 'this' function parameter also counts. > @@ -331,21 +331,20 @@ static bool checkFunctionOrMethodParamet > return false; > } > > - Idx = IdxInt.getLimitedValue(); > - if (Idx < 1 || (!IV && Idx > NumParams)) { > + Idx = ParamIdx(IdxInt.getLimitedValue(UINT_MAX), D); > + unsigned IdxSource = Idx.getSourceIndex(); > + if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { > S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) > - << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); > + << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); > return false; > } > - Idx--; // Convert to zero-based. > - if (HasImplicitThisParam && !AllowImplicitThis) { > - if (Idx == 0) { > + if (HasImplicitThisParam && !CanIndexImplicitThis) { > + if (IdxSource == 1) { > S.Diag(getAttrLoc(AI), > diag::err_attribute_invalid_implicit_this_argument) > - << getAttrName(AI) << IdxExpr->getSourceRange(); > + << getAttrName(AI) << IdxExpr->getSourceRange(); > return false; > } > - --Idx; > } > > return true; > @@ -772,18 +771,15 @@ static void handleAssertExclusiveLockAtt > /// AttrArgNo is used to actually retrieve the argument, so it's base-0. > template <typename AttrInfo> > static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, > - const AttrInfo &AI, unsigned > AttrArgNo, > - bool AllowDependentType = false) { > + const AttrInfo &AI, unsigned > AttrArgNo) { > assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); > Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); > - uint64_t Idx; > + ParamIdx Idx; > if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, > AttrArg, > Idx)) > return false; > > - const ParmVarDecl *Param = FD->getParamDecl(Idx); > - if (AllowDependentType && Param->getType()->isDependentType()) > - return true; > + const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); > if (!Param->getType()->isIntegerType() && > !Param->getType()->isCharType()) { > SourceLocation SrcLoc = AttrArg->getLocStart(); > S.Diag(SrcLoc, diag::err_attribute_integers_only) > @@ -806,22 +802,23 @@ static void handleAllocSizeAttr(Sema &S, > } > > const Expr *SizeExpr = AL.getArgAsExpr(0); > - int SizeArgNo; > + int SizeArgNoVal; > // Parameter indices are 1-indexed, hence Index=1 > - if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNo, /*Index=*/1)) > + if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, > /*Index=*/1)) > return; > + ParamIdx SizeArgNo(SizeArgNoVal, D); > > if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0)) > return; > > - // Args are 1-indexed, so 0 implies that the arg was not present > - int NumberArgNo = 0; > + ParamIdx NumberArgNo; > if (AL.getNumArgs() == 2) { > const Expr *NumberExpr = AL.getArgAsExpr(1); > + int Val; > // Parameter indices are 1-based, hence Index=2 > - if (!checkPositiveIntArgument(S, AL, NumberExpr, NumberArgNo, > - /*Index=*/2)) > + if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2)) > return; > + NumberArgNo = ParamIdx(Val, D); > > if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1)) > return; > @@ -1424,18 +1421,19 @@ static bool attrNonNullArgCheck(Sema &S, > } > > static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &AL) { > - SmallVector<unsigned, 8> NonNullArgs; > + SmallVector<ParamIdx, 8> NonNullArgs; > for (unsigned I = 0; I < AL.getNumArgs(); ++I) { > Expr *Ex = AL.getArgAsExpr(I); > - uint64_t Idx; > + ParamIdx Idx; > if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) > return; > > // Is the function argument a pointer type? > - if (Idx < getFunctionOrMethodNumParams(D) && > - !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), AL, > - Ex->getSourceRange(), > - getFunctionOrMethodParamRange(D, Idx))) > + if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) && > + !attrNonNullArgCheck( > + S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL, > + Ex->getSourceRange(), > + getFunctionOrMethodParamRange(D, Idx.getASTIndex()))) > continue; > > NonNullArgs.push_back(Idx); > @@ -1459,12 +1457,12 @@ static void handleNonNullAttr(Sema &S, D > S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers); > } > > - unsigned *Start = NonNullArgs.data(); > + ParamIdx *Start = NonNullArgs.data(); > unsigned Size = NonNullArgs.size(); > llvm::array_pod_sort(Start, Start + Size); > D->addAttr(::new (S.Context) > - NonNullAttr(AL.getRange(), S.Context, Start, Size, > - AL.getAttributeSpellingListIndex())); > + NonNullAttr(AL.getRange(), S.Context, Start, Size, > + AL.getAttributeSpellingListIndex())); > } > > static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, > @@ -1485,8 +1483,8 @@ static void handleNonNullAttrParameter(S > return; > > D->addAttr(::new (S.Context) > - NonNullAttr(AL.getRange(), S.Context, nullptr, 0, > - AL.getAttributeSpellingListIndex())); > + NonNullAttr(AL.getRange(), S.Context, nullptr, 0, > + AL.getAttributeSpellingListIndex())); > } > > static void handleReturnsNonNullAttr(Sema &S, Decl *D, > @@ -1587,7 +1585,7 @@ void Sema::AddAllocAlignAttr(SourceRange > unsigned SpellingListIndex) { > QualType ResultType = getFunctionOrMethodResultType(D); > > - AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex); > + AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), > SpellingListIndex); > SourceLocation AttrLoc = AttrRange.getBegin(); > > if (!ResultType->isDependentType() && > @@ -1597,28 +1595,22 @@ void Sema::AddAllocAlignAttr(SourceRange > return; > } > > - uint64_t IndexVal; > + ParamIdx Idx; > const auto *FuncDecl = cast<FunctionDecl>(D); > if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, > - /*AttrArgNo=*/1, ParamExpr, > - IndexVal)) > + /*AttrArgNo=*/1, ParamExpr, > Idx)) > return; > > - QualType Ty = getFunctionOrMethodParamType(D, IndexVal); > + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); > if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { > Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) > - << &TmpAttr << FuncDecl->getParamDecl( > IndexVal)->getSourceRange(); > + << &TmpAttr > + << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); > return; > } > > - // We cannot use the Idx returned from checkFunctionOrMethodParameter > Index > - // because that has corrected for the implicit this parameter, and is > zero- > - // based. The attribute expects what the user wrote explicitly. > - llvm::APSInt Val; > - ParamExpr->EvaluateAsInt(Val, Context); > - > - D->addAttr(::new (Context) AllocAlignAttr( > - AttrRange, Context, Val.getZExtValue(), SpellingListIndex)); > + D->addAttr(::new (Context) > + AllocAlignAttr(AttrRange, Context, Idx, > SpellingListIndex)); > } > > /// Normalize the attribute, __foo__ becomes foo. > @@ -1678,15 +1670,15 @@ static void handleOwnershipAttr(Sema &S, > Module = &S.PP.getIdentifierTable().get(ModuleName); > } > > - SmallVector<unsigned, 8> OwnershipArgs; > + SmallVector<ParamIdx, 8> OwnershipArgs; > for (unsigned i = 1; i < AL.getNumArgs(); ++i) { > Expr *Ex = AL.getArgAsExpr(i); > - uint64_t Idx; > + ParamIdx Idx; > if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) > return; > > // Is the function argument a pointer type? > - QualType T = getFunctionOrMethodParamType(D, Idx); > + QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); > int Err = -1; // No error > switch (K) { > case OwnershipAttr::Takes: > @@ -1717,14 +1709,13 @@ static void handleOwnershipAttr(Sema &S, > } else if (K == OwnershipAttr::Returns && > I->getOwnKind() == OwnershipAttr::Returns) { > // A returns attribute conflicts with any other returns attribute > using > - // a different index. Note, diagnostic reporting is 1-based, but > stored > - // argument indexes are 0-based. > + // a different index. > if (std::find(I->args_begin(), I->args_end(), Idx) == > I->args_end()) { > S.Diag(I->getLocation(), diag::err_ownership_returns_ > index_mismatch) > - << *(I->args_begin()) + 1; > + << I->args_begin()->getSourceIndex(); > if (I->args_size()) > S.Diag(AL.getLoc(), diag::note_ownership_returns_ > index_mismatch) > - << (unsigned)Idx + 1 << Ex->getSourceRange(); > + << Idx.getSourceIndex() << Ex->getSourceRange(); > return; > } > } > @@ -1732,13 +1723,12 @@ static void handleOwnershipAttr(Sema &S, > OwnershipArgs.push_back(Idx); > } > > - unsigned* start = OwnershipArgs.data(); > - unsigned size = OwnershipArgs.size(); > - llvm::array_pod_sort(start, start + size); > - > + ParamIdx *Start = OwnershipArgs.data(); > + unsigned Size = OwnershipArgs.size(); > + llvm::array_pod_sort(Start, Start + Size); > D->addAttr(::new (S.Context) > - OwnershipAttr(AL.getLoc(), S.Context, Module, start, size, > - AL.getAttributeSpellingListIndex())); > + OwnershipAttr(AL.getLoc(), S.Context, Module, Start, > Size, > + AL.getAttributeSpellingListIndex())); > } > > static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &AL) { > @@ -3109,12 +3099,12 @@ static void handleEnumExtensibilityAttr( > /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html > static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList > &AL) { > Expr *IdxExpr = AL.getArgAsExpr(0); > - uint64_t Idx; > + ParamIdx Idx; > if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) > return; > > // Make sure the format string is really a string. > - QualType Ty = getFunctionOrMethodParamType(D, Idx); > + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); > > bool NotNSStringTy = !isNSStringType(Ty, S.Context); > if (NotNSStringTy && > @@ -3137,15 +3127,8 @@ static void handleFormatArgAttr(Sema &S, > return; > } > > - // We cannot use the Idx returned from checkFunctionOrMethodParameter > Index > - // because that has corrected for the implicit this parameter, and is > zero- > - // based. The attribute expects what the user wrote explicitly. > - llvm::APSInt Val; > - IdxExpr->EvaluateAsInt(Val, S.Context); > - > - D->addAttr(::new (S.Context) > - FormatArgAttr(AL.getRange(), S.Context, Val.getZExtValue(), > - AL.getAttributeSpellingListIndex())); > + D->addAttr(::new (S.Context) FormatArgAttr( > + AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex( > ))); > } > > enum FormatAttrKind { > @@ -4539,13 +4522,13 @@ static void handleArgumentWithTypeTagAtt > << AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; > return; > } > - > - uint64_t ArgumentIdx; > + > + ParamIdx ArgumentIdx; > if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, > AL.getArgAsExpr(1), > ArgumentIdx)) > return; > > - uint64_t TypeTagIdx; > + ParamIdx TypeTagIdx; > if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, > AL.getArgAsExpr(2), > TypeTagIdx)) > return; > @@ -4553,8 +4536,9 @@ static void handleArgumentWithTypeTagAtt > bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag"; > if (IsPointer) { > // Ensure that buffer has a pointer type. > - if (ArgumentIdx >= getFunctionOrMethodNumParams(D) || > - !getFunctionOrMethodParamType(D, ArgumentIdx)->isPointerType()) > + unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); > + if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) || > + !getFunctionOrMethodParamType(D, ArgumentIdxAST)-> > isPointerType()) > S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) > << AL.getName() << 0; > } > @@ -4594,19 +4578,18 @@ static void handleTypeTagForDatatypeAttr > AL.getAttributeSpellingListIndex())); > } > > -static void handleXRayLogArgsAttr(Sema &S, Decl *D, > - const AttributeList &AL) { > - uint64_t ArgCount; > +static void handleXRayLogArgsAttr(Sema &S, Decl *D, const AttributeList > &AL) { > + ParamIdx ArgCount; > > if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, > AL.getArgAsExpr(0), > ArgCount, > - true /* AllowImplicitThis*/)) > + true /* CanIndexImplicitThis > */)) > return; > > - // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + > 1. > - D->addAttr(::new (S.Context) > - XRayLogArgsAttr(AL.getRange(), S.Context, ++ArgCount, > - AL.getAttributeSpellingListIndex())); > + // ArgCount isn't a parameter index [0;n), it's a count [1;n] > + D->addAttr(::new (S.Context) XRayLogArgsAttr( > + AL.getRange(), S.Context, ArgCount.getSourceIndex(), > + AL.getAttributeSpellingListIndex())); > } > > //===------------------------------------------------------- > ---------------===// > > Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaTemplateInstantiateDecl.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) > +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Mar 2 > 11:03:22 2018 > @@ -176,7 +176,7 @@ static void instantiateDependentAllocAli > Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, > const AllocAlignAttr *Align, Decl *New) { > Expr *Param = IntegerLiteral::Create( > - S.getASTContext(), llvm::APInt(64, Align->getParamIndex()), > + S.getASTContext(), llvm::APInt(64, Align->paramIndex(). > getSourceIndex()), > S.getASTContext().UnsignedLongLongTy, Align->getLocation()); > S.AddAllocAlignAttr(Align->getLocation(), New, Param, > Align->getSpellingListIndex()); > > Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ > StaticAnalyzer/Checkers/MallocChecker.cpp?rev=326602& > r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original) > +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Fri Mar 2 > 11:03:22 2018 > @@ -1231,9 +1231,10 @@ MallocChecker::MallocMemReturnsAttr(Chec > if (Att->getModule() != II_malloc) > return nullptr; > > - OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); > + ParamIdx *I = Att->args_begin(), *E = Att->args_end(); > if (I != E) { > - return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), State); > + return MallocMemAux(C, CE, CE->getArg(I->getASTIndex()), > UndefinedVal(), > + State); > } > return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State); > } > @@ -1331,9 +1332,9 @@ ProgramStateRef MallocChecker::FreeMemAt > bool ReleasedAllocated = false; > > for (const auto &Arg : Att->args()) { > - ProgramStateRef StateI = FreeMemAux(C, CE, State, Arg, > - Att->getOwnKind() == OwnershipAttr::Holds, > - ReleasedAllocated); > + ProgramStateRef StateI = FreeMemAux( > + C, CE, State, Arg.getASTIndex(), > + Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated); > if (StateI) > State = StateI; > } > > Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ > StaticAnalyzer/Checkers/NonNullParamChecker.cpp?rev= > 326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp > (original) > +++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp Fri > Mar 2 11:03:22 2018 > @@ -58,10 +58,11 @@ void NonNullParamChecker::checkPreCall(c > AttrNonNull.set(0, NumArgs); > break; > } > - for (unsigned Val : NonNull->args()) { > - if (Val >= NumArgs) > + for (const ParamIdx &Idx : NonNull->args()) { > + unsigned IdxAST = Idx.getASTIndex(); > + if (IdxAST >= NumArgs) > continue; > - AttrNonNull.set(Val); > + AttrNonNull.set(IdxAST); > } > } > > > Modified: cfe/trunk/test/CodeGenCXX/alloc-size.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ > CodeGenCXX/alloc-size.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CodeGenCXX/alloc-size.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/alloc-size.cpp Fri Mar 2 11:03:22 2018 > @@ -69,4 +69,22 @@ int testIt() { > __builtin_object_size(dependent_calloc<7, 8>(), 0) + > __builtin_object_size(dependent_calloc2<int, 9>(), 0); > } > +} // namespace templated_alloc_size > + > +class C { > +public: > + void *my_malloc(int N) __attribute__((alloc_size(2))); > + void *my_calloc(int N, int M) __attribute__((alloc_size(2, 3))); > +}; > + > +// CHECK-LABEL: define i32 @_Z16callMemberMallocv > +int callMemberMalloc() { > + // CHECK: ret i32 16 > + return __builtin_object_size(C().my_malloc(16), 0); > +} > + > +// CHECK-LABEL: define i32 @_Z16callMemberCallocv > +int callMemberCalloc() { > + // CHECK: ret i32 32 > + return __builtin_object_size(C().my_calloc(16, 2), 0); > } > > Modified: cfe/trunk/test/Misc/ast-dump-attr.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ > ast-dump-attr.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/test/Misc/ast-dump-attr.cpp (original) > +++ cfe/trunk/test/Misc/ast-dump-attr.cpp Fri Mar 2 11:03:22 2018 > @@ -68,12 +68,12 @@ __attribute__((pointer_with_type_tag(ide > void TestBool(void *, int) > __attribute__((pointer_with_type_tag(bool1,1,2))); > // CHECK: FunctionDecl{{.*}}TestBool > -// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 0 1 > IsPointer > +// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 1 2 > IsPointer > > void TestUnsigned(void *, int) > __attribute__((pointer_with_type_tag(unsigned1,1,2))); > // CHECK: FunctionDecl{{.*}}TestUnsigned > -// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 > 0 1 > +// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 > 1 2 > > void TestInt(void) __attribute__((constructor(123))); > // CHECK: FunctionDecl{{.*}}TestInt > > Added: cfe/trunk/test/Sema/attr-ownership.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ > attr-ownership.cpp?rev=326602&view=auto > ============================================================ > ================== > --- cfe/trunk/test/Sema/attr-ownership.cpp (added) > +++ cfe/trunk/test/Sema/attr-ownership.cpp Fri Mar 2 11:03:22 2018 > @@ -0,0 +1,7 @@ > +// RUN: %clang_cc1 %s -verify -fsyntax-only > + > +class C { > + void f(int, int) > + __attribute__((ownership_returns(foo, 2))) // expected-note > {{declared with index 2 here}} > + __attribute__((ownership_returns(foo, 3))); // expected-error > {{'ownership_returns' attribute index does not match; here it is 3}} > +}; > > Modified: cfe/trunk/test/Sema/attr-print.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ > attr-print.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/test/Sema/attr-print.cpp (original) > +++ cfe/trunk/test/Sema/attr-print.cpp Fri Mar 2 11:03:22 2018 > @@ -1,6 +1,67 @@ > // RUN: %clang_cc1 %s -ast-print | FileCheck %s > > +// CHECK: void xla(int a) __attribute__((xray_log_args(1))); > +void xla(int a) __attribute__((xray_log_args(1))); > + > // CHECK: void *as2(int, int) __attribute__((alloc_size(1, 2))); > void *as2(int, int) __attribute__((alloc_size(1, 2))); > // CHECK: void *as1(void *, int) __attribute__((alloc_size(2))); > void *as1(void *, int) __attribute__((alloc_size(2))); > + > +// CHECK: void fmt(int, const char *, ...) __attribute__((format(printf, > 2, 3))); > +void fmt(int, const char *, ...) __attribute__((format(printf, 2, 3))); > + > +// CHECK: char *fmta(int, const char *) __attribute__((format_arg(2))); > +char *fmta(int, const char *) __attribute__((format_arg(2))); > + > +// CHECK: void nn(int *, int *) __attribute__((nonnull(1, 2))); > +void nn(int *, int *) __attribute__((nonnull(1, 2))); > + > +// CHECK: int *aa(int i) __attribute__((alloc_align(1))); > +int *aa(int i) __attribute__((alloc_align(1))); > + > +// CHECK: void ownt(int *, int *) __attribute__((ownership_takes(foo, 1, > 2))); > +void ownt(int *, int *) __attribute__((ownership_takes(foo, 1, 2))); > +// CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, > 2))); > +void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, 2))); > +// CHECK: void ownr(int) __attribute__((ownership_returns(foo, 1))); > +void ownr(int) __attribute__((ownership_returns(foo, 1))); > + > +// CHECK: void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, > 3, 2))); > +void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 3, > 2))); > +// CHECK: void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, > 1, 2))); > +void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 1, 2))); > + > +class C { > + // CHECK: void xla(int a) __attribute__((xray_log_args(2))); > + void xla(int a) __attribute__((xray_log_args(2))); > + > + // CHECK: void *as2(int, int) __attribute__((alloc_size(2, 3))); > + void *as2(int, int) __attribute__((alloc_size(2, 3))); > + // CHECK: void *as1(void *, int) __attribute__((alloc_size(3))); > + void *as1(void *, int) __attribute__((alloc_size(3))); > + > + // CHECK: void fmt(int, const char *, ...) > __attribute__((format(printf, 3, 4))); > + void fmt(int, const char *, ...) __attribute__((format(printf, 3, 4))); > + > + // CHECK: char *fmta(int, const char *) __attribute__((format_arg(3))); > + char *fmta(int, const char *) __attribute__((format_arg(3))); > + > + // CHECK: void nn(int *, int *) __attribute__((nonnull(2, 3))); > + void nn(int *, int *) __attribute__((nonnull(2, 3))); > + > + // CHECK: int *aa(int i) __attribute__((alloc_align(2))); > + int *aa(int i) __attribute__((alloc_align(2))); > + > + // CHECK: void ownt(int *, int *) __attribute__((ownership_takes(foo, > 2, 3))); > + void ownt(int *, int *) __attribute__((ownership_takes(foo, 2, 3))); > + // CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, > 2, 3))); > + void ownh(int *, int *) __attribute__((ownership_holds(foo, 2, 3))); > + // CHECK: void ownr(int) __attribute__((ownership_returns(foo, 2))); > + void ownr(int) __attribute__((ownership_returns(foo, 2))); > + > + // CHECK: void awtt(int, int, ...) > __attribute__((argument_with_type_tag(foo, > 4, 3))); > + void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 4, > 3))); > + // CHECK: void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, > 2, 3))); > + void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 2, > 3))); > +}; > > Modified: cfe/trunk/test/Sema/error-type-safety.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ > error-type-safety.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/test/Sema/error-type-safety.cpp (original) > +++ cfe/trunk/test/Sema/error-type-safety.cpp Fri Mar 2 11:03:22 2018 > @@ -3,21 +3,50 @@ > #define INT_TAG 42 > > static const int test_in > - __attribute__((type_tag_for_datatype(test, int))) = INT_TAG; > + __attribute__((type_tag_for_datatype(test, int))) = INT_TAG; > > // Argument index: 1, Type tag index: 2 > void test_bounds_index(...) > - __attribute__((argument_with_type_tag(test, 1, 2))); > + __attribute__((argument_with_type_tag(test, 1, 2))); > + > +// Argument index: 1, Type tag index: 2 > +void test_bounds_index_ptr(void *, ...) > + __attribute__((pointer_with_type_tag(test, 1, 2))); > > // Argument index: 3, Type tag index: 1 > void test_bounds_arg_index(...) > - __attribute__((argument_with_type_tag(test, 3, 1))); > + __attribute__((argument_with_type_tag(test, 3, 1))); > + > +class C { > +public: > + // Argument index: 2, Type tag index: 3 > + void test_bounds_index(...) > + __attribute__((argument_with_type_tag(test, 2, 3))); > + > + // Argument index: 2, Type tag index: 3 > + void test_bounds_index_ptr(void *, ...) > + __attribute__((pointer_with_type_tag(test, 2, 3))); > + > + // Argument index: 4, Type tag index: 2 > + void test_bounds_arg_index(...) > + __attribute__((argument_with_type_tag(test, 4, 2))); > +}; > > void test_bounds() > { > + C c; > + > // Test the boundary edges (ensure no off-by-one) with argument > indexing. > test_bounds_index(1, INT_TAG); > + c.test_bounds_index(1, INT_TAG); > + test_bounds_index_ptr(0, INT_TAG); > + c.test_bounds_index_ptr(0, INT_TAG); > + > + test_bounds_index(1); // expected-error {{type tag index 2 is > greater than the number of arguments specified}} > + c.test_bounds_index(1); // expected-error {{type tag index 3 is > greater than the number of arguments specified}} > + test_bounds_index_ptr(0); // expected-error {{type tag index 2 is > greater than the number of arguments specified}} > + c.test_bounds_index_ptr(0); // expected-error {{type tag index 3 is > greater than the number of arguments specified}} > > - test_bounds_index(1); // expected-error {{type tag index 2 is greater > than the number of arguments specified}} > - test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument index 3 > is greater than the number of arguments specified}} > + test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument index > 3 is greater than the number of arguments specified}} > + c.test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument > index 4 is greater than the number of arguments specified}} > } > > Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/ > TableGen/ClangAttrEmitter.cpp?rev=326602&r1=326601&r2=326602&view=diff > ============================================================ > ================== > --- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original) > +++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Mar 2 11:03:22 2018 > @@ -302,9 +302,6 @@ namespace { > std::string getIsOmitted() const override { > if (type == "IdentifierInfo *") > return "!get" + getUpperName().str() + "()"; > - // FIXME: Do this declaratively in Attr.td. > - if (getAttrName() == "AllocSize") > - return "0 == get" + getUpperName().str() + "()"; > return "false"; > } > > @@ -748,6 +745,138 @@ namespace { > } > }; > > + class VariadicParamIdxArgument : public VariadicArgument { > + public: > + VariadicParamIdxArgument(const Record &Arg, StringRef Attr) > + : VariadicArgument(Arg, Attr, "ParamIdx") {} > + > + public: > + void writeCtorBody(raw_ostream &OS) const override { > + VariadicArgument::writeCtorBody(OS); > + OS << " #ifndef NDEBUG\n" > + << " if (" << getLowerName() << "_size()) {\n" > + << " bool HasThis = " << getLowerName() > + << "_begin()->hasThis();\n" > + << " for (const auto Idx : " << getLowerName() << "()) {\n" > + << " assert(Idx.isValid() && \"ParamIdx must be > valid\");\n" > + << " assert(HasThis == Idx.hasThis() && " > + << "\"HasThis must be consistent\");\n" > + << " }\n" > + << " }\n" > + << " #endif\n"; > + } > + > + void writePCHReadDecls(raw_ostream &OS) const override { > + OS << " unsigned " << getUpperName() << "Size = > Record.readInt();\n"; > + OS << " bool " << getUpperName() << "HasThis = " << > getUpperName() > + << "Size ? Record.readInt() : false;\n"; > + OS << " SmallVector<ParamIdx, 4> " << getUpperName() << ";\n" > + << " " << getUpperName() << ".reserve(" << getUpperName() > + << "Size);\n" > + << " for (unsigned i = 0; i != " << getUpperName() > + << "Size; ++i) {\n" > + << " " << getUpperName() > + << ".push_back(ParamIdx(Record.readInt(), " << getUpperName() > + << "HasThis));\n" > + << " }\n"; > + } > + > + void writePCHReadArgs(raw_ostream &OS) const override { > + OS << getUpperName() << ".data(), " << getUpperName() << "Size"; > + } > + > + void writePCHWrite(raw_ostream &OS) const override { > + OS << " Record.push_back(SA->" << getLowerName() << > "_size());\n"; > + OS << " if (SA->" << getLowerName() << "_size())\n" > + << " Record.push_back(SA->" << getLowerName() > + << "_begin()->hasThis());\n"; > + OS << " for (auto Idx : SA->" << getLowerName() << "())\n" > + << " Record.push_back(Idx.getSourceIndex());\n"; > + } > + > + void writeValueImpl(raw_ostream &OS) const override { > + OS << " OS << Val.getSourceIndex();\n"; > + } > + > + void writeDump(raw_ostream &OS) const override { > + OS << " for (auto Idx : SA->" << getLowerName() << "())\n"; > + OS << " OS << \" \" << Idx.getSourceIndex();\n"; > + } > + }; > + > + class ParamIdxArgument : public Argument { > + std::string IdxName; > + > + public: > + ParamIdxArgument(const Record &Arg, StringRef Attr) > + : Argument(Arg, Attr), IdxName(getUpperName()) {} > + > + void writeDeclarations(raw_ostream &OS) const override { > + OS << "ParamIdx " << IdxName << ";\n"; > + } > + > + void writeAccessors(raw_ostream &OS) const override { > + OS << "\n" > + << " ParamIdx " << getLowerName() << "() const {" > + << " return " << IdxName << "; }\n"; > + } > + > + void writeCtorParameters(raw_ostream &OS) const override { > + OS << "ParamIdx " << IdxName; > + } > + > + void writeCloneArgs(raw_ostream &OS) const override { OS << IdxName; } > + > + void writeTemplateInstantiationArgs(raw_ostream &OS) const override { > + OS << "A->" << getLowerName() << "()"; > + } > + > + void writeImplicitCtorArgs(raw_ostream &OS) const override { > + OS << IdxName; > + } > + > + void writeCtorInitializers(raw_ostream &OS) const override { > + OS << IdxName << "(" << IdxName << ")"; > + } > + > + void writeCtorDefaultInitializers(raw_ostream &OS) const override { > + OS << IdxName << "()"; > + } > + > + void writePCHReadDecls(raw_ostream &OS) const override { > + OS << " unsigned " << IdxName << "Src = Record.readInt();\n"; > + OS << " bool " << IdxName << "HasThis = Record.readInt();\n"; > + } > + > + void writePCHReadArgs(raw_ostream &OS) const override { > + OS << "ParamIdx(" << IdxName << "Src, " << IdxName << "HasThis)"; > + } > + > + void writePCHWrite(raw_ostream &OS) const override { > + OS << " Record.push_back(SA->" << getLowerName() > + << "().isValid() ? SA->" << getLowerName() > + << "().getSourceIndex() : 0);\n"; > + OS << " Record.push_back(SA->" << getLowerName() > + << "().isValid() ? SA->" << getLowerName() > + << "().hasThis() : false);\n"; > + } > + > + std::string getIsOmitted() const override { > + return "!" + IdxName + ".isValid()"; > + } > + > + void writeValue(raw_ostream &OS) const override { > + OS << "\" << " << IdxName << ".getSourceIndex() << \""; > + } > + > + void writeDump(raw_ostream &OS) const override { > + if (isOptional()) > + OS << " if (SA->" << getLowerName() << "().isValid())\n "; > + OS << " OS << \" \" << SA->" << getLowerName() > + << "().getSourceIndex();\n"; > + } > + }; > + > // Unique the enums, but maintain the original declaration ordering. > std::vector<StringRef> > uniqueEnumsInOrder(const std::vector<StringRef> &enums) { > @@ -1247,6 +1376,10 @@ createArgument(const Record &Arg, String > Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr); > else if (ArgName == "VariadicExprArgument") > Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr); > + else if (ArgName == "VariadicParamIdxArgument") > + Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr); > + else if (ArgName == "ParamIdxArgument") > + Ptr = llvm::make_unique<ParamIdxArgument>(Arg, Attr); > else if (ArgName == "VersionArgument") > Ptr = llvm::make_unique<VersionArgument>(Arg, Attr); > > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits