From b57bde6263b4190a5d4e464dc982f624fc34da46 Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Fri, 23 Aug 2019 18:01:57 +0000 Subject: [PATCH] [Sema] Don't warn on printf('%hd', [char]) (PR41467) Summary: Link: https://bugs.llvm.org/show_bug.cgi?id=41467 Reviewers: rsmith, nickdesaulniers, aaron.ballman, lebedev.ri Reviewed By: nickdesaulniers, aaron.ballman, lebedev.ri Subscribers: lebedev.ri, nickdesaulniers, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66186 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369791 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/FormatString.cpp | 2 ++ lib/Sema/SemaChecking.cpp | 8 ++++++-- test/FixIt/format.m | 4 +--- test/Sema/format-strings-enum-fixed-type.cpp | 8 ++++---- test/Sema/format-strings-pedantic.c | 10 ++++++++++ test/Sema/format-strings.c | 4 ++-- 6 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 test/Sema/format-strings-pedantic.c diff --git a/lib/AST/FormatString.cpp b/lib/AST/FormatString.cpp index 578d5bc567..ff439f9921 100644 --- a/lib/AST/FormatString.cpp +++ b/lib/AST/FormatString.cpp @@ -386,6 +386,8 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::Char_U: case BuiltinType::UChar: + if (T == C.UnsignedShortTy || T == C.ShortTy) + return NoMatchPedantic; return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match : NoMatch; case BuiltinType::Short: diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 07db04e4ff..1b6390adc4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -8119,9 +8119,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // function. if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { - // All further checking is done on the subexpression. - if (AT.matchesType(S.Context, ExprTy)) + // All further checking is done on the subexpression + const analyze_printf::ArgType::MatchKind ImplicitMatch = + AT.matchesType(S.Context, ExprTy); + if (ImplicitMatch == analyze_printf::ArgType::Match) return true; + if (ImplicitMatch == analyze_printf::ArgType::NoMatchPedantic) + Pedantic = true; } } } else if (const CharacterLiteral *CL = dyn_cast(E)) { diff --git a/test/FixIt/format.m b/test/FixIt/format.m index 40655a0e80..ef27b1bac3 100644 --- a/test/FixIt/format.m +++ b/test/FixIt/format.m @@ -205,9 +205,7 @@ void test_percent_C() { // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%f" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)" - NSLog(@"%C", (char)0x260300); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}} - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c" - // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:"(unichar)" + NSLog(@"%C", (char)0x260300); NSLog(@"%C", 'a'); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c" diff --git a/test/Sema/format-strings-enum-fixed-type.cpp b/test/Sema/format-strings-enum-fixed-type.cpp index 0022ccbc66..de22f09378 100644 --- a/test/Sema/format-strings-enum-fixed-type.cpp +++ b/test/Sema/format-strings-enum-fixed-type.cpp @@ -79,10 +79,10 @@ void testChar(CharEnum input) { printf("%hhd", input); // no-warning printf("%hhd", CharConstant); // no-warning - // This is not correct but it is safe. We warn because '%hd' shows intent. - printf("%hd", input); // expected-warning{{format specifies type 'short' but the argument has underlying type 'char'}} - printf("%hd", CharConstant); // expected-warning{{format specifies type 'short'}} - + // This is not correct, but it is safe. Only warned in pedantic mode because '%hd' shows intent. + printf("%hd", input); + printf("%hd", CharConstant); + // This is not correct but it matches the promotion rules (and is safe). printf("%d", input); // no-warning printf("%d", CharConstant); // no-warning diff --git a/test/Sema/format-strings-pedantic.c b/test/Sema/format-strings-pedantic.c new file mode 100644 index 0000000000..8fb298ab79 --- /dev/null +++ b/test/Sema/format-strings-pedantic.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wformat -Wformat-pedantic -isystem %S/Inputs %s + +int printf(const char *restrict, ...); + +typedef unsigned char uint8_t; + +void print_char_as_short() { + printf("%hu\n", (unsigned char)1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'unsigned char'}} + printf("%hu\n", (uint8_t)1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'uint8_t' (aka 'unsigned char')}} +} diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 45bf26053a..11acfcd1b9 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -277,8 +277,8 @@ typedef unsigned char uint8_t; void should_understand_small_integers() { printf("%hhu", (short) 10); // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}} - printf("%hu\n", (unsigned char) 1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'unsigned char'}} - printf("%hu\n", (uint8_t)1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'uint8_t'}} + printf("%hu\n", (unsigned char)1); // warning with -Wformat-pedantic only + printf("%hu\n", (uint8_t)1); // warning with -Wformat-pedantic only } void test11(void *p, char *s) { -- 2.40.0