aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2009-11-17 18:02:24 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2009-11-17 18:02:24 +0000
commit4a2614e94672c47395abcde60518776fbebec589 (patch)
tree793db4f94de9dd0f2c7c7ee3be9d4ed09be41f37
parent24a069f5ebf441d86eaec7524365101adf6b2aeb (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.cpp20
-rw-r--r--lib/Sema/SemaDeclAttr.cpp9
-rw-r--r--test/SemaCXX/format-attribute.cpp8
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}}