From: Aaron Ballman Date: Tue, 30 Jul 2013 00:48:57 +0000 (+0000) Subject: Refactor some attributes to use checkFunctionOrMethodArgumentIndex instead of using... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b3d7efe0f95bc44f0e93602f4617a53ca3b66e3a;p=clang Refactor some attributes to use checkFunctionOrMethodArgumentIndex instead of using custom logic. No functional changes intended. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187398 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 016c0f1c0b..e925a70af9 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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 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 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 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 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 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(); - return; - } - - if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << "format" << 2 << IdxExpr->getSourceRange(); + uint64_t ArgIdx; + if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(), + Attr.getLoc(), 1, IdxExpr, ArgIdx)) 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())); } diff --git a/test/Sema/alloc_size.c b/test/Sema/alloc_size.c index 46d94f7cdc..2e9c30411e 100644 --- a/test/Sema/alloc_size.c +++ b/test/Sema/alloc_size.c @@ -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}} diff --git a/test/Sema/attr-format.c b/test/Sema/attr-format.c index a223e08f5a..21d9585a57 100644 --- a/test/Sema/attr-format.c +++ b/test/Sema/attr-format.c @@ -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}} diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c index 1544be52f2..4e6171160f 100644 --- a/test/Sema/nonnull.c +++ b/test/Sema/nonnull.c @@ -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}}