]> granicus.if.org Git - clang/commitdiff
[Sema] Don't warn on printf('%hd', [char]) (PR41467)
authorNathan Huckleberry <nhuck@google.com>
Fri, 23 Aug 2019 18:01:57 +0000 (18:01 +0000)
committerNathan Huckleberry <nhuck@google.com>
Fri, 23 Aug 2019 18:01:57 +0000 (18:01 +0000)
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
lib/Sema/SemaChecking.cpp
test/FixIt/format.m
test/Sema/format-strings-enum-fixed-type.cpp
test/Sema/format-strings-pedantic.c [new file with mode: 0644]
test/Sema/format-strings.c

index 578d5bc567338927a637dd831ef9d0789ddca1d0..ff439f9921c9b5c8aff5ad3b5b4567d87f9a4611 100644 (file)
@@ -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:
index 07db04e4ffbf41df7ebc4de34dbbca27ff2a36ce..1b6390adc48d916745762e732561e0038ec9b991 100644 (file)
@@ -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<CharacterLiteral>(E)) {
index 40655a0e808ef337fe9998e06623c18868384ad6..ef27b1bac353fc0b34997326b3a772dd3d9ecb0f 100644 (file)
@@ -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"
index 0022ccbc66baa9058add983930acab9e1fbcd796..de22f093780d9de6e22a9f43af676528a25b2314 100644 (file)
@@ -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 (file)
index 0000000..8fb298a
--- /dev/null
@@ -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')}}
+}
index 45bf26053a94c28a8d47670f6ba040c5d0671d59..11acfcd1b9a62d8ba8a086951750c12d383d9563 100644 (file)
@@ -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) {