r326602 - [Attr] Fix parameter indexing for several attributes

Joel E. Denny via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 2 11:03:23 PST 2018


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);
 




More information about the cfe-commits mailing list