diff options
author | Jason Merrill <jason@redhat.com> | 2020-03-05 15:50:45 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-01-06 19:23:17 -0500 |
commit | 4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda (patch) | |
tree | 0a38c0720e5d43cd717dbef2244dad9d139dd830 /gcc/cp/cp-gimplify.c | |
parent | beaee0a871b6485d20573fe050b1fd425581e56a (diff) | |
download | gcc-4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda.zip gcc-4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda.tar.gz gcc-4f6bc28fc7dd86bd9e7408cbf28de1e973dd1eda.tar.bz2 |
c++: EH and partially constructed aggr temp [PR66139]
Now that PR94041 is fixed, I can return to addressing PR66139, missing
cleanups for partially constructed aggregate temporaries. My previous
approach of calling split_nonconstant_init in cp_gimplify_init_expr broke
because gimplification is too late to be introducing destructor calls. So
instead I now call it under cp_fold_function, just before cp_genericize;
doing it from cp_genericize itself ran into trouble with the rewriting of
invisible references.
So now the prediction in cp_gimplify_expr that cp_gimplify_init_expr
might need to replace references to TARGET_EXPR_SLOT within
TARGET_EXPR_INITIAL has come to pass. constexpr.c already had the simple
search-and-replace tree walk I needed, but it needed to be fixed to actually
replace all occurrences instead of just the first one.
Handling of VEC_INIT_EXPR at gimplify time had similar issues that we worked
around with build_vec_init_elt, so I'm moving that to cp_fold_function as
well. But it seems that build_vec_init_elt is still useful for setting the
VEC_INIT_EXPR_IS_CONSTEXPR flag, so I'm leaving it alone.
This also fixes 52320, because build_aggr_init of each X from build_vec_init
builds an INIT_EXPR rather than call split_nonconstant_init at that point,
and now that INIT_EXPR gets split later.
PR c++/66139
PR c++/52320
gcc/cp/ChangeLog:
* constexpr.c (replace_decl): Rename from replace_result_decl.
* cp-tree.h (replace_decl): Declare it.
* cp-gimplify.c (cp_gimplify_init_expr): Call it.
(cp_gimplify_expr): Don't handle VEC_INIT_EXPR.
(cp_genericize_init, cp_genericize_init_expr)
(cp_genericize_target_expr): New.
(cp_fold_r): Call them.
* tree.c (build_array_copy): Add a TARGET_EXPR.
* typeck2.c (digest_init_r): Look through a TARGET_EXPR.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/initlist116.C: New test.
* g++.dg/cpp0x/initlist117.C: New test.
* g++.dg/cpp0x/lambda/lambda-eh.C: New test.
* g++.dg/eh/aggregate1.C: New test.
Diffstat (limited to 'gcc/cp/cp-gimplify.c')
-rw-r--r-- | gcc/cp/cp-gimplify.c | 93 |
1 files changed, 74 insertions, 19 deletions
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index e4f2442..114fa78 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -239,12 +239,21 @@ cp_gimplify_init_expr (tree *expr_p) tree to = TREE_OPERAND (*expr_p, 0); tree t; - /* What about code that pulls out the temp and uses it elsewhere? I - think that such code never uses the TARGET_EXPR as an initializer. If - I'm wrong, we'll abort because the temp won't have any RTL. In that - case, I guess we'll need to replace references somehow. */ - if (TREE_CODE (from) == TARGET_EXPR && TARGET_EXPR_INITIAL (from)) - from = TARGET_EXPR_INITIAL (from); + if (TREE_CODE (from) == TARGET_EXPR) + if (tree init = TARGET_EXPR_INITIAL (from)) + { + if (VOID_TYPE_P (TREE_TYPE (init)) + && TREE_CODE (init) != AGGR_INIT_EXPR) + { + /* If this was changed by cp_genericize_target_expr, we need to + walk into it to replace uses of the slot. */ + replace_decl (&init, TARGET_EXPR_SLOT (from), to); + *expr_p = init; + return; + } + else + from = init; + } /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them inside the TARGET_EXPR. */ @@ -460,19 +469,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) ret = GS_OK; break; - case VEC_INIT_EXPR: - { - *expr_p = expand_vec_init_expr (NULL_TREE, *expr_p, - tf_warning_or_error); - - hash_set<tree> pset; - cp_walk_tree (expr_p, cp_fold_r, &pset, NULL); - cp_genericize_tree (expr_p, false); - copy_if_shared (expr_p); - ret = GS_OK; - } - break; - case THROW_EXPR: /* FIXME communicate throw type to back end, probably by moving THROW_EXPR into ../tree.def. */ @@ -868,6 +864,57 @@ omp_cxx_notice_variable (struct cp_genericize_omp_taskreg *omp_ctx, tree decl) } } +/* If we might need to clean up a partially constructed object, break down the + CONSTRUCTOR with split_nonconstant_init. Also expand VEC_INIT_EXPR at this + point. If initializing TO with FROM is non-trivial, overwrite *REPLACE with + the result. */ + +static void +cp_genericize_init (tree *replace, tree from, tree to) +{ + if (TREE_CODE (from) == VEC_INIT_EXPR) + { + tree init = expand_vec_init_expr (to, from, tf_warning_or_error); + + /* Make cp_gimplify_init_expr call replace_decl. */ + *replace = fold_convert (void_type_node, init); + } + else if (flag_exceptions + && TREE_CODE (from) == CONSTRUCTOR + && TREE_SIDE_EFFECTS (from) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (from))) + { + to = cp_stabilize_reference (to); + replace_placeholders (from, to); + *replace = split_nonconstant_init (to, from); + } +} + +/* For an INIT_EXPR, replace the INIT_EXPR itself. */ + +static void +cp_genericize_init_expr (tree *stmt_p) +{ + tree to = TREE_OPERAND (*stmt_p, 0); + tree from = TREE_OPERAND (*stmt_p, 1); + if (SIMPLE_TARGET_EXPR_P (from) + /* Return gets confused if we clobber its INIT_EXPR this soon. */ + && TREE_CODE (to) != RESULT_DECL) + from = TARGET_EXPR_INITIAL (from); + cp_genericize_init (stmt_p, from, to); +} + +/* For a TARGET_EXPR, change the TARGET_EXPR_INITIAL. We will need to use + replace_decl later when we know what we're initializing. */ + +static void +cp_genericize_target_expr (tree *stmt_p) +{ + cp_genericize_init (&TARGET_EXPR_INITIAL (*stmt_p), + TARGET_EXPR_INITIAL (*stmt_p), + TARGET_EXPR_SLOT (*stmt_p)); +} + /* Genericization context. */ struct cp_genericize_data @@ -1007,6 +1054,14 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data) } break; + case INIT_EXPR: + cp_genericize_init_expr (stmt_p); + break; + + case TARGET_EXPR: + cp_genericize_target_expr (stmt_p); + break; + default: break; } |