There were two problems with this testcase:

1) In a template non-dependent context, we try to do full semantic
processing and then roll back and build an expression with the
original operands and the computed type.  This was failing with a
CONSTRUCTOR operand, since digest_init changes the contents of an
input CONSTRUCTOR rather than return a new one, so the original
new-initializer got clobbered.  Fixed by copying CONSTRUCTORs as well
as the init vector itself.

2) We weren't replacing PLACEHOLDER_EXPR in a new-initializer.  And
properly doing that replacement prevents us from doing the
optimization of evaluating the initializer before allocating the
object, since the initializer needs to refer to the object.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit f7187e708e1ccf76cbc49df60584b81e07c5f863
Author: Jason Merrill <ja...@redhat.com>
Date:   Sat Feb 11 07:45:05 2017 -0500

            PR c++/77659 - ICE with new and C++14 aggregate NSDMI
    
            * init.c (build_new): Make backups of any CONSTRUCTORs in init.
            (build_new_1): Use replace_placeholders.
            * tree.c (replace_placeholders_t): Also track whether we've seen a
            placeholder.
            (replace_placeholders, replace_placeholders_r): Adjust.
            * cp-tree.h: Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0146332..6675ee5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6658,7 +6658,7 @@ extern tree array_type_nelts_total                (tree);
 extern tree array_type_nelts_top               (tree);
 extern tree break_out_target_exprs             (tree);
 extern tree build_ctor_subob_ref               (tree, tree, tree);
-extern tree replace_placeholders               (tree, tree);
+extern tree replace_placeholders               (tree, tree, bool * = NULL);
 extern tree get_type_decl                      (tree);
 extern tree decl_namespace_context             (tree);
 extern bool decl_anon_ns_mem_p                 (const_tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 42f1c61..524c583 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3282,7 +3282,19 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, 
tree nelts,
              init_expr = cp_build_modify_expr (input_location, init_expr,
                                                INIT_EXPR, ie, complain);
            }
-         stable = stabilize_init (init_expr, &init_preeval_expr);
+         /* If the initializer uses C++14 aggregate NSDMI that refer to the
+            object being initialized, replace them now and don't try to
+            preevaluate.  */
+         bool had_placeholder = false;
+         if (cxx_dialect >= cxx14
+             && !processing_template_decl
+             && TREE_CODE (init_expr) == INIT_EXPR)
+           TREE_OPERAND (init_expr, 1)
+             = replace_placeholders (TREE_OPERAND (init_expr, 1),
+                                     TREE_OPERAND (init_expr, 0),
+                                     &had_placeholder);
+         stable = (!had_placeholder
+                   && stabilize_init (init_expr, &init_preeval_expr));
        }
 
       if (init_expr == error_mark_node)
@@ -3454,7 +3466,17 @@ build_new (vec<tree, va_gc> **placement, tree type, tree 
nelts,
       orig_placement = make_tree_vector_copy (*placement);
       orig_nelts = nelts;
       if (*init)
-       orig_init = make_tree_vector_copy (*init);
+       {
+         orig_init = make_tree_vector_copy (*init);
+         /* Also copy any CONSTRUCTORs in *init, since reshape_init and
+            digest_init clobber them in place.  */
+         for (unsigned i = 0; i < orig_init->length(); ++i)
+           {
+             tree e = (**init)[i];
+             if (TREE_CODE (e) == CONSTRUCTOR)
+               (**init)[i] = copy_node (e);
+           }
+       }
 
       make_args_non_dependent (*placement);
       if (nelts)
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 56c4bba..d3c63b8 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2728,13 +2728,20 @@ build_ctor_subob_ref (tree index, tree type, tree obj)
   return obj;
 }
 
+struct replace_placeholders_t
+{
+  tree obj;        /* The object to be substituted for a PLACEHOLDER_EXPR.  */
+  bool seen;       /* Whether we've encountered a PLACEHOLDER_EXPR.  */
+};
+
 /* Like substitute_placeholder_in_expr, but handle C++ tree codes and
    build up subexpressions as we go deeper.  */
 
 static tree
 replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
 {
-  tree obj = static_cast<tree>(data_);
+  replace_placeholders_t *d = static_cast<replace_placeholders_t*>(data_);
+  tree obj = d->obj;
 
   if (TREE_CONSTANT (*t))
     {
@@ -2753,6 +2760,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, 
void* data_)
          gcc_assert (TREE_CODE (x) == COMPONENT_REF);
        *t = x;
        *walk_subtrees = false;
+       d->seen = true;
       }
       break;
 
@@ -2778,9 +2786,10 @@ replace_placeholders_r (tree* t, int* walk_subtrees, 
void* data_)
                if (TREE_CODE (*valp) == TARGET_EXPR)
                  valp = &TARGET_EXPR_INITIAL (*valp);
              }
-
+           d->obj = subob;
            cp_walk_tree (valp, replace_placeholders_r,
-                         subob, NULL);
+                         data_, NULL);
+           d->obj = obj;
          }
        *walk_subtrees = false;
        break;
@@ -2794,12 +2803,15 @@ replace_placeholders_r (tree* t, int* walk_subtrees, 
void* data_)
 }
 
 tree
-replace_placeholders (tree exp, tree obj)
+replace_placeholders (tree exp, tree obj, bool *seen_p)
 {
   tree *tp = &exp;
+  replace_placeholders_t data = { obj, false };
   if (TREE_CODE (exp) == TARGET_EXPR)
     tp = &TARGET_EXPR_INITIAL (exp);
-  cp_walk_tree (tp, replace_placeholders_r, obj, NULL);
+  cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
+  if (seen_p)
+    *seen_p = data.seen;
   return exp;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr6.C 
b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr6.C
new file mode 100644
index 0000000..83fdedd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr6.C
@@ -0,0 +1,14 @@
+// PR c++/77659
+// { dg-do compile { target c++14 } }
+
+template <typename Type> Type get_max_value(Type);
+struct A {
+  struct B {
+    int baz = get_max_value(baz);
+  };
+  template <typename> void m_fn1() { new B{}; }
+};
+void foo() {
+  A a;
+  a.m_fn1<int>();
+}

Reply via email to