Author: Félix Cloutier Date: 2021-10-27T15:48:35-07:00 New Revision: d378a0febc7e13aae7853b2e8733626f61140e55
URL: https://github.com/llvm/llvm-project/commit/d378a0febc7e13aae7853b2e8733626f61140e55 DIFF: https://github.com/llvm/llvm-project/commit/d378a0febc7e13aae7853b2e8733626f61140e55.diff LOG: [Sema] Recognize format argument indicated by format attribute inside blocks - `[[format(archetype, fmt-idx, ellipsis)]]` specifies that a function accepts a format string and arguments according to `archetype`. This is how Clang type-checks `printf` arguments based on the format string. - Clang has a `-Wformat-nonliteral` warning that is triggered when a function with the `format` attribute is called with a format string that is not inspectable because it isn't constant. This warning is suppressed if the caller has the `format` attribute itself and the format argument to the callee is the caller's own format parameter. - When using the `format` attribute on a block, Clang wouldn't recognize its format parameter when calling another function with the format attribute. This would cause unsuppressed -Wformat-nonliteral warnings for no supported reason. Reviewed By: ahatanak Differential Revision: https://reviews.llvm.org/D112569 Radar-Id: rdar://84603673 Added: Modified: clang/lib/Sema/SemaChecking.cpp clang/test/Sema/format-strings.c Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 83fb824cb14a6..3eaeae197648a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7784,11 +7784,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, // } if (HasVAListArg) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) { - if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) { + if (const Decl *D = dyn_cast<Decl>(PV->getDeclContext())) { int PVIndex = PV->getFunctionScopeIndex() + 1; - for (const auto *PVFormat : ND->specific_attrs<FormatAttr>()) { + for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) { // adjust for implicit parameter - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) if (MD->isInstance()) ++PVIndex; // We also check if the formats are compatible. diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index e8cd478d25126..bbe47636ebb7d 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s +// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s +// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s #include <stdarg.h> #include <stddef.h> @@ -714,3 +714,30 @@ void PR30481() { void test_printf_opaque_ptr(void *op) { printf("%s", op); // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}} } + +void test_block() { + void __attribute__((__format__(__printf__, 1, 2))) (^printf_arg1)( + const char *, ...) = + ^(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))) { + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + }; + + printf_arg1("%s string %i\n", "aaa", 123); + printf_arg1("%s string\n", 123); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}} + + void __attribute__((__format__(__printf__, 2, 3))) (^printf_arg2)( + const char *, const char *, ...) = + ^(const char *not_fmt, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))) { + va_list ap; + va_start(ap, fmt); + vprintf(not_fmt, ap); // expected-warning{{format string is not a string literal}} + va_end(ap); + }; + + printf_arg2("foo", "%s string %i\n", "aaa", 123); + printf_arg2("%s string\n", "foo", "bar"); // expected-warning{{data argument not used by format string}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits