summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaChecking.cpp23
-rw-r--r--clang/test/Sema/format-strings.c5
2 files changed, 22 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4e2e9c7376b..5db7038405c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/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<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;
}
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index 02e39a426be..a055bfe1822 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/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;
OpenPOWER on IntegriCloud