]> granicus.if.org Git - clang/commitdiff
Format string checking: selectively ignore implicit casts to 'int'
authorTed Kremenek <kremenek@apple.com>
Mon, 1 Feb 2010 19:28:15 +0000 (19:28 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 1 Feb 2010 19:28:15 +0000 (19:28 +0000)
when checking if the format specifier matches the type of the data
argument and the length modifier indicates the data type is 'char' or
'short'.

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

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

index 4e2e9c7376b6830fcd96edad72116f1284d9c1a4..5db7038405c3f52a1d8629ffa4ec3269db9febe4 100644 (file)
@@ -1280,14 +1280,25 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
   // format specifier.
   const Expr *Ex = getDataArg(NumConversions);
   const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
-    
+  
   if (const QualType *T = ATR.getSpecificType()) {
     if (!MatchType(*T, Ex->getType(), true)) {
-      S.Diag(getLocationOfByte(CS.getStart()),
-             diag::warn_printf_conversion_argument_type_mismatch)
-        << *T << Ex->getType()
-        << getFormatSpecifierRange(startSpecifier, specifierLen)
-        << Ex->getSourceRange();
+      // Check if we didn't match because of an implicit cast from a 'char'
+      // or 'short' to an 'int'.  This is done because printf is a varargs
+      // function.
+      bool hasError = true;      
+      if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
+        if (ICE->getType() == S.Context.IntTy) {
+          Ex = ICE->getSubExpr();
+          hasError = !MatchType(*T, Ex->getType(), true);
+        }
+      
+      if (hasError)            
+        S.Diag(getLocationOfByte(CS.getStart()),
+               diag::warn_printf_conversion_argument_type_mismatch)
+          << *T << Ex->getType()
+          << getFormatSpecifierRange(startSpecifier, specifierLen)
+          << Ex->getSourceRange();
     }
     return true;
   }
index 02e39a426be23f26ff3b6f66dcc0fa1a6e8bc2c5..a055bfe1822ba7b3495af2ad3545a355b3b50f3a 100644 (file)
@@ -162,6 +162,11 @@ void test10(int x, float f, int i, long long lli) {
   printf("%.", x);  // expected-warning{{incomplete format specifier}}
   printf("%f", 4); // expected-warning{{conversion specifies type 'double' but the argument has type 'int'}}
   printf("%qd", lli);
+  printf("hhX %hhX", (unsigned char)10); // no-warning
+  printf("llX %llX", (long long) 10); // no-warning
+  // This is fine, because there is an implicit conversion to an int.
+  printf("%d", (unsigned char) 10); // no-warning
+  printf("%d", (long long) 10); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
 } 
 
 typedef struct __aslclient *aslclient;