https://gcc.gnu.org/g:2047aa4ce2ed9976fb36e984b43864fcd6f3a65d
commit r16-970-g2047aa4ce2ed9976fb36e984b43864fcd6f3a65d Author: Jason Merrill <ja...@redhat.com> Date: Thu May 29 12:36:23 2025 -0400 c++: xobj lambda 'this' capture [PR113563] 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. Diff: --- gcc/cp/lambda.cc | 12 +++---- gcc/cp/semantics.cc | 17 ++++------ gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C | 39 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index a2bed9fb36aa..34c7defb6049 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) { diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 241f2730878b..1279d78b1868 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 000000000000..69936388969c --- /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; }(); + } +};