A while back I added unsafe_copy_elision_p to catch cases where we
don't want to initialize a base subobject directly from a call because
it might clobber data packed into the tail padding of the base.  Later
I extended that function to look into COMPOUND_EXPR.  This patch
further adjusts it to look into COND_EXPR.

Tested x86_64-pc-linux-gnu, applying to trunk/7/6.
commit 145aa5adf95adfa581f663e9a799f5fe0c6418cb
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Feb 26 18:23:30 2018 -0500

            PR c++/84441 - ICE with base initialized from ?:
    
            * call.c (unsafe_copy_elision_p): Handle COND_EXPR.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c47befdbf7f..11fe28292fb 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7580,6 +7580,15 @@ unsafe_copy_elision_p (tree target, tree exp)
   /* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR.  */
   while (TREE_CODE (init) == COMPOUND_EXPR)
     init = TREE_OPERAND (init, 1);
+  if (TREE_CODE (init) == COND_EXPR)
+    {
+      /* We'll end up copying from each of the arms of the COND_EXPR directly
+        into the target, so look at them. */
+      if (tree op = TREE_OPERAND (init, 1))
+       if (unsafe_copy_elision_p (target, op))
+         return true;
+      return unsafe_copy_elision_p (target, TREE_OPERAND (init, 2));
+    }
   return (TREE_CODE (init) == AGGR_INIT_EXPR
          && !AGGR_INIT_VIA_CTOR_P (init));
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/elision3.C 
b/gcc/testsuite/g++.dg/cpp0x/elision3.C
new file mode 100644
index 00000000000..7c5c8b9f0b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/elision3.C
@@ -0,0 +1,21 @@
+// PR c++/84441
+// { dg-do compile { target c++11 } }
+
+struct B {
+  int *b;
+};
+struct A {
+  B b;
+  A (A &&);
+};
+struct C {
+  A c;
+  int d;
+};
+C bar ();
+struct D : C {
+  D ()
+    : C (0 ? bar () : bar ())
+  {}
+};
+D d;

Reply via email to