diff mbox

C++ PATCH for c++/77659 (ICE with new-expression and C++14 aggregate NSDMI)

Message ID CADzB+2n4W58id1dtNdpZin8WKxEWCV353m2axR3rVokE-bHdmw@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Feb. 12, 2017, 3:24 a.m. UTC
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 <jason@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 mbox

Patch

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>();
+}