Refactor some attributes to use checkFunctionOrMethodArgumentIndex instead of using custom logic. No functional changes intended.

llvm-svn: 187398
This commit is contained in:
Aaron Ballman 2013-07-30 00:48:57 +00:00
parent e2e0548d77
commit be50eb86e6
4 changed files with 50 additions and 160 deletions

View File

@ -251,13 +251,15 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
const Expr *IdxExpr,
uint64_t &Idx)
{
assert(isFunctionOrMethod(D) && hasFunctionProto(D));
assert(isFunctionOrMethod(D));
// In C++ the implicit 'this' function parameter also counts.
// Parameters are counted from one.
const bool HasImplicitThisParam = isInstanceMethod(D);
const unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
const unsigned FirstIdx = 1;
bool HP = hasFunctionProto(D);
bool HasImplicitThisParam = isInstanceMethod(D);
bool IV = HP && isFunctionOrMethodVariadic(D);
unsigned NumArgs = (HP ? getFunctionOrMethodNumArgs(D) : 0) +
HasImplicitThisParam;
llvm::APSInt IdxInt;
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
@ -269,7 +271,7 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
}
Idx = IdxInt.getLimitedValue();
if (Idx < FirstIdx || (!isFunctionOrMethodVariadic(D) && Idx > NumArgs)) {
if (Idx < 1 || (!IV && Idx > NumArgs)) {
S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds)
<< AttrName << AttrArgNum << IdxExpr->getSourceRange();
return false;
@ -1163,70 +1165,35 @@ static void possibleTransparentUnionPointerType(QualType &T) {
static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< "alloc_size" << ExpectedFunctionOrMethod;
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
unsigned NumArgs;
if (hasFunctionProto(D))
NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
else
NumArgs = 0;
SmallVector<unsigned, 8> SizeArgs;
for (AttributeList::arg_iterator I = Attr.arg_begin(),
E = Attr.arg_end(); I!=E; ++I) {
// The argument must be an integer constant expression.
Expr *Ex = *I;
llvm::APSInt ArgNum;
if (Ex->isTypeDependent() || Ex->isValueDependent() ||
!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "alloc_size" << Ex->getSourceRange();
for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
Expr *Ex = Attr.getArg(i);
uint64_t Idx;
if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
Attr.getLoc(), i + 1, Ex, Idx))
return;
}
uint64_t x = ArgNum.getZExtValue();
if (x < 1 || x > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "alloc_size" << I.getArgNum() << Ex->getSourceRange();
return;
}
--x;
if (HasImplicitThisParam) {
if (x == 0) {
S.Diag(Attr.getLoc(),
diag::err_attribute_invalid_implicit_this_argument)
<< "alloc_size" << Ex->getSourceRange();
return;
}
--x;
}
// check if the function argument is of an integer type
QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
if (!T->isIntegerType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "alloc_size" << Ex->getSourceRange();
<< "alloc_size" << Ex->getSourceRange();
return;
}
SizeArgs.push_back(x);
SizeArgs.push_back(Idx);
}
// check if the function returns a pointer
if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
<< "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
<< Attr.getName() << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
}
D->addAttr(::new (S.Context)
@ -1244,47 +1211,16 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
SmallVector<unsigned, 10> NonNullArgs;
for (AttributeList::arg_iterator I = Attr.arg_begin(),
E = Attr.arg_end(); I != E; ++I) {
// The argument must be an integer constant expression.
Expr *Ex = *I;
llvm::APSInt ArgNum(32);
if (Ex->isTypeDependent() || Ex->isValueDependent() ||
!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "nonnull" << Ex->getSourceRange();
SmallVector<unsigned, 8> NonNullArgs;
for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
Expr *Ex = Attr.getArg(i);
uint64_t Idx;
if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
Attr.getLoc(), i + 1, Ex, Idx))
return;
}
unsigned x = (unsigned) ArgNum.getZExtValue();
if (x < 1 || x > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "nonnull" << I.getArgNum() << Ex->getSourceRange();
return;
}
--x;
if (HasImplicitThisParam) {
if (x == 0) {
S.Diag(Attr.getLoc(),
diag::err_attribute_invalid_implicit_this_argument)
<< "nonnull" << Ex->getSourceRange();
return;
}
--x;
}
// Is the function argument a pointer type?
QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
possibleTransparentUnionPointerType(T);
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
@ -1294,7 +1230,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
continue;
}
NonNullArgs.push_back(x);
NonNullArgs.push_back(Idx);
}
// If no arguments were specified to __attribute__((nonnull)) then all pointer
@ -1378,59 +1314,32 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
return;
}
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
StringRef Module = AL.getParameterName()->getName();
// Normalize the argument, __foo__ becomes foo.
if (Module.startswith("__") && Module.endswith("__"))
Module = Module.substr(2, Module.size() - 4);
SmallVector<unsigned, 10> OwnershipArgs;
for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E;
++I) {
Expr *IdxExpr = *I;
llvm::APSInt ArgNum(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
|| !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_not_int)
<< AL.getName()->getName() << IdxExpr->getSourceRange();
continue;
}
unsigned x = (unsigned) ArgNum.getZExtValue();
if (x > NumArgs || x < 1) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< AL.getName()->getName() << x << IdxExpr->getSourceRange();
continue;
}
--x;
if (HasImplicitThisParam) {
if (x == 0) {
S.Diag(AL.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
<< "ownership" << IdxExpr->getSourceRange();
return;
}
--x;
}
SmallVector<unsigned, 8> OwnershipArgs;
for (unsigned i = 0; i < AL.getNumArgs(); ++i) {
Expr *Ex = AL.getArg(i);
uint64_t Idx;
if (!checkFunctionOrMethodArgumentIndex(S, D, AL.getName()->getName(),
AL.getLoc(), i + 1, Ex, Idx))
return;
switch (K) {
case OwnershipAttr::Takes:
case OwnershipAttr::Holds: {
// Is the function argument a pointer type?
QualType T = getFunctionOrMethodArgType(D, x);
QualType T = getFunctionOrMethodArgType(D, Idx);
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(AL.getLoc(), diag::err_ownership_type)
<< ((K==OwnershipAttr::Takes)?"ownership_takes":"ownership_holds")
<< "pointer"
<< IdxExpr->getSourceRange();
<< Ex->getSourceRange();
continue;
}
break;
@ -1460,14 +1369,14 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
if ((*i)->getOwnKind() != K) {
for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end();
I!=E; ++I) {
if (x == *I) {
if (Idx == *I) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< AL.getName()->getName() << "ownership_*";
}
}
}
}
OwnershipArgs.push_back(x);
OwnershipArgs.push_back(Idx);
}
unsigned* start = OwnershipArgs.data();
@ -3043,39 +2952,11 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
// checks for the 2nd argument
Expr *IdxExpr = Attr.getArg(0);
llvm::APSInt Idx(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
<< Attr.getName() << 2 << ArgumentIntegerConstant
<< IdxExpr->getSourceRange();
uint64_t ArgIdx;
if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
Attr.getLoc(), 1, IdxExpr, ArgIdx))
return;
}
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
}
unsigned ArgIdx = Idx.getZExtValue() - 1;
if (HasImplicitThisParam) {
if (ArgIdx == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
<< "format_arg" << IdxExpr->getSourceRange();
return;
}
ArgIdx--;
}
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
@ -3103,8 +2984,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
// We cannot use the ArgIdx returned from checkFunctionOrMethodArgumentIndex
// 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(Attr.getRange(), S.Context, Idx.getZExtValue(),
FormatArgAttr(Attr.getRange(), S.Context, Val.getZExtValue(),
Attr.getAttributeSpellingListIndex()));
}

View File

@ -5,7 +5,7 @@ void* my_calloc(unsigned char, short) __attribute__((alloc_size(1,2)));
void* my_realloc(void*, unsigned) __attribute__((alloc_size(2)));
void* fn1(int) __attribute__((alloc_size("xpto"))); // expected-error{{attribute requires integer constant}}
void* fn1(int) __attribute__((alloc_size("xpto"))); // expected-error{{'alloc_size' attribute requires parameter 1 to be an integer constant}}
void* fn2(void*) __attribute__((alloc_size(1))); // expected-error{{attribute requires integer constant}}

View File

@ -78,3 +78,5 @@ extern void gcc_cxxformat (const char *, ...)
__attribute__ ((__format__(__gcc_cxxdiag__, 1, 2)));
extern void gcc_tformat (const char *, ...)
__attribute__ ((__format__(__gcc_tdiag__, 1, 2)));
const char *foo3(const char *format) __attribute__((format_arg("foo"))); // expected-error{{'format_arg' attribute requires parameter 1 to be an integer constant}}

View File

@ -19,3 +19,4 @@ int main(void) {
Class_init(obj, "Hello World");
}
void foo(const char *str) __attribute__((nonnull("foo"))); // expected-error{{'nonnull' attribute requires parameter 1 to be an integer constant}}