aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/call.cc16
-rw-r--r--gcc/cp/coroutines.cc43
-rw-r--r--gcc/cp/cp-gimplify.cc13
-rw-r--r--gcc/cp/cp-tree.h11
-rw-r--r--gcc/cp/decl.cc2
-rw-r--r--gcc/cp/except.cc2
-rw-r--r--gcc/cp/init.cc31
-rw-r--r--gcc/cp/method.cc4
-rw-r--r--gcc/cp/semantics.cc12
-rw-r--r--gcc/cp/tree.cc4
-rw-r--r--gcc/cp/typeck.cc6
-rw-r--r--gcc/cp/typeck2.cc56
12 files changed, 138 insertions, 62 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 7771d80..70ec964 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9144,7 +9144,7 @@ init_by_return_slot_p (tree exp)
Places that use this function (or _opt) to decide to elide a copy should
probably use make_safe_copy_elision instead. */
-static bool
+bool
unsafe_copy_elision_p (tree target, tree exp)
{
return unsafe_return_slot_p (target) && init_by_return_slot_p (exp);
@@ -9941,7 +9941,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
&& !unsafe)
{
tree to = cp_build_fold_indirect_ref (fa);
- val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+ val = cp_build_init_expr (to, arg);
return val;
}
}
@@ -10100,7 +10100,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
call = cxx_constant_value (call, obj_arg, complain);
if (obj_arg && !error_operand_p (call))
- call = build2 (INIT_EXPR, void_type_node, obj_arg, call);
+ call = cp_build_init_expr (obj_arg, call);
call = convert_from_reference (call);
}
}
@@ -10765,7 +10765,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
check_self_delegation (arg);
/* Avoid change of behavior on Wunused-var-2.C. */
instance = mark_lvalue_use (instance);
- return build2 (INIT_EXPR, class_type, instance, arg);
+ return cp_build_init_expr (instance, arg);
}
}
@@ -11183,9 +11183,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
{
if (is_dummy_object (instance))
return get_target_expr (init, complain);
- init = build2 (INIT_EXPR, TREE_TYPE (instance), instance, init);
- TREE_SIDE_EFFECTS (init) = true;
- return init;
+ return cp_build_init_expr (instance, init);
}
/* Otherwise go ahead with overload resolution. */
@@ -11232,9 +11230,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
ctor = digest_init (basetype, ctor, complain);
if (ctor == error_mark_node)
return error_mark_node;
- ctor = build2 (INIT_EXPR, TREE_TYPE (instance), instance, ctor);
- TREE_SIDE_EFFECTS (ctor) = true;
- return ctor;
+ return cp_build_init_expr (instance, ctor);
}
}
if (complain & tf_error)
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 60b8466..01a3e83 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1732,7 +1732,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
if (!same_type_ignoring_top_level_qualifiers_p (susp_type,
void_coro_handle_type))
r = build1_loc (loc, VIEW_CONVERT_EXPR, void_coro_handle_type, r);
- r = build2_loc (loc, INIT_EXPR, void_coro_handle_type, data->conthand, r);
+ r = cp_build_init_expr (loc, data->conthand, r);
r = build1 (CONVERT_EXPR, void_type_node, r);
append_to_statement_list (r, &body_list);
is_cont = true;
@@ -1755,7 +1755,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
r = build_call_expr_internal_loc (loc, IFN_CO_YIELD, integer_type_node, 5,
susp_idx, final_susp, r_l, d_l,
data->coro_fp);
- r = build2 (INIT_EXPR, integer_type_node, cond, r);
+ r = cp_build_init_expr (cond, r);
finish_switch_cond (r, sw);
r = build_case_label (build_int_cst (integer_type_node, 0), NULL_TREE,
create_anon_label_with_ctx (loc, actor));
@@ -2304,7 +2304,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
vec<tree, va_gc> *args = make_tree_vector_single (r);
tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL,
NULL, tf_warning_or_error);
- r = build2 (INIT_EXPR, handle_type, ash, hfa);
+ r = cp_build_init_expr (ash, hfa);
r = coro_build_cvt_void_expr_stmt (r, loc);
add_stmt (r);
release_tree_vector (args);
@@ -2776,17 +2776,19 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
if (!VOID_TYPE_P (TREE_TYPE (then_cl)))
{
gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST);
- then_cl
- = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
- var, then_cl);
+ if (init_expr)
+ then_cl = cp_build_init_expr (var, then_cl);
+ else
+ then_cl = build2 (MODIFY_EXPR, var_type, var, then_cl);
}
tree else_cl = COND_EXPR_ELSE (old_expr);
if (!VOID_TYPE_P (TREE_TYPE (else_cl)))
{
gcc_checking_assert (TREE_CODE (else_cl) != STATEMENT_LIST);
- else_cl
- = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type,
- var, else_cl);
+ if (init_expr)
+ else_cl = cp_build_init_expr (var, else_cl);
+ else
+ else_cl = build2 (MODIFY_EXPR, var_type, var, else_cl);
}
n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl);
}
@@ -2804,7 +2806,7 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
DECL_ARTIFICIAL (cond_var) = true;
layout_decl (cond_var, 0);
gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type));
- cond = build2 (INIT_EXPR, cond_type, cond_var, cond);
+ cond = cp_build_init_expr (cond_var, cond);
var_nest_node *ins
= new var_nest_node (cond_var, cond, n->prev, n);
COND_EXPR_COND (n->init) = cond_var;
@@ -2957,8 +2959,7 @@ handle_nested_conditionals (var_nest_node *n, vec<tree>& list,
expression that performs the init and then records that the
variable is live (and the DTOR should be run at the scope
exit. */
- tree set_flag = build2 (INIT_EXPR, boolean_type_node,
- flag, boolean_true_node);
+ tree set_flag = cp_build_init_expr (flag, boolean_true_node);
n->init
= build2 (COMPOUND_EXPR, boolean_type_node, n->init, set_flag);
}
@@ -3471,8 +3472,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d)
/* We want to initialize the new variable with the expression
that contains the await(s) and potentially also needs to
have truth_if expressions expanded. */
- tree new_s = build2_loc (sloc, INIT_EXPR, boolean_type_node,
- newvar, cond_inner);
+ tree new_s = cp_build_init_expr (sloc, newvar, cond_inner);
finish_expr_stmt (new_s);
IF_COND (if_stmt) = newvar;
add_stmt (if_stmt);
@@ -3656,7 +3656,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d)
if (TREE_CODE (cond_inner) == CLEANUP_POINT_EXPR)
cond_inner = TREE_OPERAND (cond_inner, 0);
location_t sloc = EXPR_LOCATION (SWITCH_STMT_COND (sw_stmt));
- tree new_s = build2_loc (sloc, INIT_EXPR, sw_type, newvar,
+ tree new_s = cp_build_init_expr (sloc, newvar,
cond_inner);
finish_expr_stmt (new_s);
SWITCH_STMT_COND (sw_stmt) = newvar;
@@ -4735,7 +4735,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
}
tree allocated = build1 (CONVERT_EXPR, coro_frame_ptr, new_fn);
- tree r = build2 (INIT_EXPR, TREE_TYPE (coro_fp), coro_fp, allocated);
+ tree r = cp_build_init_expr (coro_fp, allocated);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
@@ -4796,7 +4796,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
1, 0,tf_warning_or_error);
tree fnf_x = build_class_member_access_expr (deref_fp, fnf_m, NULL_TREE,
false, tf_warning_or_error);
- r = build2 (INIT_EXPR, boolean_type_node, fnf_x, boolean_true_node);
+ r = cp_build_init_expr (fnf_x, boolean_true_node);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
@@ -4808,7 +4808,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
/*protect=*/1, /*want_type=*/0, tf_warning_or_error);
tree resume_x = build_class_member_access_expr (deref_fp, resume_m, NULL_TREE,
false, tf_warning_or_error);
- r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, resume_x, actor_addr);
+ r = cp_build_init_expr (fn_start, resume_x, actor_addr);
finish_expr_stmt (r);
tree destroy_addr = build1 (ADDR_EXPR, act_des_fn_ptr, destroy);
@@ -4818,7 +4818,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree destroy_x
= build_class_member_access_expr (deref_fp, destroy_m, NULL_TREE, false,
tf_warning_or_error);
- r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, destroy_x, destroy_addr);
+ r = cp_build_init_expr (fn_start, destroy_x, destroy_addr);
finish_expr_stmt (r);
/* [dcl.fct.def.coroutine] /13
@@ -5011,8 +5011,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
release_tree_vector (arg);
}
else
- r = build2_loc (fn_start, INIT_EXPR, gro_type,
- DECL_RESULT (orig), get_ro);
+ r = cp_build_init_expr (fn_start, DECL_RESULT (orig), get_ro);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type))
/* If some part of the initalization code (prior to the await_resume
@@ -5067,7 +5066,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
= build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false,
tf_warning_or_error);
r = build_int_cst (short_unsigned_type_node, 0);
- r = build2_loc (fn_start, INIT_EXPR, short_unsigned_type_node, resume_idx, r);
+ r = cp_build_init_expr (fn_start, resume_idx, r);
r = coro_build_cvt_void_expr_stmt (r, fn_start);
add_stmt (r);
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index cb8bbd8..d0e12c9 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -250,6 +250,7 @@ cp_gimplify_init_expr (tree *expr_p)
if (TREE_CODE (from) == TARGET_EXPR)
if (tree init = TARGET_EXPR_INITIAL (from))
{
+ gcc_checking_assert (TARGET_EXPR_ELIDING_P (from));
if (target_expr_needs_replace (from))
{
/* If this was changed by cp_genericize_target_expr, we need to
@@ -745,6 +746,11 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
/* A TARGET_EXPR that expresses direct-initialization should have been
elided by cp_gimplify_init_expr. */
gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
+ /* Likewise, but allow extra temps of trivial type so that
+ gimplify_init_ctor_preeval can materialize subobjects of a CONSTRUCTOR
+ on the rhs of an assignment, as in constexpr-aggr1.C. */
+ gcc_checking_assert (!TARGET_EXPR_ELIDING_P (*expr_p)
+ || !TREE_ADDRESSABLE (TREE_TYPE (*expr_p)));
ret = GS_UNHANDLED;
break;
@@ -1110,7 +1116,10 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
cp_walk_tree (&init, cp_fold_r, data, NULL);
*walk_subtrees = 0;
if (TREE_CODE (init) == TARGET_EXPR)
- *stmt_p = init;
+ {
+ TARGET_EXPR_ELIDING_P (init) = TARGET_EXPR_ELIDING_P (stmt);
+ *stmt_p = init;
+ }
}
break;
@@ -2902,7 +2911,7 @@ cp_fold (tree x)
loc = EXPR_LOCATION (x);
tree s = build_fold_indirect_ref_loc (loc,
CALL_EXPR_ARG (x, 0));
- r = build2_loc (loc, INIT_EXPR, TREE_TYPE (s), s, r);
+ r = cp_build_init_expr (s, r);
}
x = r;
break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 469eb2f..ab6f85a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -505,6 +505,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
DECL_MODULE_EXPORT_P (in _DECL)
PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION)
LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
+ TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
CALL_EXPR, or FIELD_DECL).
@@ -5370,6 +5371,11 @@ get_vec_init_expr (tree t)
#define TARGET_EXPR_DIRECT_INIT_P(NODE) \
TREE_LANG_FLAG_2 (TARGET_EXPR_CHECK (NODE))
+/* True if we expect this TARGET_EXPR to be used as an initializer, not to
+ materialize as a temporary. */
+#define TARGET_EXPR_ELIDING_P(NODE) \
+ TREE_LANG_FLAG_3 (TARGET_EXPR_CHECK (NODE))
+
/* True if NODE is a TARGET_EXPR that just expresses a copy of its INITIAL; if
the initializer has void type, it's doing something more complicated. */
#define SIMPLE_TARGET_EXPR_P(NODE) \
@@ -6657,6 +6663,7 @@ extern bool is_list_ctor (tree);
extern void validate_conversion_obstack (void);
extern void mark_versions_used (tree);
extern int unsafe_return_slot_p (tree);
+extern bool unsafe_copy_elision_p (tree, tree);
extern bool make_safe_copy_elision (tree, tree);
extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error);
extern void cp_warn_deprecated_use_scopes (tree);
@@ -8182,6 +8189,10 @@ extern tree build_functional_cast (location_t, tree, tree,
tsubst_flags_t);
extern tree add_exception_specifier (tree, tree, tsubst_flags_t);
extern tree merge_exception_specifiers (tree, tree);
+extern void set_target_expr_eliding (tree);
+extern tree cp_build_init_expr (location_t, tree, tree);
+inline tree cp_build_init_expr (tree t, tree i)
+{ return cp_build_init_expr (input_location, t, i); }
/* in mangle.cc */
extern void init_mangle (void);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 07148b9..82eb0c2 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7500,7 +7500,7 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
}
if (init && init != error_mark_node)
- init_code = build2 (INIT_EXPR, type, decl, init);
+ init_code = cp_build_init_expr (decl, init);
if (init_code && !TREE_SIDE_EFFECTS (init_code)
&& init_code != error_mark_node)
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 048612d..b8a85ed 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -755,7 +755,7 @@ build_throw (location_t loc, tree exp)
tree tmp = decay_conversion (exp, tf_warning_or_error);
if (tmp == error_mark_node)
return error_mark_node;
- exp = build2 (INIT_EXPR, temp_type, object, tmp);
+ exp = cp_build_init_expr (object, tmp);
}
/* Mark any cleanups from the initialization as MUST_NOT_THROW, since
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 0ab0aaa..3d5d390 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -686,6 +686,8 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
/* Now put it back so C++17 copy elision works. */
init = get_target_expr (init);
+ set_target_expr_eliding (init);
+
current_class_ptr = save_ccp;
current_class_ref = save_ccr;
return init;
@@ -1006,7 +1008,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
if (TREE_CODE (type) == ARRAY_TYPE)
{
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
}
else
@@ -1014,7 +1016,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
tree value = build_value_init (type, tf_warning_or_error);
if (value == error_mark_node)
return;
- init = build2 (INIT_EXPR, type, decl, value);
+ init = cp_build_init_expr (decl, value);
finish_expr_stmt (init);
}
}
@@ -1025,7 +1027,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
{
if (init)
{
- init = build2 (INIT_EXPR, type, decl, TREE_VALUE (init));
+ init = cp_build_init_expr (decl, TREE_VALUE (init));
finish_expr_stmt (init);
}
}
@@ -1062,7 +1064,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
FOR_EACH_VEC_ELT (*cleanups, i, t)
push_cleanup (NULL_TREE, t, false);
@@ -1081,7 +1083,7 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
/* Initialize the array only if it's not a flexible
array member (i.e., if it has an upper bound). */
init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
+ init = cp_build_init_expr (decl, init);
finish_expr_stmt (init);
}
}
@@ -2097,7 +2099,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
complete objects. */
gcc_assert (TREE_CODE (init) == CONSTRUCTOR || true_exp == exp);
- init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
+ init = cp_build_init_expr (exp, init);
TREE_SIDE_EFFECTS (init) = 1;
finish_expr_stmt (init);
return true;
@@ -2136,8 +2138,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
TREE_TYPE (*p) = void_type_node;
p = &TREE_OPERAND (*p, 0);
}
- *p = build2 (INIT_EXPR, TREE_TYPE (exp), exp, *p);
- TREE_SIDE_EFFECTS (*p) = 1;
+ *p = cp_build_init_expr (exp, *p);
finish_expr_stmt (init);
return true;
}
@@ -2202,7 +2203,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
{
tree e = maybe_constant_init (rval, exp);
if (TREE_CONSTANT (e))
- rval = build2 (INIT_EXPR, type, exp, e);
+ rval = cp_build_init_expr (exp, e);
}
}
@@ -2290,7 +2291,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
field_size = TYPE_SIZE (CLASSTYPE_AS_BASE (type));
init = build_zero_init_1 (type, NULL_TREE, /*static_storage_p=*/false,
field_size);
- init = build2 (INIT_EXPR, type, exp, init);
+ init = cp_build_init_expr (exp, init);
finish_expr_stmt (init);
}
@@ -3678,7 +3679,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
tree val = build_value_init (type, complain | tf_no_cleanup);
if (val == error_mark_node)
return error_mark_node;
- init_expr = build2 (INIT_EXPR, type, init_expr, val);
+ init_expr = cp_build_init_expr (init_expr, val);
}
else
{
@@ -4430,7 +4431,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (BRACE_ENCLOSED_INITIALIZER_P (init))
init = digest_init (atype, init, complain);
- stmt_expr = build2 (INIT_EXPR, atype, base, init);
+ stmt_expr = cp_build_init_expr (base, init);
return stmt_expr;
}
@@ -4602,7 +4603,7 @@ build_vec_init (tree base, tree maxindex, tree init,
gcc_checking_assert (!target_expr_needs_replace (elt));
if (digested)
- one_init = build2 (INIT_EXPR, type, baseref, elt);
+ one_init = cp_build_init_expr (baseref, elt);
else if (tree vi = get_vec_init_expr (elt))
one_init = expand_vec_init_expr (baseref, vi, complain, flags);
else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
@@ -4623,7 +4624,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (do_static_init)
one_init = NULL_TREE;
else
- one_init = build2 (INIT_EXPR, type, baseref, e);
+ one_init = cp_build_init_expr (baseref, e);
}
else
{
@@ -4805,7 +4806,7 @@ build_vec_init (tree base, tree maxindex, tree init,
{
elt_init = build_value_init (type, complain);
if (elt_init != error_mark_node)
- elt_init = build2 (INIT_EXPR, type, to, elt_init);
+ elt_init = cp_build_init_expr (to, elt_init);
}
else
{
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 622e1b9..c217d7e 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -680,7 +680,7 @@ do_build_copy_constructor (tree fndecl)
else if (tree_int_cst_equal (TYPE_SIZE (current_class_type),
CLASSTYPE_SIZE (current_class_type)))
{
- tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
+ tree t = cp_build_init_expr (current_class_ref, parm);
finish_expr_stmt (t);
}
else
@@ -695,7 +695,7 @@ do_build_copy_constructor (tree fndecl)
current_class_ptr, alias_set);
tree rhs = build2 (MEM_REF, array_type,
TREE_OPERAND (parm, 0), alias_set);
- tree t = build2 (INIT_EXPR, void_type_node, lhs, rhs);
+ tree t = cp_build_init_expr (lhs, rhs);
finish_expr_stmt (t);
}
}
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 39b11ee..7d46c3c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2519,6 +2519,10 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
/* Update for array-to-pointer decay. */
type = TREE_TYPE (expr);
+ /* This TARGET_EXPR will initialize the outer one added by
+ finish_stmt_expr. */
+ set_target_expr_eliding (expr);
+
/* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a
normal statement, but don't convert to void or actually add
the EXPR_STMT. */
@@ -4668,7 +4672,7 @@ simplify_aggr_init_expr (tree *tp)
expand_call{,_inline}. */
cxx_mark_addressable (slot);
CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true;
- call_expr = build2 (INIT_EXPR, TREE_TYPE (call_expr), slot, call_expr);
+ call_expr = cp_build_init_expr (slot, call_expr);
}
else if (style == pcc)
{
@@ -4687,7 +4691,7 @@ simplify_aggr_init_expr (tree *tp)
{
tree init = build_zero_init (type, NULL_TREE,
/*static_storage_p=*/false);
- init = build2 (INIT_EXPR, void_type_node, slot, init);
+ init = cp_build_init_expr (slot, init);
call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (call_expr),
init, call_expr);
}
@@ -4882,7 +4886,7 @@ finalize_nrv_r (tree* tp, int* walk_subtrees, void* data)
tree init;
if (DECL_INITIAL (dp->var)
&& DECL_INITIAL (dp->var) != error_mark_node)
- init = build2 (INIT_EXPR, void_type_node, dp->result,
+ init = cp_build_init_expr (dp->result,
DECL_INITIAL (dp->var));
else
init = build_empty_stmt (EXPR_LOCATION (*tp));
@@ -6426,7 +6430,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
else
init = fold_convert (TREE_TYPE (v), integer_zero_node);
OMP_CLAUSE_REDUCTION_INIT (c)
- = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
+ = cp_build_init_expr (v, init);
}
}
}
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,
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index cecf825..b4a8e3c 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9294,7 +9294,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
if (! same_type_p (TREE_TYPE (rhs), lhstype))
/* Call convert to generate an error; see PR 11063. */
rhs = convert (lhstype, rhs);
- result = build2 (INIT_EXPR, lhstype, lhs, rhs);
+ result = cp_build_init_expr (lhs, rhs);
TREE_SIDE_EFFECTS (result) = 1;
goto ret;
}
@@ -9542,6 +9542,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
+ if (modifycode == INIT_EXPR)
+ set_target_expr_eliding (newrhs);
TREE_SIDE_EFFECTS (result) = 1;
if (!plain_assign)
@@ -11105,7 +11107,7 @@ check_return_expr (tree retval, bool *no_warning)
/* Actually copy the value returned into the appropriate location. */
if (retval && retval != result)
- retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval);
+ retval = cp_build_init_expr (result, retval);
if (tree set = maybe_set_retval_sentinel ())
retval = build2 (COMPOUND_EXPR, void_type_node, retval, set);
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index d5236d1..2644472 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -649,7 +649,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last,
else
{
build_init:
- code = build2 (INIT_EXPR, inner_type, sub, value);
+ code = cp_build_init_expr (sub, value);
}
code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code);
@@ -764,7 +764,7 @@ split_nonconstant_init (tree dest, tree init)
}
else if (init)
{
- tree ie = build2 (INIT_EXPR, void_type_node, dest, init);
+ tree ie = cp_build_init_expr (dest, init);
code = add_stmt_to_compound (ie, code);
}
}
@@ -773,7 +773,7 @@ split_nonconstant_init (tree dest, tree init)
code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false,
/*from array*/1, tf_warning_or_error);
else
- code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+ code = cp_build_init_expr (dest, init);
return code;
}
@@ -1464,6 +1464,7 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain)
&& CP_AGGREGATE_TYPE_P (type))
init = reshape_init (type, init, complain);
init = digest_init_flags (type, init, flags, complain);
+ set_target_expr_eliding (init);
/* We may have temporary materialization in a NSDMI, if the initializer
has something like A{} in it. Digesting the {} could have introduced
@@ -1542,6 +1543,7 @@ massage_init_elt (tree type, tree init, int nested, int flags,
tree t = fold_non_dependent_init (init, complain);
if (TREE_CONSTANT (t))
init = t;
+ set_target_expr_eliding (init);
}
return init;
}
@@ -1771,6 +1773,13 @@ process_init_constructor_record (tree type, tree init, int nested, int flags,
{
gcc_assert (ce->value);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ /* We can't actually elide the temporary when initializing a
+ potentially-overlapping field from a function that returns by
+ value. */
+ if (ce->index
+ && TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (ce->index, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
++idx;
}
}
@@ -1804,6 +1813,9 @@ process_init_constructor_record (tree type, tree init, int nested, int flags,
a class, just build one up; if it's an array, recurse. */
next = build_constructor (init_list_type_node, NULL);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ if (TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (field, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
/* Warn when some struct elements are implicitly initialized. */
if ((complain & tf_warning)
@@ -2727,3 +2739,41 @@ require_complete_eh_spec_types (tree fntype, tree decl)
}
}
}
+
+/* Record that any TARGET_EXPR in T are going to be elided in
+ cp_gimplify_init_expr (or sooner). */
+
+void
+set_target_expr_eliding (tree t)
+{
+ if (!t)
+ return;
+ switch (TREE_CODE (t))
+ {
+ case TARGET_EXPR:
+ TARGET_EXPR_ELIDING_P (t) = true;
+ break;
+ case COMPOUND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ break;
+ case COND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ set_target_expr_eliding (TREE_OPERAND (t, 2));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call the above in the process of building an INIT_EXPR. */
+
+tree
+cp_build_init_expr (location_t loc, tree target, tree init)
+{
+ set_target_expr_eliding (init);
+ tree ie = build2_loc (loc, INIT_EXPR, TREE_TYPE (target),
+ target, init);
+ TREE_SIDE_EFFECTS (ie) = true;
+ return ie;
+}