public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Patrick Palka <ppalka@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r12-1068] c++: constexpr and copy elision within mem init [PR100368]
Date: Wed, 26 May 2021 13:08:53 +0000 (GMT)	[thread overview]
Message-ID: <20210526130853.247BC3847808@sourceware.org> (raw)

https://gcc.gnu.org/g:88834c7d05acf5ce4eaccda56fb04436595e2a52

commit r12-1068-g88834c7d05acf5ce4eaccda56fb04436595e2a52
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed May 26 08:37:30 2021 -0400

    c++: constexpr and copy elision within mem init [PR100368]
    
    In the testcase below, the member initializer b(f()) inside C's default
    constructor is encoded as a TARGET_EXPR wrapping the CALL_EXPR f() in
    C++17 mode.  During massaging of this constexpr constructor,
    build_target_expr_with_type called from bot_manip on this initializer
    tries to add an extra copy using B's implicitly deleted copy constructor
    rather than just preserving the copy elision.
    
    Since it's wrong to introduce an extra copy when initializing a
    temporary from a CALL_EXPR, this patch makes build_target_expr_with_type
    avoid calling force_rvalue in this case.  Additionally, bot_manip should
    be copying TARGET_EXPRs in a more oblivious manner, so this patch makes
    bot_manip use force_target_expr instead of build_target_expr_with_type.
    And since bot_manip is now no longer a caller, we can remove the void
    initializer handling in build_target_expr_with_type.
    
            PR c++/100368
    
    gcc/cp/ChangeLog:
    
            * tree.c (build_target_expr_with_type): Don't call force_rvalue
            on CALL_EXPR initializer.  Simplify now that bot_manip is no
            longer a caller.
            (bot_manip): Use force_target_expr instead of
            build_target_expr_with_type.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp1z/elide6.C: New test.

Diff:
---
 gcc/cp/tree.c                       | 15 ++++++++-------
 gcc/testsuite/g++.dg/cpp1z/elide6.C | 16 ++++++++++++++++
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 72f498f4b3b..372d89fa9ed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -843,21 +843,22 @@ tree
 build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain)
 {
   gcc_assert (!VOID_TYPE_P (type));
+  gcc_assert (!VOID_TYPE_P (TREE_TYPE (init)));
 
   if (TREE_CODE (init) == TARGET_EXPR
       || init == error_mark_node)
     return init;
   else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type)
-	   && !VOID_TYPE_P (TREE_TYPE (init))
 	   && TREE_CODE (init) != COND_EXPR
 	   && TREE_CODE (init) != CONSTRUCTOR
-	   && TREE_CODE (init) != VA_ARG_EXPR)
-    /* We need to build up a copy constructor call.  A void initializer
-       means we're being called from bot_manip.  COND_EXPR is a special
+	   && TREE_CODE (init) != VA_ARG_EXPR
+	   && TREE_CODE (init) != CALL_EXPR)
+    /* We need to build up a copy constructor call.  COND_EXPR is a special
        case because we already have copies on the arms and we don't want
        another one here.  A CONSTRUCTOR is aggregate initialization, which
        is handled separately.  A VA_ARG_EXPR is magic creation of an
-       aggregate; there's no additional work to be done.  */
+       aggregate; there's no additional work to be done.  A CALL_EXPR
+       already creates a prvalue.  */
     return force_rvalue (init, complain);
 
   return force_target_expr (type, init, complain);
@@ -3112,8 +3113,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
 	    AGGR_INIT_ZERO_FIRST (TREE_OPERAND (u, 1)) = true;
 	}
       else
-	u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t),
-					 tf_warning_or_error);
+	u = force_target_expr (TREE_TYPE (t), TREE_OPERAND (t, 1),
+			       tf_warning_or_error);
 
       TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t);
       TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t);
diff --git a/gcc/testsuite/g++.dg/cpp1z/elide6.C b/gcc/testsuite/g++.dg/cpp1z/elide6.C
new file mode 100644
index 00000000000..399e1a9a1ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/elide6.C
@@ -0,0 +1,16 @@
+// PR c++/100368
+// { dg-do compile { target c++11 } }
+
+struct A {
+  A() = default;
+  A(const A&) = delete;
+};
+
+struct B { A a; }; // { dg-error "deleted" "" { target c++14_down } }
+
+constexpr B f() { return {}; }
+
+struct C {
+  constexpr C() : b(f()) {} // { dg-error "deleted" "" { target c++14_down } }
+  B b;
+};


                 reply	other threads:[~2021-05-26 13:08 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210526130853.247BC3847808@sourceware.org \
    --to=ppalka@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).