From: Jason Merrill Date: Wed, 13 Jan 2021 18:27:06 +0000 (-0500) Subject: c++: Avoid redundant copy in {} init [PR98642] X-Git-Tag: releases/gcc-10.3.0~352 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=506fcfdb12562e829448e2b2eff475c65986e26b;p=thirdparty%2Fgcc.git c++: Avoid redundant copy in {} init [PR98642] Here, initializing from { } implies a call to the default constructor for base. We were then seeing that we're initializing a base subobject, so we tried to copy the result of that call. This is clearly wrong; we should initialize the base directly from its default constructor. gcc/cp/ChangeLog: PR c++/98642 * typeck2.c (split_nonconstant_init_1): Don't copy a list-init constructor call. gcc/testsuite/ChangeLog: PR c++/98642 * g++.dg/cpp1z/elide5.C: New test. --- diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index c3b29cec1adb..2fc6081557f2 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -706,17 +706,31 @@ split_nonconstant_init_1 (tree dest, tree init, bool nested) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); + /* We may need to add a copy constructor call if + the field has [[no_unique_address]]. */ if (unsafe_return_slot_p (sub)) { - /* We may need to add a copy constructor call if - the field has [[no_unique_address]]. */ + /* But not if the initializer is an implicit ctor call + we just built in digest_init. */ + if (TREE_CODE (value) == TARGET_EXPR + && TARGET_EXPR_LIST_INIT_P (value)) + { + tree init = TARGET_EXPR_INITIAL (value); + if (init && TREE_CODE (init) == AGGR_INIT_EXPR + && AGGR_INIT_VIA_CTOR_P (init)) + goto build_init; + } + releasing_vec args = make_tree_vector_single (value); code = build_special_member_call (sub, complete_ctor_identifier, &args, inner_type, LOOKUP_NORMAL, tf_warning_or_error); } else - code = build2 (INIT_EXPR, inner_type, sub, value); + { + build_init: + code = build2 (INIT_EXPR, inner_type, sub, value); + } code = build_stmt (input_location, EXPR_STMT, code); code = maybe_cleanup_point_expr_void (code); add_stmt (code); diff --git a/gcc/testsuite/g++.dg/cpp1z/elide5.C b/gcc/testsuite/g++.dg/cpp1z/elide5.C new file mode 100644 index 000000000000..abe80ec0bc43 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/elide5.C @@ -0,0 +1,15 @@ +// PR c++/98642 +// { dg-do compile { target c++11 } } + +struct base { + base(void) {} + base(base &&) = delete; +}; + +struct foo : public base { }; + +static foo c1 { }; + +#if __cpp_aggregate_bases +static foo c2 { {} }; +#endif