Index: test/Sema/format-attribute.c =================================================================== --- test/Sema/format-attribute.c (revision 48361) +++ test/Sema/format-attribute.c (working copy) @@ -14,3 +14,5 @@ void y(char *str) __attribute__((format(strftime, 1,0))); // no-error void z(char *str, int c, ...) __attribute__((format(strftime, 1,2))); // expected-error {{strftime format attribute requires 3rd parameter to be 0}} + +int (*f_ptr)(char*,...) __attribute__((format(printf, 1,2))); // no-error Index: Sema/SemaDecl.cpp =================================================================== --- Sema/SemaDecl.cpp (revision 48361) +++ Sema/SemaDecl.cpp (working copy) @@ -2117,6 +2117,24 @@ d->addAttr(new NoThrowAttr()); } +static const FunctionTypeProto *getFunctionProto(Decl *d) { + ValueDecl *decl = dyn_cast(d); + if (!decl) return 0; + + QualType Ty = decl->getType(); + + if (Ty->isFunctionPointerType()) { + const PointerType *PtrTy = Ty->getAsPointerType(); + Ty = PtrTy->getPointeeType(); + } + + if (const FunctionType *FnTy = Ty->getAsFunctionType()) + return dyn_cast(FnTy->getAsFunctionType()); + + return 0; +} + + /// Handle __attribute__((format(type,idx,firstarg))) attributes /// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { @@ -2133,22 +2151,18 @@ return; } - FunctionDecl *Fn = dyn_cast(d); - if (!Fn) { + const FunctionTypeProto *proto = getFunctionProto(d); + + if (!proto) { Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, "format", "function"); return; } - const FunctionTypeProto *proto = - dyn_cast(Fn->getType()->getAsFunctionType()); - if (!proto) - return; - // FIXME: in C++ the implicit 'this' function parameter also counts. // this is needed in order to be compatible with GCC // the index must start in 1 and the limit is numargs+1 - unsigned NumArgs = Fn->getNumParams(); + unsigned NumArgs = proto->getNumArgs(); unsigned FirstIdx = 1; const char *Format = rawAttr->getParameterName()->getName();