My patch for the new inheriting constructor semantics changed
tree-inline.c to avoid copying non-taken branches, in order to avoid
trying to refer to parameters that are omitted from base constructor
clones; this overlooked that we might enter such branches via goto.
This patch reverts that change, and addresses the omitted parameter
issue in the front end by providing a suitable replacement.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit e4a9364d66494c3cfd6cf528d8176a02b24b9d00
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Feb 3 15:30:24 2017 -0500

            PR c++/78689 - ICE on constructor with label
    
    gcc/
            * tree-inline.c (copy_tree_body_r) [COND_EXPR]: Revert change to
            avoid copying non-taken branch.
    gcc/cp/
            * optimize.c (maybe_clone_body): Replace omitted parameters with
            null lvalues.
            * class.c (build_clone): Fix logic for omitting inherited parms.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index d99ebcd..7ec07c9 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4818,7 +4818,7 @@ build_clone (tree fn, tree name)
 
   /* A base constructor inheriting from a virtual base doesn't get the
      arguments.  */
-  if (ctor_omit_inherited_parms (fn))
+  if (ctor_omit_inherited_parms (clone))
     DECL_CHAIN (DECL_CHAIN (DECL_ARGUMENTS (clone))) = NULL_TREE;
 
   for (parms = DECL_ARGUMENTS (clone); parms; parms = DECL_CHAIN (parms))
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index f61d035..933612c 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -621,9 +621,21 @@ maybe_clone_body (tree fn)
                  function.  */
               else
                 {
-                  decl_map->put (parm, clone_parm);
+                 tree replacement;
                  if (clone_parm)
-                   clone_parm = DECL_CHAIN (clone_parm);
+                   {
+                     replacement = clone_parm;
+                     clone_parm = DECL_CHAIN (clone_parm);
+                   }
+                 else
+                   {
+                     /* Inheriting ctors can omit parameters from the base
+                        clone.  Replace them with null lvalues.  */
+                     tree reftype = build_reference_type (TREE_TYPE (parm));
+                     replacement = fold_convert (reftype, null_pointer_node);
+                     replacement = convert_from_reference (replacement);
+                   }
+                  decl_map->put (parm, replacement);
                 }
             }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C 
b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
index 0c862f7..c0cf040 100644
--- a/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
@@ -14,6 +14,9 @@ Z z(0); // OK: initialization of Y does not invoke default 
constructor of X
 // { dg-final { scan-assembler "_ZN1YCI21WEi" } }
 // { dg-final { scan-tree-dump "Y::Y ._2, _3.;" "gimple" } }
 
+// And that we aren't expecting the int, either.
+// { dg-final { scan-tree-dump-not "Y::Y.int\[^\n\]*int" "gimple" } }
+
 // And that we *are* passing the int along to V::V.
 // { dg-final { scan-assembler "_ZN1VCI21WEi" } }
 // { dg-final { scan-tree-dump "V::V .this, _1.;" "gimple" } }
diff --git a/gcc/testsuite/g++.dg/init/ctor12.C 
b/gcc/testsuite/g++.dg/init/ctor12.C
new file mode 100644
index 0000000..7c1aab72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/ctor12.C
@@ -0,0 +1,14 @@
+// PR c++/78689 - ICE on constructor with label
+
+struct e {
+  e() {
+    goto aj;
+    if (0)
+    aj:;
+  }
+};
+
+void f()
+{
+  struct e x;
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index d63c70f..138b992 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1045,7 +1045,6 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void 
*data)
   copy_body_data *id = (copy_body_data *) data;
   tree fn = id->src_fn;
   tree new_block;
-  bool copied = false;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
      inlining context.  Our output for these trees is completely
@@ -1242,40 +1241,10 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void 
*data)
          *walk_subtrees = 0;
          return NULL;
        }
-      else if (TREE_CODE (*tp) == COND_EXPR)
-       {
-         tree cond = TREE_OPERAND (*tp, 0);
-         walk_tree (&cond, copy_tree_body_r, data, NULL);
-         tree folded = fold (cond);
-         if (TREE_CODE (folded) == INTEGER_CST)
-           {
-             /* Only copy the taken branch; for a C++ base constructor clone
-                inherited from a virtual base, copying the other branch leads
-                to references to parameters that were optimized away.  */
-             tree branch = (integer_nonzerop (folded)
-                            ? TREE_OPERAND (*tp, 1)
-                            : TREE_OPERAND (*tp, 2));
-             tree type = TREE_TYPE (*tp);
-             if (VOID_TYPE_P (type)
-                 || type == TREE_TYPE (branch))
-               {
-                 *tp = branch;
-                 return copy_tree_body_r (tp, walk_subtrees, data);
-               }
-           }
-         /* Avoid copying the condition twice.  */
-         copy_tree_r (tp, walk_subtrees, NULL);
-         TREE_OPERAND (*tp, 0) = cond;
-         walk_tree (&TREE_OPERAND (*tp, 1), copy_tree_body_r, data, NULL);
-         walk_tree (&TREE_OPERAND (*tp, 2), copy_tree_body_r, data, NULL);
-         *walk_subtrees = 0;
-         copied = true;
-       }
 
       /* Here is the "usual case".  Copy this tree node, and then
         tweak some special cases.  */
-      if (!copied)
-       copy_tree_r (tp, walk_subtrees, NULL);
+      copy_tree_r (tp, walk_subtrees, NULL);
 
       /* If EXPR has block defined, map it to newly constructed block.
          When inlining we want EXPRs without block appear in the block

Reply via email to