This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/39480
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 13 Apr 2009 16:52:28 -0400
- Subject: C++ PATCH for c++/39480
It's pedantically invalid to call memcpy to copy an object to itself,
and apparently it even breaks on some targets. So avoid doing this.
The best solution is for me to fix 22488 so we can go back to using a
MODIFY_EXPR for copying the base subobject...
Tested x86_64-pc-linux-gnu, applying to trunk, 4.4 and 4.3.
2009-04-09 Jason Merrill <jason@redhat.com>
PR c++/39480
* call.c (build_over_call): Don't call memcpy if the target is
the same as the source.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 869146e..ef7c045 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5396,14 +5396,28 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
instead of an explicit call to memcpy. */
tree arg0, arg1, arg2, t;
+ tree test = NULL_TREE;
arg2 = TYPE_SIZE_UNIT (as_base);
arg1 = arg;
arg0 = cp_build_unary_op (ADDR_EXPR, to, 0, complain);
+
+ if (!(optimize && flag_tree_ter))
+ {
+ /* When TER is off get_pointer_alignment returns 0, so a call
+ to __builtin_memcpy is expanded as a call to memcpy, which
+ is invalid with identical args. When TER is on it is
+ expanded as a block move, which should be safe. */
+ arg0 = save_expr (arg0);
+ arg1 = save_expr (arg1);
+ test = build2 (EQ_EXPR, boolean_type_node, arg0, arg1);
+ }
t = implicit_built_in_decls[BUILT_IN_MEMCPY];
t = build_call_n (t, 3, arg0, arg1, arg2);
t = convert (TREE_TYPE (arg0), t);
+ if (test)
+ t = build3 (COND_EXPR, TREE_TYPE (t), test, arg0, t);
val = cp_build_indirect_ref (t, 0, complain);
}
diff --git a/gcc/testsuite/g++.dg/init/copy7.C b/gcc/testsuite/g++.dg/init/copy7.C
new file mode 100644
index 0000000..f4364f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/copy7.C
@@ -0,0 +1,32 @@
+// PR c++/39480
+// It isn't always safe to call memcpy with identical arguments.
+// { dg-do run }
+
+extern "C" void abort();
+extern "C" void *
+memcpy(void *dest, void *src, __SIZE_TYPE__ n)
+{
+ abort();
+}
+
+struct A
+{
+ double d[10];
+};
+
+struct B: public A
+{
+ char bc;
+};
+
+B b;
+
+void f(B *a1, B* a2)
+{
+ *a1 = *a2;
+}
+
+int main()
+{
+ f(&b,&b);
+}