From 6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 17 Sep 2022 12:04:05 +0200 Subject: 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. --- gcc/cp/tree.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp/tree.cc') 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, -- cgit v1.1