diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-11-17 18:02:24 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-11-17 18:02:24 +0000 |
commit | 4a2614e94672c47395abcde60518776fbebec589 (patch) | |
tree | 793db4f94de9dd0f2c7c7ee3be9d4ed09be41f37 | |
parent | 24a069f5ebf441d86eaec7524365101adf6b2aeb (diff) |
Adjust format attribute index for implicit object arguments. Fixes PR5521.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89113 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/format-attribute.cpp | 8 |
3 files changed, 35 insertions, 2 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 92f1ba5d6a..9060fe6ab7 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -91,6 +91,12 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { if (Format->getType() == "printf0") { // printf0 allows null "format" string; if so don't check format/args unsigned format_idx = Format->getFormatIdx() - 1; + // Does the index refer to the implicit object argument? + if (isa<CXXMemberCallExpr>(TheCall)) { + if (format_idx == 0) + return false; + --format_idx; + } if (format_idx < TheCall->getNumArgs()) { Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts(); if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) @@ -204,7 +210,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { if (!HasVAListArg) { if (const FunctionProtoType *Proto = FDecl->getType()->getAs<FunctionProtoType>()) - HasVAListArg = !Proto->isVariadic(); + HasVAListArg = !Proto->isVariadic(); } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); @@ -970,6 +976,18 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg) { const Expr *Fn = TheCall->getCallee(); + // The way the format attribute works in GCC, the implicit this argument + // of member functions is counted. However, it doesn't appear in our own + // lists, so decrement format_idx in that case. + if (isa<CXXMemberCallExpr>(TheCall)) { + // Catch a format attribute mistakenly referring to the object argument. + if (format_idx == 0) + return; + --format_idx; + if(firstDataArg != 0) + --firstDataArg; + } + // CHECK: printf-like function is called with no format string. if (format_idx >= TheCall->getNumArgs()) { Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 803be138c2..e7ea43be02 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1351,7 +1351,14 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: Do we need to bounds check? unsigned ArgIdx = Idx.getZExtValue() - 1; - if (HasImplicitThisParam) ArgIdx--; + if (HasImplicitThisParam) { + if (ArgIdx == 0) { + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << "a string type" << IdxExpr->getSourceRange(); + return; + } + ArgIdx--; + } // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); diff --git a/test/SemaCXX/format-attribute.cpp b/test/SemaCXX/format-attribute.cpp new file mode 100644 index 0000000000..a21ebe1130 --- /dev/null +++ b/test/SemaCXX/format-attribute.cpp @@ -0,0 +1,8 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5521 +struct A { void a(const char*,...) __attribute((format(printf,2,3))); }; +void b(A x) { + x.a("%d", 3); +} +struct X { void a(const char*,...) __attribute((format(printf,1,3))); }; // expected-error {{format argument not a string type}} |