On Wed, 1 May 2024, Jason Merrill wrote:

> On 4/12/24 13:22, Patrick Palka wrote:
> > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > 
> > > On 3/26/24 09:44, Patrick Palka wrote:
> > > > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > > > 
> > > > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > > > 
> > > > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does
> > > > > > > > > > > this
> > > > > > > > > > > look
> > > > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, but
> > > > > > > > > > > at
> > > > > > > > > > > least
> > > > > > > > > > > it safely fixes these testcases I guess.  Note that
> > > > > > > > > > > there's
> > > > > > > > > > > implementation disagreement about the second testcase, GCC
> > > > > > > > > > > always
> > > > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > > > 
> > > > > > > > > > Because of trying to initialize int& from {c}; removing the
> > > > > > > > > > extra
> > > > > > > > > > braces
> > > > > > > > > > makes it work everywhore.
> > > > > > > > > > 
> > > > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we
> > > > > > > > > > always
> > > > > > > > > > generate a
> > > > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate if
> > > > > > > > > > the
> > > > > > > > > > initializer is an init-list?
> > > > > > > > > 
> > > > > > > > > ...but it seems bad to silently bind a const int& to a prvalue
> > > > > > > > > instead
> > > > > > > > > of
> > > > > > > > > directly to the reference returned by the operator, as clang
> > > > > > > > > does
> > > > > > > > > if
> > > > > > > > > we add
> > > > > > > > > const to the second testcase, so I think there's a defect in
> > > > > > > > > the
> > > > > > > > > standard
> > > > > > > > > here.
> > > > > > > > 
> > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > reference-related to E <ins>or scalar</ins>, ..."
> > > > > > > > 
> > > > > > > > > Maybe for now also disable the maybe_valid heuristics in the
> > > > > > > > > case
> > > > > > > > > of
> > > > > > > > > an
> > > > > > > > > init-list?
> > > > > > > > > 
> > > > > > > > > > The first testcase is special because it's a C-style cast;
> > > > > > > > > > seems
> > > > > > > > > > like the
> > > > > > > > > > maybe_valid = false heuristics should be disabled if
> > > > > > > > > > c_cast_p.
> > > > > > > 
> > > > > > > Thanks a lot for the pointers.  IIUC c_cast_p and
> > > > > > > LOOKUP_SHORTCUT_BAD_CONVS
> > > > > > > should already be mutually exclusive, since the latter is set only
> > > > > > > when
> > > > > > > computing argument conversions, so it shouldn't be necessary to
> > > > > > > check
> > > > > > > c_cast_p.
> > > > > > > 
> > > > > > > I suppose we could disable the heuristic for init-lists, but after
> > > > > > > some
> > > > > > > digging I noticed that the heuristics were originally in same spot
> > > > > > > they
> > > > > > > are now until r5-601-gd02f620dc0bb3b moved them to get checked
> > > > > > > after
> > > > > > > the recursive recalculation case in reference_binding, returning a
> > > > > > > bad
> > > > > > > conversion instead of NULL.  (Then in r13-1755-g68f37670eff0b872 I
> > > > > > > moved
> > > > > > > them back; IIRC that's why I felt confident that moving the checks
> > > > > > > was
> > > > > > > safe.)
> > > > > > > Thus we didn't always accept the second testcase, we only started
> > > > > > > doing so
> > > > > > > in
> > > > > > > GCC 5: https://godbolt.org/z/6nsEW14fh (sorry for missing this and
> > > > > > > saying
> > > > > > > we
> > > > > > > always accepted it)
> > > > > > > 
> > > > > > > And indeed the current order of checks seems consistent with that
> > > > > > > of
> > > > > > > [dcl.init.ref]/5.  So I wonder if we don't instead want to
> > > > > > > "complete"
> > > > > > > the NULL-to-bad-conversion adjustment in r5-601-gd02f620dc0bb3b
> > > > > > > and
> > > > > > > do:
> > > > > > > 
> > > > > > > gcc/cp/ChangeLog:
> > > > > > > 
> > > > > > >   * call.cc (reference_binding): Set bad_p according to
> > > > > > >   maybe_valid_p in the recursive case as well.  Remove
> > > > > > >   redundant gcc_assert.
> > > > > > > 
> > > > > > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > > > > > > index 9de0d77c423..c4158b2af37 100644
> > > > > > > --- a/gcc/cp/call.cc
> > > > > > > +++ b/gcc/cp/call.cc
> > > > > > > @@ -2033,8 +2033,8 @@ reference_binding (tree rto, tree rfrom,
> > > > > > > tree
> > > > > > > expr,
> > > > > > > bool c_cast_p, int flags,
> > > > > > >                                      sflags, complain);
> > > > > > >               if (!new_second)
> > > > > > >                 return bad_direct_conv ? bad_direct_conv :
> > > > > > > nullptr;
> > > > > > > +     t->bad_p = !maybe_valid_p;
> > > > > > 
> > > > > > Oops, that should be |= not =.
> > > > > > 
> > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > reference-related to E <ins>or scalar</ins>, ..."
> > > > > > >               conv = merge_conversion_sequences (t, new_second);
> > > > > > > -     gcc_assert (maybe_valid_p || conv->bad_p);
> > > > > > >               return conv;
> > > > > > >             }
> > > > > > >         }
> > > > > > > 
> > > > > > > This'd mean we'd go back to rejecting the second testcase (only
> > > > > > > the
> > > > > > > call, not the direct-init, interestingly enough), but that seems
> > > > > > > to be
> > > > > > 
> > > > > > In the second testcase, with the above fix initialize_reference
> > > > > > silently
> > > > > > returns error_mark_node for the direct-init without issuing a
> > > > > > diagnostic, because in the error path convert_like doesn't find
> > > > > > anything
> > > > > > wrong with the bad conversion.  So more changes need to be made if
> > > > > > we
> > > > > > want to set bad_p in the recursive case of reference_binding it
> > > > > > seems;
> > > > > > dunno if that's the path we want to go down?
> > > > > > 
> > > > > > On the other hand, disabling the badness checks in certain cases
> > > > > > seems
> > > > > > to be undesirable as well, since AFAICT their current position is
> > > > > > consistent with [dcl.init.ref]/5?
> > > > > > 
> > > > > > So I wonder if we should just go with the safest thing at this
> > > > > > stage,
> > > > > > which would be the original patch that removes the problematic
> > > > > > assert?
> > > > > 
> > > > > I still think the assert is correct, and the problem is that
> > > > > maybe_valid_p
> > > > > is
> > > > > wrong; these cases turn out to be valid, so maybe_valid_p should be
> > > > > true.
> > > > 
> > > > I'm afraid then I don't know how we can statically identify these cases
> > > > without actually performing the conversion, in light of the recursion :/
> > > > Do you mind taking this PR?  I don't feel well-versed enough with the
> > > > reference binding rules to tackle this adequately..
> > > 
> > > That ended up being a surprisingly deep dive, but I've now checked in
> > > separate
> > > fixes for the two cases.
> > 
> > Very interesting, thanks a lot.
> 
> ...but I don't think my fixes are suitable for GCC 13, so would you apply your
> original patch to the 13 branch?

Will do

> 
> Jason
> 
> 

Reply via email to