From: Ted Kremenek Date: Mon, 1 Feb 2010 19:28:15 +0000 (+0000) Subject: Format string checking: selectively ignore implicit casts to 'int' X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=180f2840d1d8bcb2139bfb53e2d88eda280e939e;p=clang Format string checking: selectively ignore implicit casts to 'int' 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 --- diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4e2e9c7376..5db7038405 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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(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; } diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 02e39a426b..a055bfe182 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -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;