aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/tree.cc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-09-17 12:04:05 +0200
committerJason Merrill <jason@redhat.com>2022-10-07 20:25:51 -0400
commit6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 (patch)
treedc67518a45f51746a76021cdca31b0d4c10677ed /gcc/cp/tree.cc
parent9ff6c33e2ec0d75958d3f19089519034e8f96a30 (diff)
downloadgcc-6ffbf87ca66f4ed9cd79cff675fabe2109e46e85.zip
gcc-6ffbf87ca66f4ed9cd79cff675fabe2109e46e85.tar.gz
gcc-6ffbf87ca66f4ed9cd79cff675fabe2109e46e85.tar.bz2
c++: track whether we expect a TARGET_EXPR to be elided
A discussion at Cauldron made me think that with the formalization of copy elision in C++17, we should be able to determine before optimization which TARGET_EXPRs will become temporaries and which are initializers. This patch implements that: we set TARGET_EXPR_ELIDING_P if it's used as an initializer, and later check that we were right. There's an exception in the cp_gimplify_expr check to allow extra temporaries of non-addressable type: this is used by gimplify_init_ctor_preeval to materialize subobjects of a CONSTRUCTOR on the rhs of a MODIFY_EXPR rather than materializing the whole object. If the type isn't addressable, there's no way for a program to tell the difference, so this is a valid optimization. I considered changing replace_placeholders_for_class_temp_r to check TARGET_EXPR_ELIDING_P instead of potential_prvalue_result_of, but decided that would be wrong: if we have an eliding TARGET_EXPR inside a non-eliding one, we would miss replacing its placeholders. gcc/cp/ChangeLog: * cp-tree.h (TARGET_EXPR_ELIDING_P): New. (unsafe_copy_elision_p, set_target_expr_eliding) (cp_build_init_expr): Declare. * call.cc (unsafe_copy_elision_p): No longer static. (build_over_call, build_special_member_call) (build_new_method_call): Use cp_build_init_expr. * coroutines.cc (expand_one_await_expression) (build_actor_fn, flatten_await_stmt, handle_nested_conditionals) (await_statement_walker, morph_fn_to_coro): Use cp_build_init_expr. * cp-gimplify.cc (cp_gimplify_init_expr) (cp_gimplify_expr): Check TARGET_EXPR_ELIDING_P. (cp_fold_r): Propagate it. (cp_fold): Use cp_build_init_expr. * decl.cc (check_initializer): Use cp_build_init_expr. * except.cc (build_throw): Use cp_build_init_expr. * init.cc (get_nsdmi): Call set_target_expr_eliding. (perform_member_init, expand_default_init, expand_aggr_init_1) (build_new_1, build_vec_init): Use cp_build_init_expr. * method.cc (do_build_copy_constructor): Use cp_build_init_expr. * semantics.cc (simplify_aggr_init_expr, finalize_nrv_r) (finish_omp_reduction_clause): Use cp_build_init_expr. * tree.cc (build_target_expr): Call set_target_expr_eliding. (bot_manip): Copy TARGET_EXPR_ELIDING_P. * typeck.cc (cp_build_modify_expr): Call set_target_expr_eliding. (check_return_expr): Use cp_build_modify_expr. * typeck2.cc (split_nonconstant_init_1) (split_nonconstant_init): Use cp_build_init_expr. (massage_init_elt): Call set_target_expr_eliding. (process_init_constructor_record): Clear TARGET_EXPR_ELIDING_P on unsafe copy elision. (set_target_expr_eliding, cp_build_init_expr): New.
Diffstat (limited to 'gcc/cp/tree.cc')
-rw-r--r--gcc/cp/tree.cc4
1 files changed, 4 insertions, 0 deletions
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 6d968a2..3532e44 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -533,6 +533,9 @@ build_target_expr (tree decl, tree value, tsubst_flags_t complain)
if (t == error_mark_node)
return error_mark_node;
}
+
+ set_target_expr_eliding (value);
+
t = build4 (TARGET_EXPR, type, decl, value, t, NULL_TREE);
if (location_t eloc = cp_expr_location (value))
SET_EXPR_LOCATION (t, eloc);
@@ -3194,6 +3197,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t);
TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t);
TARGET_EXPR_DIRECT_INIT_P (u) = TARGET_EXPR_DIRECT_INIT_P (t);
+ TARGET_EXPR_ELIDING_P (u) = TARGET_EXPR_ELIDING_P (t);
/* Map the old variable to the new one. */
splay_tree_insert (target_remap,