diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -10129,6 +10129,12 @@ IsEnum = true; } + // Consider %hh or %h length modifiers for ints/unsigned ints -Wpedantic. + LengthModifier::Kind LMK = FS.getLengthModifier().getKind(); + if ((LMK == LengthModifier::AsChar || LMK == LengthModifier::AsShort) && + (ExprTy == S.Context.IntTy || ExprTy == S.Context.UnsignedIntTy)) + Match = ArgType::NoMatchPedantic; + // %C in an Objective-C context prints a unichar, not a wchar_t. // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. diff --git a/clang/test/FixIt/format.m b/clang/test/FixIt/format.m --- a/clang/test/FixIt/format.m +++ b/clang/test/FixIt/format.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -fblocks -verify %s -// RUN: %clang_cc1 -triple %itanium_abi_triple -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -fblocks -verify %s -Wformat-pedantic +// RUN: %clang_cc1 -triple %itanium_abi_triple -fdiagnostics-parseable-fixits -fblocks %s 2>&1 -Wformat-pedantic | FileCheck %s @class NSString; extern void NSLog(NSString *, ...); diff --git a/clang/test/Sema/format-strings-freebsd.c b/clang/test/Sema/format-strings-freebsd.c --- a/clang/test/Sema/format-strings-freebsd.c +++ b/clang/test/Sema/format-strings-freebsd.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-unknown-freebsd %s -// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd %s -// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-scei-ps4 %s -// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-sie-ps5 %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-unknown-freebsd %s -Wformat-pedantic +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd %s -Wformat-pedantic +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-scei-ps4 %s -Wformat-pedantic +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-sie-ps5 %s -Wformat-pedantic // Test FreeBSD kernel printf extensions. int freebsd_kernel_printf(const char *, ...) __attribute__((__format__(__freebsd_kprintf__, 1, 2))); diff --git a/clang/test/Sema/format-strings-pedantic.c b/clang/test/Sema/format-strings-pedantic.c --- a/clang/test/Sema/format-strings-pedantic.c +++ b/clang/test/Sema/format-strings-pedantic.c @@ -18,3 +18,16 @@ printf("%p", nullptr); // expected-warning {{format specifies type 'void *' but the argument has type 'std::nullptr_t'}} #endif } + +void test_intentional_truncation(void) { + int x = 42; + printf("%hhd", x); // expected-warning {{format specifies type 'char' but the argument has type 'int'}} + printf("%hhu", x); // expected-warning {{format specifies type 'unsigned char' but the argument has type 'int'}} + printf("%hd", x); // expected-warning {{format specifies type 'short' but the argument has type 'int'}} + printf("%hu", x); // expected-warning {{format specifies type 'unsigned short' but the argument has type 'int'}} + unsigned y = 42; + printf("%hhd", y); // expected-warning {{format specifies type 'char' but the argument has type 'unsigned int'}} + printf("%hhu", y); // expected-warning {{format specifies type 'unsigned char' but the argument has type 'unsigned int'}} + printf("%hd", y); // expected-warning {{format specifies type 'short' but the argument has type 'unsigned int'}} + printf("%hu", y); // expected-warning {{format specifies type 'unsigned short' but the argument has type 'unsigned int'}} +} diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -830,3 +830,18 @@ printf_arg2("foo", "%s string %i\n", "aaa", 123); printf_arg2("%s string\n", "foo", "bar"); // expected-warning{{data argument not used by format string}} } + +// These are handled by -Wformat-pedantic. See also +// clang/test/Sema/format-strings-pedantic.c. +void test_intentional_truncation(void) { + int x = 42; + printf("%hhd", x); // no-warning + printf("%hhu", x); // no-warning + printf("%hd", x); // no-warning + printf("%hu", x); // no-warning + unsigned y = 42; + printf("%hhd", y); // no-warning + printf("%hhu", y); // no-warning + printf("%hd", y); // no-warning + printf("%hu", y); // no-warning +}