PR c++/77659 - ICE with new and C++14 aggregate NSDMI
authorJason Merrill <jason@redhat.com>
Sun, 12 Feb 2017 03:31:02 +0000 (22:31 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 12 Feb 2017 03:31:02 +0000 (22:31 -0500)
* 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.

From-SVN: r245372

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr6.C [new file with mode: 0644]

index 553db8a126b56b9474a7237a51dc9c0f73d6cecf..486cb88575f13f40d7d236bb58d4d2e9ca446df4 100644 (file)
@@ -1,5 +1,13 @@
 2017-02-11  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        PR c++/77790 - ICE with auto function in C++11 mode
        * decl.c (undeduced_auto_decl): Remove C++14 limitation.
        (require_deduced_type): Add complain parm, return bool.
index 0146332181c0a8be28379f9a312a119819bf37b0..6675ee5bb50eb42abf8647178404f5498d52479e 100644 (file)
@@ -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);
index 42f1c6192eceeb6f61ba917ef25327662ab9b553..524c583138f3e5cf7eb6ab05ad97e27c4c033642 100644 (file)
@@ -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)
index 56c4bbaf8b87479a8e2a1ca95408307f0c2d4037..d3c63b82cb347e9baadf8f4f76aefee4e04e5a75 100644 (file)
@@ -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 (file)
index 0000000..83fdedd
--- /dev/null
@@ -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>();
+}