re PR c++/79937 (ICE in replace_placeholders_r)
authorJakub Jelinek <jakub@redhat.com>
Fri, 16 Mar 2018 12:46:12 +0000 (13:46 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 16 Mar 2018 12:46:12 +0000 (13:46 +0100)
PR c++/79937
PR c++/82410
* tree.h (TARGET_EXPR_NO_ELIDE): Define.
* gimplify.c (gimplify_modify_expr_rhs): Don't elide TARGET_EXPRs with
TARGET_EXPR_NO_ELIDE flag set unless *expr_p is INIT_EXPR.

* cp-tree.h (CONSTRUCTOR_PLACEHOLDER_BOUNDARY): Define.
(find_placeholder): Declare.
* tree.c (struct replace_placeholders_t): Add exp member.
(replace_placeholders_r): Don't walk into ctors with
CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set, unless they are equal to
d->exp.  Replace PLACEHOLDER_EXPR with unshare_expr (x) rather than x.
(replace_placeholders): Initialize data.exp.
(find_placeholders_r, find_placeholders): New functions.
* typeck2.c (process_init_constructor_record,
process_init_constructor_union): Set CONSTRUCTOR_PLACEHOLDER_BOUNDARY
if adding NSDMI on which find_placeholder returns true.
* call.c (build_over_call): Don't call replace_placeholders here.
* cp-gimplify.c (cp_genericize_r): Set TARGET_EXPR_NO_ELIDE on
TARGET_EXPRs with CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on
TARGET_EXPR_INITIAL.
(cp_fold): Copy over CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit to new
ctor.

* g++.dg/cpp1y/pr79937-1.C: New test.
* g++.dg/cpp1y/pr79937-2.C: New test.
* g++.dg/cpp1y/pr79937-3.C: New test.
* g++.dg/cpp1y/pr79937-4.C: New test.
* g++.dg/cpp1y/pr82410.C: New test.

From-SVN: r258593

15 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr79937-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/pr79937-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/pr79937-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/pr79937-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/pr82410.C [new file with mode: 0644]
gcc/tree.h

index 9ed1172..627700a 100644 (file)
@@ -1,3 +1,11 @@
+2018-03-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/79937
+       PR c++/82410
+       * tree.h (TARGET_EXPR_NO_ELIDE): Define.
+       * gimplify.c (gimplify_modify_expr_rhs): Don't elide TARGET_EXPRs with
+       TARGET_EXPR_NO_ELIDE flag set unless *expr_p is INIT_EXPR.
+
 2018-03-16  Julia Koval  <julia.koval@intel.com>
 
        * doc/invoke.texi (Skylake Server): Add CLWB.
index a580860..0ea8371 100644 (file)
@@ -1,3 +1,25 @@
+2018-03-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/79937
+       PR c++/82410
+       * cp-tree.h (CONSTRUCTOR_PLACEHOLDER_BOUNDARY): Define.
+       (find_placeholder): Declare.
+       * tree.c (struct replace_placeholders_t): Add exp member.
+       (replace_placeholders_r): Don't walk into ctors with
+       CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set, unless they are equal to
+       d->exp.  Replace PLACEHOLDER_EXPR with unshare_expr (x) rather than x.
+       (replace_placeholders): Initialize data.exp.
+       (find_placeholders_r, find_placeholders): New functions.
+       * typeck2.c (process_init_constructor_record,
+       process_init_constructor_union): Set CONSTRUCTOR_PLACEHOLDER_BOUNDARY
+       if adding NSDMI on which find_placeholder returns true.
+       * call.c (build_over_call): Don't call replace_placeholders here.
+       * cp-gimplify.c (cp_genericize_r): Set TARGET_EXPR_NO_ELIDE on
+       TARGET_EXPRs with CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on
+       TARGET_EXPR_INITIAL.
+       (cp_fold): Copy over CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit to new
+       ctor.
+
 2018-03-16  Jason Merrill  <jason@redhat.com>
 
        PR c++/83911 - ICE with multiversioned constructor.
index 67438ff..5cee63f 100644 (file)
@@ -8164,8 +8164,6 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        {
          arg = cp_build_fold_indirect_ref (arg);
          val = build2 (MODIFY_EXPR, TREE_TYPE (to), to, arg);
-         /* Handle NSDMI that refer to the object being initialized.  */
-         replace_placeholders (arg, to);
        }
       else
        {
index 653d1dc..332ff2b 100644 (file)
@@ -1538,6 +1538,13 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       }
       break;
 
+    case TARGET_EXPR:
+      if (TARGET_EXPR_INITIAL (stmt)
+         && TREE_CODE (TARGET_EXPR_INITIAL (stmt)) == CONSTRUCTOR
+         && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (TARGET_EXPR_INITIAL (stmt)))
+       TARGET_EXPR_NO_ELIDE (stmt) = 1;
+      break;
+
     default:
       if (IS_TYPE_OR_DECL_P (stmt))
        *walk_subtrees = 0;
@@ -2492,7 +2499,11 @@ cp_fold (tree x)
              }
          }
        if (nelts)
-         x = build_constructor (TREE_TYPE (x), nelts);
+         {
+           x = build_constructor (TREE_TYPE (x), nelts);
+           CONSTRUCTOR_PLACEHOLDER_BOUNDARY (x)
+             = CONSTRUCTOR_PLACEHOLDER_BOUNDARY (org_x);
+         }
        break;
       }
     case TREE_VEC:
index 99c51a8..727822e 100644 (file)
@@ -425,6 +425,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       DECL_VTABLE_OR_VTT_P (in VAR_DECL)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
       CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
+      CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR)
    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
       DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
       TYPE_MARKED_P (in _TYPE)
@@ -4144,6 +4145,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define CONSTRUCTOR_C99_COMPOUND_LITERAL(NODE) \
   (TREE_LANG_FLAG_3 (CONSTRUCTOR_CHECK (NODE)))
 
+/* True if this CONSTRUCTOR contains PLACEHOLDER_EXPRs referencing the
+   CONSTRUCTOR's type not nested inside another CONSTRUCTOR marked with
+   CONSTRUCTOR_PLACEHOLDER_BOUNDARY.  */
+#define CONSTRUCTOR_PLACEHOLDER_BOUNDARY(NODE) \
+  (TREE_LANG_FLAG_5 (CONSTRUCTOR_CHECK (NODE)))
+
 #define DIRECT_LIST_INIT_P(NODE) \
    (BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE))
 
@@ -7021,6 +7028,7 @@ 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, bool * = NULL);
+extern bool find_placeholders                  (tree);
 extern tree get_type_decl                      (tree);
 extern tree decl_namespace_context             (tree);
 extern bool decl_anon_ns_mem_p                 (const_tree);
index c2299ba..90fbe18 100644 (file)
@@ -3096,6 +3096,7 @@ build_ctor_subob_ref (tree index, tree type, tree obj)
 struct replace_placeholders_t
 {
   tree obj;        /* The object to be substituted for a PLACEHOLDER_EXPR.  */
+  tree exp;        /* The outermost exp.  */
   bool seen;       /* Whether we've encountered a PLACEHOLDER_EXPR.  */
   hash_set<tree> *pset;        /* To avoid walking same trees multiple times.  */
 };
@@ -3124,7 +3125,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
                                                           TREE_TYPE (x));
             x = TREE_OPERAND (x, 0))
          gcc_assert (TREE_CODE (x) == COMPONENT_REF);
-       *t = x;
+       *t = unshare_expr (x);
        *walk_subtrees = false;
        d->seen = true;
       }
@@ -3134,7 +3135,12 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
       {
        constructor_elt *ce;
        vec<constructor_elt,va_gc> *v = CONSTRUCTOR_ELTS (*t);
-       if (d->pset->add (*t))
+       /* Don't walk into CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors
+          other than the d->exp one, those have PLACEHOLDER_EXPRs
+          related to another object.  */
+       if ((CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t)
+            && *t != d->exp)
+           || d->pset->add (*t))
          {
            *walk_subtrees = false;
            return NULL_TREE;
@@ -3192,16 +3198,57 @@ replace_placeholders (tree exp, tree obj, bool *seen_p)
     return exp;
 
   tree *tp = &exp;
-  hash_set<tree> pset;
-  replace_placeholders_t data = { obj, false, &pset };
   if (TREE_CODE (exp) == TARGET_EXPR)
     tp = &TARGET_EXPR_INITIAL (exp);
+  hash_set<tree> pset;
+  replace_placeholders_t data = { obj, *tp, false, &pset };
   cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
   if (seen_p)
     *seen_p = data.seen;
   return exp;
 }
 
+/* Callback function for find_placeholders.  */
+
+static tree
+find_placeholders_r (tree *t, int *walk_subtrees, void *)
+{
+  if (TYPE_P (*t) || TREE_CONSTANT (*t))
+    {
+      *walk_subtrees = false;
+      return NULL_TREE;
+    }
+
+  switch (TREE_CODE (*t))
+    {
+    case PLACEHOLDER_EXPR:
+      return *t;
+
+    case CONSTRUCTOR:
+      if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t))
+       *walk_subtrees = false;
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return true if EXP contains a PLACEHOLDER_EXPR.  Don't walk into
+   ctors with CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set.  */
+
+bool
+find_placeholders (tree exp)
+{
+  /* This is only relevant for C++14.  */
+  if (cxx_dialect < cxx14)
+    return false;
+
+  return cp_walk_tree_without_duplicates (&exp, find_placeholders_r, NULL);
+}
+
 /* Similar to `build_nt', but for template definitions of dependent
    expressions  */
 
index 2df51a5..464e8a7 100644 (file)
@@ -1470,6 +1470,9 @@ process_init_constructor_record (tree type, tree init, int nested,
            }
          /* C++14 aggregate NSDMI.  */
          next = get_nsdmi (field, /*ctor*/false, complain);
+         if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)
+             && find_placeholders (next))
+           CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
        }
       else if (type_build_ctor_call (TREE_TYPE (field)))
        {
@@ -1608,10 +1611,11 @@ process_init_constructor_union (tree type, tree init, int nested,
          if (TREE_CODE (field) == FIELD_DECL
              && DECL_INITIAL (field) != NULL_TREE)
            {
-             CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init),
-                                     field,
-                                     get_nsdmi (field, /*in_ctor=*/false,
-                                                complain));
+             tree val = get_nsdmi (field, /*in_ctor=*/false, complain);
+             if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)
+                 && find_placeholders (val))
+               CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+             CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), field, val);
              break;
            }
        }
index 7fedd97..115f80b 100644 (file)
@@ -5211,6 +5211,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
            tree init = TARGET_EXPR_INITIAL (*from_p);
 
            if (init
+               && (TREE_CODE (*expr_p) != MODIFY_EXPR
+                   || !TARGET_EXPR_NO_ELIDE (*from_p))
                && !VOID_TYPE_P (TREE_TYPE (init)))
              {
                *from_p = init;
index 491c403..ff2ac8b 100644 (file)
@@ -1,3 +1,13 @@
+2018-03-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/79937
+       PR c++/82410
+       * g++.dg/cpp1y/pr79937-1.C: New test.
+       * g++.dg/cpp1y/pr79937-2.C: New test.
+       * g++.dg/cpp1y/pr79937-3.C: New test.
+       * g++.dg/cpp1y/pr79937-4.C: New test.
+       * g++.dg/cpp1y/pr82410.C: New test.
+
 2018-03-16  Tom de Vries  <tom@codesourcery.com>
 
        * gcc.dg/tree-ssa/pr84512.c: Require effective target vect_int_mult.
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-1.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-1.C
new file mode 100644 (file)
index 0000000..f547782
--- /dev/null
@@ -0,0 +1,23 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+C
+bar (X x)
+{
+  if (x.i != 1 || x.n != 1)
+    __builtin_abort ();
+  return {};
+}
+
+int
+main ()
+{
+  C c = bar (X {1});
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-2.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-2.C
new file mode 100644 (file)
index 0000000..551b8b6
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+  unsigned m = i;
+};
+
+C
+bar (X x)
+{
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+  return {};
+}
+
+int
+main ()
+{
+  C c = bar (X {1, X {2}.n});
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-3.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-3.C
new file mode 100644 (file)
index 0000000..6f0c22d
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+  unsigned m = i;
+};
+
+X
+bar (X x)
+{
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+  return x;
+}
+
+int
+main ()
+{
+  X x = bar (X {1, X {2}.n});
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-4.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-4.C
new file mode 100644 (file)
index 0000000..1a49630
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+X
+bar (X x)
+{
+  return x;
+}
+
+struct Y
+{
+  static Y bar (Y y) { return y; }
+  unsigned i;
+  unsigned n = bar (Y{2,i}).n;
+};
+
+int
+main ()
+{
+  X x { 1, bar (X{2}).n };
+  if (x.n != 2)
+    __builtin_abort ();
+
+  Y y { 1 };
+  if (y.n != 1)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr82410.C b/gcc/testsuite/g++.dg/cpp1y/pr82410.C
new file mode 100644 (file)
index 0000000..185f644
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/82410
+// { dg-do compile { target c++14 } }
+
+int
+main ()
+{
+  struct A {};
+  struct S
+  {
+    int & p;
+    int x = p;
+    operator A () { return {}; }
+  };
+  int l;
+  [] (A) {} (S{l});
+}
index af8a6fb..1e14d9f 100644 (file)
@@ -1197,6 +1197,9 @@ extern tree maybe_wrap_with_location (tree, location_t);
 #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
 #define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1)
 #define TARGET_EXPR_CLEANUP(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 2)
+/* Don't elide the initialization of TARGET_EXPR_SLOT for this TARGET_EXPR
+   on rhs of MODIFY_EXPR.  */
+#define TARGET_EXPR_NO_ELIDE(NODE) (TARGET_EXPR_CHECK (NODE)->base.private_flag)
 
 /* DECL_EXPR accessor. This gives access to the DECL associated with
    the given declaration statement.  */