The early front-end only implementation of -Wrestrict that's still present in GCC 10 issues a false postive for %p arguments that are the same as the destination. Bug 84919 reports an instance of this false positive in the Linux kernel.
That attached patch suppresses the front-end warning for the sprintf family of functions, letting the sprintf pass that was in GCC 10 extended to also handle -Wrestrict for these functions, handle them instead. Tested on x86_64-linux. Since this is a regression I'd like to commit the fix to GCC 10. Martin
PR c/84919 - bogus -Wrestrict on sprintf %p with destination as argument gcc/c-family/ChangeLog: PR c/84919 * c-common.c (check_function_arguments): Avoid overlap checking of sprintf functions. gcc/testsuite/ChangeLog: PR c/84919 * gcc.dg/Wrestrict-20.c: New test. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 4a7f3a52335..4bb21772c64 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5732,8 +5732,26 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, if (warn_format) check_function_sentinel (fntype, nargs, argarray); - if (warn_restrict) - warned_p |= check_function_restrict (fndecl, fntype, nargs, argarray); + if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_SPRINTF: + case BUILT_IN_SPRINTF_CHK: + case BUILT_IN_SNPRINTF: + case BUILT_IN_SNPRINTF_CHK: + /* Let the sprintf pass handle these. */ + return warned_p; + + default: + break; + } + } + + /* check_function_restrict sets the DECL_READ_P for arguments + so it must be called unconditionally. */ + warned_p |= check_function_restrict (fndecl, fntype, nargs, argarray); + return warned_p; } diff --git a/gcc/testsuite/gcc.dg/Wrestrict-20.c b/gcc/testsuite/gcc.dg/Wrestrict-20.c new file mode 100644 index 00000000000..9826e7f4503 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-20.c @@ -0,0 +1,41 @@ +/* PR c/84919 - bogus -Wrestrict on sprintf %p with destination as argument + { dg-do compile } + -O2 isn't strictly necessary but setting also verifies that the sprintf/ + strlen pass doesn't warn with non-constant arguments. + { dg-options "-O2 -Wall" } */ + +extern int sprintf (char* restrict, const char* restrict, ...); +extern int snprintf (char* restrict, __SIZE_TYPE__, const char* restrict, ...); + +char a[32]; + +void test_warn (char *p) +{ + a[0] = 0; + sprintf (a, "a=%s", a); /* { dg-warning "-Wrestrict" } */ + + p = a; + char *q = p + 1; + sprintf (p, "a=%s", q); /* { dg-warning "-Wrestrict" } */ +} + +void test_nowarn_front_end (char *d) +{ + sprintf (d, "%p", d); + snprintf (d, 32, "%p", d); + + sprintf (a, "p=%p", a); + snprintf (a, sizeof a, "%p", a); +} + +void test_nowarn_sprintf_pass (char *d) +{ + char *q = d; + + sprintf (d, "p=%p", q); + snprintf (d, 32, "p=%p", q); + + q = a; + sprintf (a, "a=%p", q); + snprintf (a, sizeof a, "a=%p", q); +}