I have become convinced that issuing -Wrestrict in gimple-fold for calls to memcpy() where the source pointer is the same as the destination causes more trouble than it's worth, especially when inlining is involved, as in:
inline void bar (void *d, void *s, unsigned N) { if (s != d) memcpy (d, s, N); } void foo (void* src) { bar (src, src, 1); } It seems that there should be a way to teach GCC to avoid folding statements in dead blocks (e.g., in a block controlled by 'if (0 != 0)' as the one below), and that it might even speed up compilation, but in the meantime it leads to false positive -Wrestrict warnings. The attached patch removes this instance of the warning and adjusts tests not to expect it. Martin
PR tree-optimization/83456 - -Wrestrict false positive on a non-overlapping memcpy in an inline function gcc/ChangeLog: PR tree-optimization/83456 * gimple-fold.c (gimple_fold_builtin_memory_op): Avoid warning for perfectly overlapping calls to memcpy. (gimple_fold_builtin_memory_chk): Same. gcc/testsuite/ChangeLog: PR tree-optimization/83456 * c-c++-common/Wrestrict-2.c: Remove test cases. * c-c++-common/Wrestrict.c: Same. * gcc.dg/Wrestrict-12.c: New test. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 258339) +++ gcc/gimple-fold.c (working copy) @@ -713,13 +713,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterato { /* Avoid diagnosing exact overlap in calls to __builtin_memcpy. It's safe and may even be emitted by GCC itself (see bug - 32667). However, diagnose it in explicit calls to the memcpy - function. */ - if (check_overlap && *IDENTIFIER_POINTER (DECL_NAME (func)) != '_') - warning_at (loc, OPT_Wrestrict, - "%qD source argument is the same as destination", - func); - + 32667). */ unlink_stmt_vdef (stmt); if (gimple_vdef (stmt) && TREE_CODE (gimple_vdef (stmt)) == SSA_NAME) release_ssa_name (gimple_vdef (stmt)); @@ -2499,15 +2493,6 @@ gimple_fold_builtin_memory_chk (gimple_stmt_iterat (resp. DEST+LEN for __mempcpy_chk). */ if (fcode != BUILT_IN_MEMSET_CHK && operand_equal_p (src, dest, 0)) { - if (fcode != BUILT_IN_MEMMOVE && fcode != BUILT_IN_MEMMOVE_CHK) - { - tree func = gimple_call_fndecl (stmt); - - warning_at (loc, OPT_Wrestrict, - "%qD source argument is the same as destination", - func); - } - if (fcode != BUILT_IN_MEMPCPY_CHK) { replace_call_with_value (gsi, dest); Index: gcc/testsuite/c-c++-common/Wrestrict-2.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict-2.c (revision 258339) +++ gcc/testsuite/c-c++-common/Wrestrict-2.c (working copy) @@ -12,13 +12,13 @@ static void wrap_memcpy (void *d, const void *s, size_t n) { - memcpy (d, s, n); /* { dg-warning "source argument is the same as destination" "memcpy" } */ + memcpy (d, s, n); /* { dg-warning "accessing 2 bytes at offsets 0 and 1 overlaps 1 byte at offset 1" "memcpy" } */ } -void call_memcpy (void *d, size_t n) +void call_memcpy (char *d) { - const void *s = d; - wrap_memcpy (d, s, n); + const void *s = d + 1; + wrap_memcpy (d, s, 2); } Index: gcc/testsuite/c-c++-common/Wrestrict.c =================================================================== --- gcc/testsuite/c-c++-common/Wrestrict.c (revision 258339) +++ gcc/testsuite/c-c++-common/Wrestrict.c (working copy) @@ -52,7 +52,6 @@ void test_memcpy_cst (void *d, const void *s) } while (0) T (a, a, 0); - T (a, s = a, 3); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ /* This isn't detected because memcpy calls with small power-of-2 sizes are intentionally folded into safe copies equivalent to memmove. @@ -64,19 +63,6 @@ void test_memcpy_cst (void *d, const void *s) T (a, a + 3, 5); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ { - char a[3] = { 1, 2, 3 }; - - /* Verify that a call to memcpy with an exact overlap is diagnosed - (also tested above) but an excplicit one to __builtin_memcpy is - not. See bug 32667 for the rationale. */ - (memcpy)(a, a, sizeof a); /* { dg-warning "source argument is the same as destination" "memcpy" } */ - sink (a); - - __builtin_memcpy (a, a, sizeof a); - sink (a); - } - - { char a[3][7]; sink (a); @@ -116,11 +102,6 @@ void test_memcpy_cst (void *d, const void *s) memcpy (d, s, sizeof x.a); sink (&x); - d = x.a; - s = x.a; - memcpy (d, s, sizeof x.a); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ - sink (&x); - d = x.a + 4; s = x.b; memcpy (d, s, sizeof x.a); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ @@ -450,19 +431,6 @@ void test_memcpy_var (char *d, const char *s) memcpy (d, d, 0); sink (d); - memcpy (d, d, n); /* { dg-warning "source argument is the same as destination" "memcpy" } */ - sink (d); - - memcpy (d, &d[0], n); /* { dg-warning "source argument is the same as destination" "memcpy" } */ - sink (d); - - memcpy (&d[0], d, n); /* { dg-warning "source argument is the same as destination" "memcpy" } */ - sink (d); - - s = d; - memcpy (d, s, n); /* { dg-warning "source argument is the same as destination" "memcpy" } */ - sink (d); - /* The following overlaps if n is greater than 1. */ s = d + 1; memcpy (d, s, n); @@ -499,10 +467,6 @@ void test_memcpy_var (char *d, const char *s) s = d + 5; n = 7; memcpy (d, s, n); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ - - n = UR (0, 1); - s = d; - memcpy (d, s, n); /* { dg-warning "\\\[-Wrestrict" "memcpy" } */ } Index: gcc/testsuite/gcc.dg/Wrestrict-12.c =================================================================== --- gcc/testsuite/gcc.dg/Wrestrict-12.c (nonexistent) +++ gcc/testsuite/gcc.dg/Wrestrict-12.c (working copy) @@ -0,0 +1,66 @@ +/* PR tree-optimization/83456 - -Wrestrict false positive on + a non-overlapping memcpy in an inline function + { dg-do compile } + { dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */ + +extern void* memcpy (void*, const void*, __SIZE_TYPE__); + +/* Test case from comment #0. */ + +inline void pr83456_comment0 (void *d, void *s, unsigned N) +{ + if (s != d) + memcpy (d, s, N); +} + +void call_pr83456_comment0 (void* src) +{ + pr83456_comment0 (src, src, 1); +} + + +/* Test case from comment #1. */ + +char a[4]; + +void pr83456_comment1 (unsigned n) +{ + for (int i = 0; i < 1; i++) + { + if (!i) + continue; + + memcpy (a, a, n); + } +} + +/* Test case from comment #2. */ + +struct netdevice { + void *priv; +}; + +struct ip_tunnel { + struct netdevice *dev; + int ip6rd[3]; +}; + +struct sit_net { + struct netdevice *fb_tunnel_dev; +}; + +void ipip6_tunnel_clone_6rd (struct netdevice *dev, struct sit_net *sitn) +{ + struct ip_tunnel *t = dev->priv; + if (t->dev == sitn->fb_tunnel_dev) + return; + + struct ip_tunnel *t0 = sitn->fb_tunnel_dev->priv; + memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd)); +} + +void sit_init_net (struct sit_net *sitn, struct netdevice *fb_tunnel_dev) +{ + sitn->fb_tunnel_dev = fb_tunnel_dev; + ipip6_tunnel_clone_6rd (sitn->fb_tunnel_dev, sitn); +}