]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Avoid redundant copy in {} init [PR98642]
authorJason Merrill <jason@redhat.com>
Wed, 13 Jan 2021 18:27:06 +0000 (13:27 -0500)
committerJason Merrill <jason@redhat.com>
Fri, 29 Jan 2021 16:00:00 +0000 (11:00 -0500)
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.

gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp1z/elide5.C [new file with mode: 0644]

index c3b29cec1adb6218d00f819ecfe7e60818a71107..2fc6081557f2ecf8ab6653ba5c7b9b53ccc2c392 100644 (file)
@@ -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 (file)
index 0000000..abe80ec
--- /dev/null
@@ -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