I don't think so, I'm concerned that it might eat the xobj parameter if
we do it that way. Besides, all we want is the lambda type anyway, I
don't want to build a whole new node just to do that. Upon further
consideration I think my solution does work and shouldn't cause
problems. The field that I'm using just doesn't get used anywhere else
for function_type nodes, and we create a new node in
tsubst_function_decl so we don't rely on that field anywhere after it's
used in tsubst_function_decl. I think I will null out the member,
consuming it, so that is clearly communicated.

I am still having issues trying to figure out where exactly to emit
errors from, it's really unclear how this stuff works during template
instantiation. I tried emitting conditionally based on the complain
parameter, but that seemed to suppress errors at all times. While at
the same time, I seemed to observe emitting errors unconditionally
(correctly) not not displaying the error when another candidate was
selected. This leads me to believe that there's already a mechanism for
discarding errors that occur during substitution. I don't really know
what to do for it, but surely I will figure it out now that I'm asking
for help, as tradition dictates.

The other problem I'm having is

auto f0 = [n = 5, &m](this auto const&){ n = 10; };
This errors just fine, the lambda is unconditionally const so
LAMBDA_EXPR_MUTABLE_P flag is set for the closure.

This on the other hand does not. The constness of the captures depends
on (I assume) LAMBDA_EXPR_MUTABLE_P so all the captures are non-const
here.
auto f1 = [n = 5](this auto&& self){ n = 10; };
as_const(f1)();

I don't know the right way to solve this, I haven't even really tracked
down where the tree is built up. At the moment I think that hacking
something into instantiate_body to make them const is the right
decision, as the type of the closure shouldn't be changing when
instantiating it's call operator template. I'm not sure this is really
actually the right call though because it's another thing that feels
very much like a hack. As I near completion of the patch it feels like
more and more of the solutions I'm finding are hacks, and I don't know
if it's just a consequence of old assumptions or if I'm really just
reaching for the easy(ier) solutions way too quickly now.

These problems are the last few that I have and they are taking me way
more time than I am comfortable with.

I was going to close out this message there but I just realized why
exactly you think erroring in instantiate_body is too late, it's
because at that point an error is an error, while if we error a little
bit earlier during substitution it's not a hard error. I'm glad I
realized this now, because I am much more confident in how to implement
the errors for unrelated type now. I'm still a little confused on what
the exact protocol for emitting errors at this stage is, as there
aren't many explicit errors written in. It seems to me like the errors
are supposed to be emitted when calling back into non-template stages
of the compiler with substituted types. It also seems like that hasn't
always been strictly followed, and I hate to contribute to code debt
but I'm not sure how I would do it in this case, nor if I actually have
a valid understanding of how this all works.

Given my above realization, I'm now more confident in figuring out how
exactly to implement the errors for unrelated types. I guess I'm rubber
ducking a little bit in these e-mails. On the other hand, if the
conclusions I'm forming are incorrect, it's probably still helpful to
know the journey I took to get to them. I'm thinking it's probably
better I still include my initial concerns even though I feel like I
know the answer now.

One side note before I close up here, I don't like when *_P macros are
used to set flags. Is this
something else we should clean up in the future? I'm beginning to
wonder if an overhaul that gets rid of the macros from the public
interface is a good idea. I'm reluctant to suggest that as I've really
warmed up to the macros a lot. They are used in a consistent and easy
to understand way which is highly unlike the bad uses of macros that
I've seen before that really obscure what's actually going on. But they
are still macros, so maybe moving away from them is the right call,
especially since there has started to be a mix-up of macros and
functions for the same purposes. I'm mildly of the opinion that only
one style should be used (in the public interface) because mixing them
causes confusion, it did for me anyway. Perhaps I should open a thread
on the general mail list and see what others think, get some input
before I decide which direction to go with it. To be clear, when I say
getting rid of macros, I want to emphasize I mean only in the public
interface, I don't see any value in getting rid of macros under the
hood as the way the checking macros are implemented is already really
good and works. It would only cause problems to try to move away from
that. I think I'll probably start to mess around with this idea as soon
as this patch is done.

That unrelated rambling aside, I will get back to work and try my best
to finish the errors for unrelated types today. It feels kind of bad to
work so hard on this since I've noticed that it's almost impossible to
coerce the case other than overload resolution when taking the address
of a lambdas operator. But that's not an excuse to leave a hole in the
compiler so, it's still gotta get done. I don't think I will get
rejection of mutation of captures done, especially since I'm uncertain
of what the right way to do it is, but maybe I'll work fast.


On Saturday, November 25th, 2023 at 10:32 AM, Jason Merrill <ja...@redhat.com> 
wrote:


> 
> 
> On 11/24/23 01:49, waffl3x wrote:
> 
> > > and this in tsubst_lambda_expr that assumes iobj:
> > > 
> > > /* Fix the type of 'this'. */
> > > fntype = build_memfn_type (fntype, type,
> > > type_memfn_quals (fntype),
> > > type_memfn_rqual (fntype));
> > 
> > Unfortunately, putting a condition on this had some unforeseen
> > consequences. I've been working on this about 8 hours today and I'm a
> > little defeated after discovering this.
> > 
> > commit 39ade88fa1632c659c5c4ed065fa2b62d16a8670
> > Author: Jason Merrill ja...@redhat.com
> > Date: Tue Jan 24 15:29:35 2023 -0500
> > 
> > c++: static lambda in template [PR108526]
> > 
> > tsubst_lambda_expr uses build_memfn_type to build a METHOD_TYPE for the new
> > lamba op(). This is not what we want for a C++23 static op(), but since we
> > also use that METHOD_TYPE to communicate the closure type down to
> > tsubst_function_decl, let's wait and turn it back at that point.
> > 
> > PR c++/108526
> > 
> > gcc/cp/ChangeLog:
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_function_decl): Handle static lambda.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp23/static-operator-call5.C: New test.
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 2a4d03c5e47..51fc246ed71 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -14306,6 +14306,11 @@ tsubst_function_decl (tree t, tree args, 
> > tsubst_flags_t complain,
> > tree ctx = closure ? closure : DECL_CONTEXT (t);
> > bool member = ctx && TYPE_P (ctx);
> > 
> > + /* If this is a static lambda, remove the 'this' pointer added in
> > + tsubst_lambda_expr now that we know the closure type. */
> > + if (lambda_fntype && DECL_STATIC_FUNCTION_P (t))
> > + lambda_fntype = static_fn_type (lambda_fntype);
> 
> 
> Ah, right. So the simplest thing would be to do the same thing here for
> xob lambdas.
> 
> Jason

Reply via email to