public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Patrick Palka <ppalka@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: Jason Merrill <jason@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: constexpr init of union sub-aggr w/ base [PR105491]
Date: Fri, 6 May 2022 16:10:30 -0400 (EDT)	[thread overview]
Message-ID: <660ef433-cb10-e137-e734-5fbf3223a39f@idea> (raw)
In-Reply-To: <e5f2e52e-acd5-7948-8eff-b05ab6b4d870@idea>

On Fri, 6 May 2022, Patrick Palka wrote:

> On Fri, 6 May 2022, Jason Merrill wrote:
> 
> > On 5/6/22 14:00, Patrick Palka wrote:
> > > On Fri, 6 May 2022, Patrick Palka wrote:
> > > 
> > > > On Fri, 6 May 2022, Jason Merrill wrote:
> > > > 
> > > > > On 5/6/22 11:22, Patrick Palka wrote:
> > > > > > Here ever since r10-7313-gb599bf9d6d1e18,
> > > > > > reduced_constant_expression_p
> > > > > > in C++11/14 is rejecting the marked sub-aggregate initializer (of type
> > > > > > S)
> > > > > > 
> > > > > >     W w = {.D.2445={.s={.D.2387={.m=0}, .b=0}}}
> > > > > >                        ^
> > > > > > 
> > > > > > ultimately because said initializer has CONSTRUCTOR_NO_CLEARING set,
> > > > > > and
> > > > > > so the function proceeds to verify that all fields of S are
> > > > > > initialized.
> > > > > > And before C++17 we don't expect to see base class fields (since
> > > > > > next_initializable_field skips over the), so the base class
> > > > > > initializer
> > > > > > causes r_c_e_p to return false.
> > > > > 
> > > > > That seems like the primary bug.  I guess r_c_e_p shouldn't be using
> > > > > next_initializable_field.  Really that function should only be used for
> > > > > aggregates.
> > > > 
> > > > I see, I'll try replacing it in r_c_e_p.  Would that be in addition to
> > > > or instead of the clear_no_implicit_zero approach?
> > > 
> > > I'm testing the following, which uses a custom predicate instead of
> > > next_initializable_field in r_c_e_p.
> > 
> > Let's make it a public predicate, not internal to r_c_e_p.  Maybe it could be
> > next_subobject_field, and the current next_initializable_field change to
> > next_aggregate_field?
> 
> Will do.
> 
> > 
> > > Looks like the inner initializer {.D.2387={.m=0}, .b=0} is formed during
> > > the subobject constructor call:
> > > 
> > >   V::V (&((struct S *) this)->D.2120);
> > > 
> > > after the evaluation of which, 'result' in cxx_eval_call_expression is NULL
> > > (presumably because it's a CALL_EXPR, not AGGR_INIT_EXPR?):
> > > 
> > >   /* This can be null for a subobject constructor call, in
> > >      which case what we care about is the initialization
> > >      side-effects rather than the value.  We could get at the
> > >      value by evaluating *this, but we don't bother; there's
> > >      no need to put such a call in the hash table.  */
> > >   result = lval ? ctx->object : ctx->ctor;
> > > 
> > > so we end up not calling clear_no_implicit_zero for the inner initializer
> > > directly.  We only call clear_no_implicit_zero after evaluating the
> > > AGGR_INIT_EXPR for outermost initializer (of type W).
> > 
> > Maybe for constructors we could call it on ctx->ctor instead of result, or
> > call r_c_e_p in C++20+?
> 
> But both ctx->ctor and ->object are NULL during a subobject constructor
> call (since we apparently clear these fields when entering a
> STATEMENT_LIST):
> 
> So I tried instead obtaining the constructor by evaluating new_obj via
> 
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -2993,6 +2988,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>       in order to detect reading an unitialized object in constexpr instead
>       of value-initializing it.  (reduced_constant_expression_p is expected to
>       take care of clearing the flag.)  */
> +  if (new_obj && DECL_CONSTRUCTOR_P (fun))
> +    result = cxx_eval_constant_expression (ctx, new_obj, /*lval=*/false,
> +                                          non_constant_p, overflow_p);
>    if (TREE_CODE (result) == CONSTRUCTOR
>        && (cxx_dialect < cxx20
>           || !DECL_CONSTRUCTOR_P (fun)))
> 
> but that seems to break e.g. g++.dg/cpp2a/constexpr-init12.C because
> after the subobject constructor call
> 
>   S::S (&((struct W *) this)->s, NON_LVALUE_EXPR <8>);
> 
> the constructor for the subobject a.s in new_obj is still completely
> missing (I suppose because S::S doesn't initialize any of its members)
> so trying to obtain it causes us to complain too soon from
> cxx_eval_component_reference:
> 
> constexpr-init12.C:16:24:   in ‘constexpr’ expansion of ‘W(42)’
> constexpr-init12.C:10:22:   in ‘constexpr’ expansion of ‘((W*)this)->W::s.S::S(8)’
> constexpr-init12.C:16:24: error: accessing uninitialized member ‘W::s’
>    16 | constexpr auto a = W(42); // { dg-error "not a constant expression" }
>       |                        ^
> 
> > 
> > It does seem dubious that we would clear the flag on an outer ctor when it's
> > still set on an inner ctor, should probably add an assert somewhere.
> 
> Makes sense, not sure where the best place would be..

On second thought, if I'm understanding your suggestion correctly, I
don't think we can generally enforce such a property for
CONSTRUCTOR_NO_CLEARING, given how cxx_eval_store_expression uses it for
unions:

  union U {
    struct { int x, y; } a;
  } u;
  u.a.x = 0;

Here after evaluating the assignment, the outer ctor for the union will
have CONSTRUCTOR_NO_CLEARING cleared to indicate we finished activating
the union member, but the inner ctor is certainly not fully initialized
so it'll have CONSTRUCTOR_NO_CLEARING set still.

> 
> > 
> > Jason
> > 
> > 

  reply	other threads:[~2022-05-06 20:10 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-06 15:22 Patrick Palka
2022-05-06 15:56 ` Jason Merrill
2022-05-06 16:04   ` Marek Polacek
2022-05-06 16:40   ` Patrick Palka
2022-05-06 18:00     ` Patrick Palka
2022-05-06 18:22       ` Jason Merrill
2022-05-06 19:24         ` Patrick Palka
2022-05-06 20:10           ` Patrick Palka [this message]
2022-05-06 20:27             ` Jason Merrill
2022-05-06 20:46               ` Patrick Palka
2022-05-07 21:18                 ` Jason Merrill
2022-05-17 16:34                   ` Patrick Palka
2022-05-18 14:22                     ` Jason Merrill
2022-05-31 16:41                       ` Patrick Palka
2022-05-31 19:06                         ` Jason Merrill

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=660ef433-cb10-e137-e734-5fbf3223a39f@idea \
    --to=ppalka@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@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).