Joel, can you investigate the issue? ~Aaron
On Wed, Mar 7, 2018 at 4:32 PM, Nico Weber via cfe-commits <[email protected]> wrote: > (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 > <[email protected]> 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 >> checkFunctionOrMethodParameterIndex >> - // 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 >> checkFunctionOrMethodParameterIndex >> - // 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 >> [email protected] >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > _______________________________________________ cfe-commits mailing list [email protected] http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
