diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db7cb9bd9b0..a8cb00ed6e0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2016-04-07 Patrick Palka + + PR c++/70452 + * constexpr.c (find_constructor): New function. + (unshare_constructor): New function. + (cxx_eval_call_expression): Use unshare_constructor instead of + unshare_expr. + (find_array_ctor_elt): Likewise. + (cxx_eval_vec_init_1): Likewise. + (cxx_eval_store_expression): Likewise. + (cxx_eval_constant_expression): Likewise. + 2016-04-06 Patrick Palka PR c/70436 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1c2701bbcd4..5bccdec8d15 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1151,6 +1151,30 @@ adjust_temp_type (tree type, tree temp) return cp_fold_convert (type, temp); } +/* Callback for walk_tree used by unshare_constructor. */ + +static tree +find_constructor (tree *tp, int *walk_subtrees, void *) +{ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + if (TREE_CODE (*tp) == CONSTRUCTOR) + return *tp; + return NULL_TREE; +} + +/* If T is a CONSTRUCTOR or an expression that has a CONSTRUCTOR node as a + subexpression, return an unshared copy of T. Otherwise return T. */ + +static tree +unshare_constructor (tree t) +{ + tree ctor = walk_tree (&t, find_constructor, NULL, NULL); + if (ctor != NULL_TREE) + return unshare_expr (t); + return t; +} + /* Subroutine of cxx_eval_call_expression. We are processing a call expression (either CALL_EXPR or AGGR_INIT_EXPR) in the context of CTX. Evaluate @@ -1454,7 +1478,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree arg = TREE_VALUE (bound); gcc_assert (DECL_NAME (remapped) == DECL_NAME (oparm)); /* Don't share a CONSTRUCTOR that might be changed. */ - arg = unshare_expr (arg); + arg = unshare_constructor (arg); ctx->values->put (remapped, arg); bound = TREE_CHAIN (bound); remapped = DECL_CHAIN (remapped); @@ -1534,7 +1558,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } pop_cx_call_context (); - return unshare_expr (result); + return unshare_constructor (result); } /* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ @@ -1880,7 +1904,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert = false) /* Append the element we want to insert. */ ++middle; e.index = dindex; - e.value = unshare_expr (elt.value); + e.value = unshare_constructor (elt.value); vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle, e); } else @@ -1896,7 +1920,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert = false) e.index = hi; else e.index = build2 (RANGE_EXPR, sizetype, new_lo, hi); - e.value = unshare_expr (elt.value); + e.value = unshare_constructor (elt.value); vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle+1, e); } } @@ -2565,7 +2589,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, for (i = 1; i < max; ++i) { idx = build_int_cst (size_type_node, i); - CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_expr (eltinit)); + CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_constructor (eltinit)); } break; } @@ -3113,7 +3137,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, init = cxx_eval_constant_expression (&new_ctx, init, false, non_constant_p, overflow_p); /* Don't share a CONSTRUCTOR that might be changed later. */ - init = unshare_expr (init); + init = unshare_constructor (init); if (target == object) /* The hash table might have moved since the get earlier. */ valp = ctx->values->get (object); @@ -3565,7 +3589,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, false, non_constant_p, overflow_p); /* Don't share a CONSTRUCTOR that might be changed. */ - init = unshare_expr (init); + init = unshare_constructor (init); ctx->values->put (r, init); } else if (ctx == &new_ctx) @@ -3610,7 +3634,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (lval) { tree slot = TARGET_EXPR_SLOT (t); - r = unshare_expr (r); + r = unshare_constructor (r); ctx->values->put (slot, r); return slot; }