public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jason Merrill <jason@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: constexpr and copy elision within mem init [PR100368]
Date: Tue, 25 May 2021 16:38:06 -0400	[thread overview]
Message-ID: <e0addb36-b2bd-5bf8-9d20-96407b514578@redhat.com> (raw)
In-Reply-To: <74bc6d79-ccc-996c-130-7f94aea95fb1@idea>

On 5/25/21 1:12 PM, Patrick Palka wrote:
> On Mon, 24 May 2021, Jason Merrill wrote:
> 
>> On 5/24/21 1:48 PM, Patrick Palka wrote:
>>> In the testcase below, the initializer for C::b 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 ends up trying to use
>>> B's implicitly deleted copy constructor rather than preserving the
>>> copy elision.
>>
>>> This patch makes bot_manip use force_target_expr instead of
>>> build_target_expr_with_type so that it copies TARGET_EXPRs in a more
>>> oblivious manner.
>>
>> Even with that change we should fix build_target_expr_with_type to handle
>> CALL_EXPR properly; adding an extra copy is just wrong.
> 
> Sounds good.
> 
>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
>>> for trunk?
>>>
>>> 	PR c++/100368
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* tree.c (build_target_expr_with_type): 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.
>>> ---
>>>    gcc/cp/tree.c                       |  8 +++-----
>>>    gcc/testsuite/g++.dg/cpp1z/elide6.C | 16 ++++++++++++++++
>>>    2 files changed, 19 insertions(+), 5 deletions(-)
>>>    create mode 100644 gcc/testsuite/g++.dg/cpp1z/elide6.C
>>>
>>> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
>>> index 72f498f4b3b..84b84621d35 100644
>>> --- a/gcc/cp/tree.c
>>> +++ b/gcc/cp/tree.c
>>> @@ -848,12 +848,10 @@ build_target_expr_with_type (tree init, tree type,
>>> tsubst_flags_t complain)
>>>          || 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.
>>
>> In general, a void initializer for a TARGET_EXPR means that the initialization
>> is more complex than initializing the object from the value of the expression.
>> The caller would need to handle making that initialization apply to the new
>> TARGET_EXPR_SLOT (and bot_manip does). If we change bot_manip to not call this
>> function, I think this function should reject void init.
> 
> I see, thanks.  How does the following look for trunk?  Bootstrapped and
> regetested on x86_64-pc-linux-gnu.
> 
> -- >8 --
> 
> 
> Subject: [PATCH] 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 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 and instead reject
> such initializers.
> 
> 	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.
> ---
>   gcc/cp/tree.c                       | 12 ++++++------
>   gcc/testsuite/g++.dg/cpp1z/elide6.C | 16 ++++++++++++++++
>   2 files changed, 22 insertions(+), 6 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/elide6.C
> 
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index 72f498f4b3b..d97b220423d 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -843,17 +843,17 @@ 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

Let's add "A CALL_EXPR already creates a prvalue." to this comment.  OK 
with that.

> @@ -3112,8 +3112,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-25 20:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-24 17:48 Patrick Palka
2021-05-24 21:31 ` Jason Merrill
2021-05-25 17:12   ` Patrick Palka
2021-05-25 20:38     ` Jason Merrill [this message]

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=e0addb36-b2bd-5bf8-9d20-96407b514578@redhat.com \
    --to=jason@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=ppalka@redhat.com \
    /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).