nickdesaulniers created this revision. nickdesaulniers added a reviewer: aaron.ballman. Herald added a subscriber: emaste. Herald added a project: All. nickdesaulniers requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Similar to commit cc01d6421f4a ("[Sema] Don't warn on printf('%hd', [char]) (PR41467)") warning on %hhd -> int or %hd -> int is a major source of pain wrt. compatibility with GCC; it's making enabling -Wformat for the Linux kernel excessively painful. Fixes: #57102 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D132266 Files: clang/lib/Sema/SemaChecking.cpp clang/test/FixIt/format.m clang/test/Sema/format-strings-freebsd.c clang/test/Sema/format-strings-pedantic.c clang/test/Sema/format-strings.c Index: clang/test/Sema/format-strings.c =================================================================== --- clang/test/Sema/format-strings.c +++ 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 +} Index: clang/test/Sema/format-strings-pedantic.c =================================================================== --- clang/test/Sema/format-strings-pedantic.c +++ 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'}} +} Index: clang/test/Sema/format-strings-freebsd.c =================================================================== --- clang/test/Sema/format-strings-freebsd.c +++ 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))); Index: clang/test/FixIt/format.m =================================================================== --- clang/test/FixIt/format.m +++ 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 *, ...); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ 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.
Index: clang/test/Sema/format-strings.c =================================================================== --- clang/test/Sema/format-strings.c +++ 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 +} Index: clang/test/Sema/format-strings-pedantic.c =================================================================== --- clang/test/Sema/format-strings-pedantic.c +++ 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'}} +} Index: clang/test/Sema/format-strings-freebsd.c =================================================================== --- clang/test/Sema/format-strings-freebsd.c +++ 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))); Index: clang/test/FixIt/format.m =================================================================== --- clang/test/FixIt/format.m +++ 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 *, ...); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ 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.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits