r326602 - [Attr] Fix parameter indexing for several attributes

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 7 13:49:18 PST 2018


Joel, can you investigate the issue?

~Aaron

On Wed, Mar 7, 2018 at 4:32 PM, Nico Weber via cfe-commits
<cfe-commits at lists.llvm.org> 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
> <cfe-commits at 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
>> 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
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>


More information about the cfe-commits mailing list