]> granicus.if.org Git - clang/commitdiff
Adjust format attribute index for implicit object arguments. Fixes PR5521.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 17 Nov 2009 18:02:24 +0000 (18:02 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 17 Nov 2009 18:02:24 +0000 (18:02 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89113 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
lib/Sema/SemaDeclAttr.cpp
test/SemaCXX/format-attribute.cpp [new file with mode: 0644]

index 92f1ba5d6ad0fa25903cd957bf244be90eead310..9060fe6ab742da05df1d05889b9e915481c4e71d 100644 (file)
@@ -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)
index 803be138c2626a9d4f21334b53f84f2780f799e1..e7ea43be021b402d6957417caa8b5df376541e78 100644 (file)
@@ -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 (file)
index 0000000..a21ebe1
--- /dev/null
@@ -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}}