+2018-03-12 Martin Sebor <msebor@redhat.com>
+
+ 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.
+ (gimple_fold_builtin_strcpy): Handle no-warning.
+ (gimple_fold_builtin_stxcpy_chk): Same.
+ * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Handle no-warning.
+
2018-03-12 Segher Boessenkool <segher@kernel.crashing.org>
* config/rs6000/rs6000.c (abi_v4_pass_in_fpr): Add bool "named"
+2018-03-12 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/83456
+ * gcc/c-family/c-common.c (check_function_restrict): Return bool.
+ Restore checking of bounded built-in functions.
+ (check_function_arguments): Also return the result
+ of warn_for_restrict.
+ * gcc/c-family/c-common.c (check_function_restrict): Return bool.
+ * gcc/c-family/c-warn.c (warn_for_restrict): Return bool.
+
2018-03-02 Marek Polacek <polacek@redhat.com>
PR c++/84171
}
}
-/* Check that the same argument isn't passed to restrict arguments
- and other arguments. */
+/* Check that the same argument isn't passed to two or more
+ restrict-qualified formal and issue a -Wrestrict warning
+ if it is. Return true if a warning has been issued. */
-static void
+static bool
check_function_restrict (const_tree fndecl, const_tree fntype,
int nargs, tree *argarray)
{
if (fndecl
&& TREE_CODE (fndecl) == FUNCTION_DECL)
{
- /* Skip checking built-ins here. They are checked in more
- detail elsewhere. */
+ /* Avoid diagnosing calls built-ins with a zero size/bound
+ here. They are checked in more detail elsewhere. */
if (DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
- return;
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && nargs == 3
+ && TREE_CODE (argarray[2]) == INTEGER_CST
+ && integer_zerop (argarray[2]))
+ return false;
if (DECL_ARGUMENTS (fndecl))
parms = DECL_ARGUMENTS (fndecl);
for (i = 0; i < nargs; i++)
TREE_VISITED (argarray[i]) = 0;
+ bool warned = false;
+
for (i = 0; i < nargs && parms && parms != void_list_node; i++)
{
tree type;
if (POINTER_TYPE_P (type)
&& TYPE_RESTRICT (type)
&& !TYPE_READONLY (TREE_TYPE (type)))
- warn_for_restrict (i, argarray, nargs);
+ warned |= warn_for_restrict (i, argarray, nargs);
}
for (i = 0; i < nargs; i++)
TREE_VISITED (argarray[i]) = 0;
+
+ return warned;
}
/* Helper for check_function_nonnull; given a list of operands which
\f
/* Check for valid arguments being passed to a function with FNTYPE.
- There are NARGS arguments in the array ARGARRAY. LOC should be used for
- diagnostics. Return true if -Wnonnull warning has been diagnosed. */
+ There are NARGS arguments in the array ARGARRAY. LOC should be used
+ for diagnostics. Return true if either -Wnonnull or -Wrestrict has
+ been issued. */
+
bool
check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
int nargs, tree *argarray, vec<location_t> *arglocs)
check_function_sentinel (fntype, nargs, argarray);
if (warn_restrict)
- check_function_restrict (fndecl, fntype, nargs, argarray);
+ warned_p |= check_function_restrict (fndecl, fntype, nargs, argarray);
return warned_p;
}
extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
bool);
extern void warn_for_omitted_condop (location_t, tree);
-extern void warn_for_restrict (unsigned, tree *, unsigned);
+extern bool warn_for_restrict (unsigned, tree *, unsigned);
/* Places where an lvalue, or modifiable lvalue, may be required.
Used to select diagnostic messages in lvalue_error and
}
/* Warn if an argument at position param_pos is passed to a
- restrict-qualified param, and it aliases with another argument. */
+ restrict-qualified param, and it aliases with another argument.
+ Return true if a warning has been issued. */
-void
+bool
warn_for_restrict (unsigned param_pos, tree *argarray, unsigned nargs)
{
tree arg = argarray[param_pos];
if (TREE_VISITED (arg) || integer_zerop (arg))
- return;
+ return false;
location_t loc = EXPR_LOC_OR_LOC (arg, input_location);
gcc_rich_location richloc (loc);
tree current_arg = argarray[i];
if (operand_equal_p (arg, current_arg, 0))
{
- TREE_VISITED (current_arg) = 1;
+ TREE_VISITED (current_arg) = 1;
arg_positions.safe_push (i + 1);
}
}
if (arg_positions.is_empty ())
- return;
+ return false;
int pos;
FOR_EACH_VEC_ELT (arg_positions, i, pos)
richloc.add_range (EXPR_LOCATION (arg), false);
}
- warning_n (&richloc, OPT_Wrestrict, arg_positions.length (),
- "passing argument %i to restrict-qualified parameter"
- " aliases with argument %Z",
- "passing argument %i to restrict-qualified parameter"
- " aliases with arguments %Z",
- param_pos + 1, arg_positions.address (),
- arg_positions.length ());
+ return warning_n (&richloc, OPT_Wrestrict, arg_positions.length (),
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with argument %Z",
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with arguments %Z",
+ param_pos + 1, arg_positions.address (),
+ arg_positions.length ());
}
/* Callback function to determine whether an expression TP or one of its
tree destvar, srcvar;
location_t loc = gimple_location (stmt);
- tree func = gimple_call_fndecl (stmt);
bool nowarn = gimple_no_warning_p (stmt);
- bool check_overlap = (DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE
- && DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE_CHK
- && !nowarn);
/* If the LEN parameter is a constant zero or in range where
the only valid value is zero, return DEST. */
{
/* 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));
/* If SRC and DEST are the same (and not volatile), return DEST. */
if (operand_equal_p (src, dest, 0))
{
- tree func = gimple_call_fndecl (stmt);
+ if (!gimple_no_warning_p (stmt))
+ {
+ tree func = gimple_call_fndecl (stmt);
- warning_at (loc, OPT_Wrestrict,
- "%qD source argument is the same as destination",
- func);
+ warning_at (loc, OPT_Wrestrict,
+ "%qD source argument is the same as destination",
+ func);
+ }
replace_call_with_value (gsi, dest);
return true;
(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);
/* If SRC and DEST are the same (and not volatile), return DEST. */
if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
{
- tree func = gimple_call_fndecl (stmt);
+ if (!gimple_no_warning_p (stmt))
+ {
+ tree func = gimple_call_fndecl (stmt);
- warning_at (loc, OPT_Wrestrict,
- "%qD source argument is the same as destination",
- func);
+ warning_at (loc, OPT_Wrestrict,
+ "%qD source argument is the same as destination",
+ func);
+ }
replace_call_with_value (gsi, dest);
return true;
+2018-03-12 Martin Sebor <msebor@redhat.com>
+
+ 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.
+ * gcc.dg/Wrestrict-14.c: New test.
+Index: gcc/c-family/c-common.c
+===================================================================
+--- gcc/c-family/c-common.c (revision 258366)
++++ gcc/c-family/c-common.c (working copy)
+@@ -5309,10 +5309,11 @@ check_function_sentinel (const_tree fntype, int na
+ }
+ }
+
2018-03-12 H.J. Lu <hongjiu.lu@intel.com>
* g++.dg/pr84821.C: New test.
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);
}
} 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.
T (a, a + 3, 3);
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);
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" } */
{
size_t n = unsigned_value ();
+ /* Since no copying takes place no warning should be issued. */
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);
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" } */
}
/* The following overlaps except in the unlikely case that value ()
is zero, so it's diagnosed. */
- T ("012", a, a, n); /* { dg-warning "source argument is the same as destination " "strncpy" } */
+ T ("012", a, a, n); /* { dg-warning "\\\[-Wrestrict]" "strncpy" } */
}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* PR tree-optimization/83456 - -Wrestrict false positive on a non-overlapping
+ memcpy in an inline function
+ Verify that calls to built-in functions are diagnosed when the pointer
+ arguments to their restrict-qualified parameters are the same (the absence
+ of the false positives reported in PR 83456 is tested in Wrestrict-12.c.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -Wrestrict -Wno-stringop-truncation" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void* restrict, const void* restrict, size_t);
+extern void* mempcpy (void* restrict, const void* restrict, size_t);
+extern char* stpncpy (char* restrict, const char* restrict, size_t);
+extern char* stpcpy (char* restrict, const char* restrict);
+extern char* strncat (char* restrict, const char* restrict, size_t);
+extern char* strcat (char* restrict, const char* restrict);
+extern char* strncpy (char* restrict, const char* restrict, size_t);
+extern char* strcpy (char* restrict, const char* restrict);
+
+struct S
+{
+ char a[4];
+ char *p;
+} s;
+
+void sink (void*);
+
+void test_memcpy (char *p, struct S *q, size_t n)
+{
+ /* The behavior of memcpy() is undefined only when when copying takes
+ place between overlapping objects. Since a call with a size of zero
+ does nothing, it should not be diagnosed. */
+ memcpy (p, p, 0);
+ sink (p);
+
+ memcpy (p, p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ memcpy (p, p, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ memcpy (q->a, q->a, 0);
+ sink (q);
+
+ memcpy (q->p, q->p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ memcpy (&q->a[0], q->a, n); /* { dg-warning "\\\[-Wrestrict]" "bug ????" { xfail *-*-* } } */
+ sink (q);
+
+ memcpy (q, q->a, n); /* { dg-warning "\\\[-Wrestrict]" "bug ????" { xfail *-*-* } } */
+ sink (q);
+}
+
+void test_mempcpy (char *p, struct S *q, size_t n)
+{
+ mempcpy (p, p, 0);
+ sink (p);
+
+ mempcpy (p, p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ mempcpy (p, p, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ mempcpy (q->a, q->a, 0);
+ sink (q);
+
+ mempcpy (q->p, q->p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ mempcpy (&q->a[0], q->a, n); /* { dg-warning "\\\[-Wrestrict]" "bug ????" { xfail *-*-* } } */
+ sink (q);
+
+ mempcpy (q, q->a, n); /* { dg-warning "\\\[-Wrestrict]" "bug ????" { xfail *-*-* } } */
+ sink (q);
+}
+
+void test_strncat (char *p, struct S *q, size_t n)
+{
+ strncat (p, p, 0);
+ sink (p);
+
+ strncat (p, p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strncat (p, p, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strncat (q->a, q->a, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncat (&q->a[0], &q->a[0], n);/* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncat (q->a, &q->a[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncat (q->p, &q->p[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
+
+void test_strcat (char *p, struct S *q, size_t n)
+{
+ strcat (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcat (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcat (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcat (q->a, q->a); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcat (&q->a[0], &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcat (q->a, &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcat (q->p, &q->p[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
+
+void test_stpncpy (char *p, struct S *q, size_t n)
+{
+ stpncpy (p, p, 0); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpncpy (p, p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpncpy (p, p, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpncpy (q->a, q->a, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpncpy (&q->a[0], &q->a[0], n);/* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpncpy (q->a, &q->a[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpncpy (q->p, &q->p[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
+
+void test_stpcpy (char *p, struct S *q, size_t n)
+{
+ stpcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ stpcpy (q->a, q->a); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpcpy (&q->a[0], &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpcpy (q->a, &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ stpcpy (q->p, &q->p[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
+
+void test_strncpy (char *p, struct S *q, size_t n)
+{
+ strncpy (p, p, 0);
+ sink (p);
+
+ strncpy (p, p, 1); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strncpy (p, p, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strncpy (q->a, q->a, n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncpy (&q->a[0], &q->a[0], n);/* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncpy (q->a, &q->a[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strncpy (q->p, &q->p[0], n); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
+
+void test_strcpy (char *p, struct S *q, size_t n)
+{
+ strcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcpy (p, p); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (p);
+
+ strcpy (q->a, q->a); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcpy (&q->a[0], &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcpy (q->a, &q->a[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+
+ strcpy (q->p, &q->p[0]); /* { dg-warning "\\\[-Wrestrict]" } */
+ sink (q);
+}
maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
{
gimple *stmt = gsi_stmt (gsi);
+ if (gimple_no_warning_p (stmt))
+ return false;
wide_int cntrange[2];