]> granicus.if.org Git - clang/commitdiff
Previously, the printf warnings would say your arguments type was 'int' when it was...
authorTed Kremenek <kremenek@apple.com>
Thu, 21 Oct 2010 04:00:58 +0000 (04:00 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 21 Oct 2010 04:00:58 +0000 (04:00 +0000)
or a 'short'. This fixes that and allows the hints to suggest 'h' modifiers for small ints.

Patch by Justin Bogner!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116996 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/PrintfFormatString.cpp
lib/Sema/SemaChecking.cpp
test/Sema/format-strings.c

index b8c327cdeba6eb6a1e891581d81f54be99f4b7be..57399d8efefbbe3b06253f8b3e2c59c0b3ebd0a7 100644 (file)
@@ -382,6 +382,18 @@ bool PrintfSpecifier::fixType(QualType QT) {
     LM.setKind(LengthModifier::None);
     break;
 
+  case BuiltinType::Char_U:
+  case BuiltinType::UChar:
+  case BuiltinType::Char_S:
+  case BuiltinType::SChar:
+    LM.setKind(LengthModifier::AsChar);
+    break;
+
+  case BuiltinType::Short:
+  case BuiltinType::UShort:
+    LM.setKind(LengthModifier::AsShort);
+    break;
+
   case BuiltinType::WChar:
   case BuiltinType::Long:
   case BuiltinType::ULong:
@@ -399,8 +411,10 @@ bool PrintfSpecifier::fixType(QualType QT) {
   }
 
   // Set conversion specifier and disable any flags which do not apply to it.
-  if (QT->isAnyCharacterType()) {
+  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
+  if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
     CS.setKind(ConversionSpecifier::cArg);
+    LM.setKind(LengthModifier::None);
     Precision.setHowSpecified(OptionalAmount::NotSpecified);
     HasAlternativeForm = 0;
     HasLeadingZeroes = 0;
index 1a07a86f80cfcacbe7eeaeb3b9553de6be0e0803..fccbe92d6f926ff1baf93a9d8e805b7ec0e161f7 100644 (file)
@@ -1603,9 +1603,12 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
     // or 'short' to an 'int'.  This is done because printf is a varargs
     // function.
     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
-      if (ICE->getType() == S.Context.IntTy)
-        if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType()))
+      if (ICE->getType() == S.Context.IntTy) {
+        // All further checking is done on the subexpression.
+        Ex = ICE->getSubExpr();
+        if (ATR.matchesType(S.Context, Ex->getType()))
           return true;
+      }
 
     // We may be able to offer a FixItHint if it is a supported type.
     PrintfSpecifier fixedFS = FS;
index 1bfab255313239178f4f9d3ae21c2094d77ec19e..57f087b2e0c8cf74c3e8f2e0c5d68c515d958d67 100644 (file)
@@ -174,7 +174,15 @@ void test10(int x, float f, int i, long long lli) {
   printf("%.0Lf", (long double) 1.0); // no-warning
   printf("%c\n", "x"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
   printf("%c\n", 1.23); // expected-warning{{conversion specifies type 'int' but the argument has type 'double'}}
-} 
+}
+
+typedef unsigned char uint8_t;
+
+void should_understand_small_integers() {
+  printf("%hhu", (short) 10); // expected-warning{{conversion specifies type 'unsigned char' but the argument has type 'short'}}
+  printf("%hu\n", (unsigned char) 1); // expected-warning{{conversion specifies type 'unsigned short' but the argument has type 'unsigned char'}}
+  printf("%hu\n", (uint8_t)1); // expected-warning{{conversion specifies type 'unsigned short' but the argument has type 'uint8_t'}}
+}
 
 void test11(void *p, char *s) {
   printf("%p", p); // no-warning