This revision was automatically updated to reflect the committed changes. Closed by commit rC336239: [Sema] Consider all format_arg attributes. (authored by Meinersbur, committed by ).
Changed prior to commit: https://reviews.llvm.org/D48734?vs=153643&id=154038#toc Repository: rC Clang https://reviews.llvm.org/D48734 Files: lib/Sema/SemaChecking.cpp test/Sema/attr-format_arg.c Index: test/Sema/attr-format_arg.c =================================================================== --- test/Sema/attr-format_arg.c +++ test/Sema/attr-format_arg.c @@ -4,10 +4,27 @@ const char* f(const char *s) __attribute__((format_arg(1))); +const char *h(const char *msg1, const char *msg2) + __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2))); + void g(const char *s) { printf("%d", 123); printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}} printf(f("%d"), 123); printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}} + + printf(h( + "", // expected-warning {{format string is empty}} + "" // expected-warning {{format string is empty}} + ), 123); + printf(h( + "%d", + "" // expected-warning {{format string is empty}} + ), 123); + printf(h( + "", // expected-warning {{format string is empty}} + "%d" + ), 123); + printf(h("%d", "%d"), 123); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -5518,13 +5518,22 @@ case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { - if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { + bool IsFirst = true; + StringLiteralCheckType CommonResult; + for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + StringLiteralCheckType Result = checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + if (IsFirst) { + CommonResult = Result; + IsFirst = false; + } + } + if (!IsFirst) + return CommonResult; + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
Index: test/Sema/attr-format_arg.c =================================================================== --- test/Sema/attr-format_arg.c +++ test/Sema/attr-format_arg.c @@ -4,10 +4,27 @@ const char* f(const char *s) __attribute__((format_arg(1))); +const char *h(const char *msg1, const char *msg2) + __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2))); + void g(const char *s) { printf("%d", 123); printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}} printf(f("%d"), 123); printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}} + + printf(h( + "", // expected-warning {{format string is empty}} + "" // expected-warning {{format string is empty}} + ), 123); + printf(h( + "%d", + "" // expected-warning {{format string is empty}} + ), 123); + printf(h( + "", // expected-warning {{format string is empty}} + "%d" + ), 123); + printf(h("%d", "%d"), 123); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -5518,13 +5518,22 @@ case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { - if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { + bool IsFirst = true; + StringLiteralCheckType CommonResult; + for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + StringLiteralCheckType Result = checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + if (IsFirst) { + CommonResult = Result; + IsFirst = false; + } + } + if (!IsFirst) + return CommonResult; + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits