r327405 - Reland "[Attr] Fix parameter indexing for several attributes"
Joel E. Denny via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 13 07:51:23 PDT 2018
Author: jdenny
Date: Tue Mar 13 07:51:22 2018
New Revision: 327405
URL: http://llvm.org/viewvc/llvm-project?rev=327405&view=rev
Log:
Reland "[Attr] Fix parameter indexing for several attributes"
Relands r326602 (reverted in r326862) with new test and fix for
PR36620.
Differential Revision: https://reviews.llvm.org/D43248
Added:
cfe/trunk/test/Frontend/ast-attr.cpp
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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Tue Mar 13 07:51:22 2018
@@ -195,6 +195,128 @@ 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) {
+ assert(Idx >= 1 && "Idx must be one-origin");
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ HasThis = FD->isCXXInstanceMember();
+ }
+
+ /// A type into which \c ParamIdx can be serialized.
+ ///
+ /// A static assertion that it's of the correct size follows the \c ParamIdx
+ /// class definition.
+ typedef uint32_t SerialType;
+
+ /// Produce a representation that can later be passed to \c deserialize to
+ /// construct an equivalent \c ParamIdx.
+ SerialType serialize() const {
+ return *reinterpret_cast<const SerialType *>(this);
+ }
+
+ /// Construct from a result from \c serialize.
+ static ParamIdx deserialize(SerialType S) {
+ ParamIdx P(*reinterpret_cast<ParamIdx *>(&S));
+ assert((!P.IsValid || P.Idx >= 1) && "valid Idx must be one-origin");
+ return P;
+ }
+
+ /// Is this parameter index valid?
+ bool isValid() const { return IsValid; }
+
+ /// 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;
+ }
+};
+
+static_assert(sizeof(ParamIdx) == sizeof(ParamIdx::SerialType),
+ "ParamIdx does not fit its serialization type");
+
#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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Mar 13 07:51:22 2018
@@ -169,6 +169,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>;
@@ -614,6 +620,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];
}
@@ -1021,7 +1033,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];
}
@@ -1108,7 +1121,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];
}
@@ -1388,16 +1401,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];
@@ -1455,7 +1468,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];
}
@@ -1664,7 +1677,8 @@ def Ownership : InheritableAttr {
Returns;
}
}];
- let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">];
+ let Args = [IdentifierArgument<"Module">,
+ VariadicParamIdxArgument<"Args">];
let Subjects = SubjectList<[HasFunctionProto]>;
let Documentation = [Undocumented];
}
@@ -2490,8 +2504,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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Mar 13 07:51:22 2018
@@ -5475,9 +5475,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->getElemSizeParam().isValid());
+ unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex();
unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
if (Call->getNumArgs() <= SizeArgNo)
return false;
@@ -5495,14 +5494,13 @@ static bool getBytesReturnedByAllocSizeC
if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem))
return false;
- if (!AllocSize->getNumElemsParam()) {
+ if (!AllocSize->getNumElemsParam().isValid()) {
Result = std::move(SizeOfElem);
return true;
}
APSInt NumberOfElems;
- // Argument numbers start at 1
- unsigned NumArgNo = AllocSize->getNumElemsParam() - 1;
+ unsigned NumArgNo = AllocSize->getNumElemsParam().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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Tue Mar 13 07:51: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->getNumElemsParam().isValid())
+ NumElemsParam = AllocSize->getNumElemsParam().getLLVMIndex();
+ FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(),
NumElemsParam);
}
}
@@ -4399,7 +4398,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->getParamIndex().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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Mar 13 07:51: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->getFormatIdx().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->getFormatIdx().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->getTypeTagIdx().getASTIndex();
+ if (TypeTagIdxAST >= ExprArgs.size()) {
Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
- << 0 << Attr->getTypeTagIdx() + 1;
+ << 0 << Attr->getTypeTagIdx().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->getArgumentIdx().getASTIndex();
+ if (ArgumentIdxAST >= ExprArgs.size()) {
Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
- << 1 << Attr->getArgumentIdx() + 1;
+ << 1 << Attr->getArgumentIdx().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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar 13 07:51:22 2018
@@ -13185,7 +13185,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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Mar 13 07:51:22 2018
@@ -312,7 +312,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.
@@ -332,23 +332,22 @@ static bool checkFunctionOrMethodParamet
return false;
}
- Idx = IdxInt.getLimitedValue();
- if (Idx < 1 || (!IV && Idx > NumParams)) {
+ unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX);
+ 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;
}
+ Idx = ParamIdx(IdxSource, D);
return true;
}
@@ -773,18 +772,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)
@@ -807,25 +803,24 @@ 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;
-
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0))
return;
+ ParamIdx SizeArgNo(SizeArgNoVal, D);
- // 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;
-
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1))
return;
+ NumberArgNo = ParamIdx(Val, D);
}
D->addAttr(::new (S.Context)
@@ -1425,18 +1420,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);
@@ -1460,12 +1456,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,
@@ -1486,8 +1482,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,
@@ -1588,7 +1584,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() &&
@@ -1598,28 +1594,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.
@@ -1679,15 +1669,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:
@@ -1718,14 +1708,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;
}
}
@@ -1733,13 +1722,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) {
@@ -3057,12 +3045,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 &&
@@ -3085,15 +3073,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 {
@@ -4487,13 +4468,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;
@@ -4501,8 +4482,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;
}
@@ -4542,19 +4524,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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Mar 13 07:51:22 2018
@@ -176,7 +176,8 @@ 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->getParamIndex().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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Tue Mar 13 07:51: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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp Tue Mar 13 07:51:22 2018
@@ -54,10 +54,11 @@ static llvm::SmallBitVector getNonNullAt
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);
}
}
return AttrNonNull;
Modified: cfe/trunk/test/CodeGenCXX/alloc-size.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/alloc-size.cpp?rev=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/alloc-size.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/alloc-size.cpp Tue Mar 13 07:51:22 2018
@@ -86,3 +86,21 @@ int testIt() {
return __builtin_object_size(p, 0);
}
} // namespace alloc_size_with_cleanups
+
+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);
+}
Added: cfe/trunk/test/Frontend/ast-attr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/ast-attr.cpp?rev=327405&view=auto
==============================================================================
--- cfe/trunk/test/Frontend/ast-attr.cpp (added)
+++ cfe/trunk/test/Frontend/ast-attr.cpp Tue Mar 13 07:51:22 2018
@@ -0,0 +1,5 @@
+// RUN: %clang -emit-ast -o %t.ast %S/../Sema/attr-print.cpp
+// RUN: %clang_cc1 %t.ast -ast-print | FileCheck %S/../Sema/attr-print.cpp
+
+// %S/../Sema/attr-print.cpp exercises many different attributes, so we reuse
+// it here to check -emit-ast for attributes.
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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/test/Misc/ast-dump-attr.cpp (original)
+++ cfe/trunk/test/Misc/ast-dump-attr.cpp Tue Mar 13 07:51: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=327405&view=auto
==============================================================================
--- cfe/trunk/test/Sema/attr-ownership.cpp (added)
+++ cfe/trunk/test/Sema/attr-ownership.cpp Tue Mar 13 07:51: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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-print.cpp (original)
+++ cfe/trunk/test/Sema/attr-print.cpp Tue Mar 13 07:51:22 2018
@@ -1,6 +1,69 @@
// RUN: %clang_cc1 %s -ast-print | FileCheck %s
+// This file is also used as input for %S/../Frontend/ast-attr.cpp.
+
+// 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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/test/Sema/error-type-safety.cpp (original)
+++ cfe/trunk/test/Sema/error-type-safety.cpp Tue Mar 13 07:51: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=327405&r1=327404&r2=327405&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Tue Mar 13 07:51:22 2018
@@ -104,6 +104,7 @@ static std::string ReadPCHRecord(StringR
.Case("Expr *", "Record.readExpr()")
.Case("IdentifierInfo *", "Record.getIdentifierInfo()")
.Case("StringRef", "Record.readString()")
+ .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())")
.Default("Record.readInt()");
}
@@ -122,6 +123,7 @@ static std::string WritePCHRecord(String
.Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
.Case("IdentifierInfo *", "AddIdentifierRef(" + std::string(name) + ");\n")
.Case("StringRef", "AddString(" + std::string(name) + ");\n")
+ .Case("ParamIdx", "push_back(" + std::string(name) + ".serialize());\n")
.Default("push_back(" + std::string(name) + ");\n");
}
@@ -302,9 +304,8 @@ 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() + "()";
+ if (type == "ParamIdx")
+ return "!get" + getUpperName().str() + "().isValid()";
return "false";
}
@@ -319,6 +320,8 @@ namespace {
<< "()->getName() : \"\") << \"";
else if (type == "TypeSourceInfo *")
OS << "\" << get" << getUpperName() << "().getAsString() << \"";
+ else if (type == "ParamIdx")
+ OS << "\" << get" << getUpperName() << "().getSourceIndex() << \"";
else
OS << "\" << get" << getUpperName() << "() << \"";
}
@@ -341,6 +344,11 @@ namespace {
<< getUpperName() << "\";\n";
} else if (type == "int" || type == "unsigned") {
OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
+ } else if (type == "ParamIdx") {
+ if (isOptional())
+ OS << " if (SA->get" << getUpperName() << "().isValid())\n ";
+ OS << " OS << \" \" << SA->get" << getUpperName()
+ << "().getSourceIndex();\n";
} else {
llvm_unreachable("Unknown SimpleArgument type!");
}
@@ -618,6 +626,10 @@ namespace {
virtual void writeValueImpl(raw_ostream &OS) const {
OS << " OS << Val;\n";
}
+ // Assumed to receive a parameter: raw_ostream OS.
+ virtual void writeDumpImpl(raw_ostream &OS) const {
+ OS << " OS << \" \" << Val;\n";
+ }
public:
VariadicArgument(const Record &Arg, StringRef Attr, std::string T)
@@ -744,7 +756,22 @@ namespace {
void writeDump(raw_ostream &OS) const override {
OS << " for (const auto &Val : SA->" << RangeName << "())\n";
- OS << " OS << \" \" << Val;\n";
+ writeDumpImpl(OS);
+ }
+ };
+
+ class VariadicParamIdxArgument : public VariadicArgument {
+ public:
+ VariadicParamIdxArgument(const Record &Arg, StringRef Attr)
+ : VariadicArgument(Arg, Attr, "ParamIdx") {}
+
+ public:
+ void writeValueImpl(raw_ostream &OS) const override {
+ OS << " OS << Val.getSourceIndex();\n";
+ }
+
+ void writeDumpImpl(raw_ostream &OS) const override {
+ OS << " OS << \" \" << Val.getSourceIndex();\n";
}
};
@@ -1247,6 +1274,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<SimpleArgument>(Arg, Attr, "ParamIdx");
else if (ArgName == "VersionArgument")
Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
More information about the cfe-commits
mailing list