From 31f8e32788adb299acad455363eb7fd244642c82 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 29 Jan 2010 23:32:22 +0000 Subject: [PATCH] Be a little more permissive than C99: allow 'unsigned' to be used for the field width and precision of a format specifier instead of just 'int'. This matches GCC, and fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94856 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaChecking.cpp | 8 ++++++-- test/Sema/format-strings.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 38f3f2df47..f10c8a17fc 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1151,10 +1151,14 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, } // Type check the data argument. It should be an 'int'. + // Although not in conformance with C99, we also allow the argument to be + // an 'unsigned int' as that is a reasonably safe case. GCC also + // doesn't emit a warning for that case. const Expr *Arg = getDataArg(NumConversions); QualType T = Arg->getType(); - const BuiltinType *BT = T->getAs(); - if (!BT || BT->getKind() != BuiltinType::Int) { + const BuiltinType *BT = T->getAs(); + if (!BT || (BT->getKind() != BuiltinType::Int && + BT->getKind() != BuiltinType::UInt)) { S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag) << T << getFormatSpecifierRange(startSpecifier, specifierLen) diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 166e8888e2..94fb593730 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -40,11 +40,15 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) { // rdar://6079877 printf("abc" - "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}} + "%*d", 1, 1); // no-warning printf("abc\ def" - "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}} - + "%*d", 1, 1); // no-warning + + // , allow 'unsigned' (instead of 'int') to be used for both + // the field width and precision. This deviates from C99, but is reasonably safe + // and is also accepted by GCC. + printf("%*d", (unsigned) 1, 1); // no-warning } void check_conditional_literal(const char* s, int i) { @@ -137,6 +141,7 @@ void test9(char *P) { void torture(va_list v8) { vprintf ("%*.*d", v8); // no-warning + } void test10(int x, float f, int i) { -- 2.40.0