On Thu, 29 May 2025, Jason Merrill wrote: > Tested x86_64-pc-linux-gnu, applying to trunk. > > -- 8< -- > > Various places were still making assumptions that we could get to the 'this' > capture through current_class_ref in a lambda op(), which is incorrect for > an explicit object op(). > > PR c++/113563 > > gcc/cp/ChangeLog: > > * lambda.cc (build_capture_proxy): Check pointerness of the > member, not the proxy type. > (lambda_expr_this_capture): Don't assume current_class_ref. > (nonlambda_method_basetype): Likewise. > * semantics.cc (finish_non_static_data_member): Don't assume > TREE_TYPE (object) is set. > (finish_this_expr): Check current_class_type for lambda, > not current_class_ref. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp23/explicit-obj-lambda16.C: New test. > --- > gcc/cp/lambda.cc | 12 +++--- > gcc/cp/semantics.cc | 17 +++----- > .../g++.dg/cpp23/explicit-obj-lambda16.C | 39 +++++++++++++++++++ > 3 files changed, 50 insertions(+), 18 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C > > diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc > index a2bed9fb36a..34c7defb604 100644 > --- a/gcc/cp/lambda.cc > +++ b/gcc/cp/lambda.cc > @@ -442,7 +442,7 @@ build_capture_proxy (tree member, tree init) > > type = lambda_proxy_type (object); > > - if (name == this_identifier && !INDIRECT_TYPE_P (type)) > + if (name == this_identifier && !INDIRECT_TYPE_P (TREE_TYPE (member))) > { > type = build_pointer_type (type); > type = cp_build_qualified_type (type, TYPE_QUAL_CONST); > @@ -921,8 +921,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p) > else > { > /* To make sure that current_class_ref is for the lambda. */ > - gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) > - == LAMBDA_EXPR_CLOSURE (lambda)); > + gcc_assert (!current_class_ref > + || (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) > + == LAMBDA_EXPR_CLOSURE (lambda))); > > result = this_capture; > > @@ -1037,12 +1038,9 @@ current_nonlambda_function (void) > tree > nonlambda_method_basetype (void) > { > - if (!current_class_ref) > - return NULL_TREE; > - > tree type = current_class_type; > if (!type || !LAMBDA_TYPE_P (type)) > - return type; > + return current_class_ref ? type : NULL_TREE; > > while (true) > {
Looks like this nonlambda_method_basetype change fixes the 12+ regression PR120123! (where current_class_ref is empty during satisfaction due to push_to_top_level, so we fail to resolve an implicit 'this' use despite being in the scope of a this-capturing lambda.) > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 241f2730878..1279d78b186 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -2770,7 +2770,7 @@ finish_non_static_data_member (tree decl, tree object, > tree qualifying_scope, > else if (PACK_EXPANSION_P (type)) > /* Don't bother trying to represent this. */ > type = NULL_TREE; > - else if (WILDCARD_TYPE_P (TREE_TYPE (object))) > + else if (!TREE_TYPE (object) || WILDCARD_TYPE_P (TREE_TYPE (object))) > /* We don't know what the eventual quals will be, so punt until > instantiation time. > > @@ -3605,16 +3605,11 @@ finish_this_expr (void) > { > tree result = NULL_TREE; > > - if (current_class_ptr) > - { > - tree type = TREE_TYPE (current_class_ref); > - > - /* In a lambda expression, 'this' refers to the captured 'this'. */ > - if (LAMBDA_TYPE_P (type)) > - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type), > true); > - else > - result = current_class_ptr; > - } > + if (current_class_type && LAMBDA_TYPE_P (current_class_type)) > + result = (lambda_expr_this_capture > + (CLASSTYPE_LAMBDA_EXPR (current_class_type), /*add*/true)); > + else if (current_class_ptr) > + result = current_class_ptr; > > if (result) > /* The keyword 'this' is a prvalue expression. */ > diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C > b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C > new file mode 100644 > index 00000000000..69936388969 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C > @@ -0,0 +1,39 @@ > +// PR c++/113563 > +// { dg-do compile { target c++23 } } > + > +struct S { > + int x_; > + void f() { > + [this](this auto) { > + this->x_ = 42; > + return this; > + }(); > + } > +}; > + > +struct R { > + int x; > + > + auto foo() { > + return [*this](this auto &self) { > + this->x = 4; > + }; > + } > +}; > + > + > +struct A > +{ > + int n; > + void fun() > + { > + auto _ = [&](this auto self) { return n; }; > + } > +}; > + > +struct B { > + int i = 42; > + int foo() { > + return [this](this auto &&self) { auto p = &i; return *p; }(); > + } > +}; > > base-commit: 5c6364b09a67de8d2237f65016ea1e3365a76e8d > -- > 2.49.0 > >