[clang] [llvm] [Sema] Implement support for -Wformat-signedness (PR #74440)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 26 06:02:52 PDT 2024
================
@@ -0,0 +1,223 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -verify -Wformat -Wformat-signedness %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -std=c11 -fsyntax-only -verify -Wformat -Wformat-signedness %s
+
+// Verify that -Wformat-signedness alone (without -Wformat) trigger the
+// warnings. Note in gcc this will not trigger the signedness warnings as
+// -Wformat is default off in gcc.
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -verify -Wformat-signedness %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -std=c11 -fsyntax-only -verify -Wformat-signedness %s
+
+// Verify that -Wformat-signedness warnings are not reported with only -Wformat
+// (gcc compat).
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wformat -Werror %s
+
+// Verify that -Wformat-signedness with -Wno-format are not reported (gcc compat).
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wformat-signedness -Wno-format -Werror %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wno-format -Wformat-signedness -Werror %s
+
+#include <limits.h>
+
+int printf(const char *restrict format, ...);
+int scanf(const char * restrict, ...);
+
+void test_printf_bool(_Bool x)
+{
+ printf("%d", x); // no-warning
+ printf("%u", x); // no-warning
+ printf("%x", x); // no-warning
+}
+
+void test_printf_char(char x)
+{
+ printf("%c", x); // no-warning
+}
+
+void test_printf_unsigned_char(unsigned char x)
+{
+ printf("%c", x); // no-warning
+}
+
+void test_printf_int(int x)
+{
+ printf("%d", x); // no-warning
+ printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}}
+ printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}}
+}
+
+void test_printf_unsigned(unsigned x)
+{
+ printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned int'}}
+ printf("%u", x); // no-warning
+ printf("%x", x); // no-warning
+}
+
+void test_printf_long(long x)
+{
+ printf("%ld", x); // no-warning
+ printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}}
+ printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}}
+}
+
+void test_printf_unsigned_long(unsigned long x)
+{
+ printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has type 'unsigned long'}}
+ printf("%lu", x); // no-warning
+ printf("%lx", x); // no-warning
+}
+
+void test_printf_long_long(long long x)
+{
+ printf("%lld", x); // no-warning
+ printf("%llu", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}}
+ printf("%llx", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}}
+}
+
+void test_printf_unsigned_long_long(unsigned long long x)
+{
+ printf("%lld", x); // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned long long'}}
+ printf("%llu", x); // no-warning
+ printf("%llx", x); // no-warning
+}
+
+enum enum_int {
+ minus_1 = -1
+};
+
+void test_printf_enum_int(enum enum_int x)
+{
+ printf("%d", x); // no-warning
+ printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}}
+ printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}}
+}
+
+#ifndef _WIN32 // Disabled due to enums have different underlying type on _WIN32
+enum enum_unsigned {
+ zero = 0
+};
+
+void test_printf_enum_unsigned(enum enum_unsigned x)
+{
+ printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has underlying type 'unsigned int'}}
+ printf("%u", x); // no-warning
+ printf("%x", x); // no-warning
+}
+
+enum enum_long {
+ minus_one = -1,
+ int_val = INT_MAX,
+ unsigned_val = (unsigned)INT_MIN
+};
+
+void test_printf_enum_long(enum enum_long x)
+{
+ printf("%ld", x); // no-warning
+ printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}}
+ printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}}
+}
+
+enum enum_unsigned_long {
+ uint_max_plus = (unsigned long)UINT_MAX+1,
----------------
AaronBallman wrote:
```suggestion
uint_max_plus = (unsigned long)((__INT_MAX__ *2U +1U)+1),
```
https://github.com/llvm/llvm-project/pull/74440
More information about the cfe-commits
mailing list