From 24f012160c856e560b8e7fcd4ea9d51863fecebb Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sun, 15 Feb 2026 12:36:38 -0500 Subject: [PATCH] c++: non-trivial by-value deducing this lambda [PR121500] Here the lambda has a by-value capture of non-trivial type, which in turn makes the closure type non-trivial. This means its by-value 'this' parameter, which gets deduced to the closure type, becomes an invisiref parameter, and so when lowering the operator() body we need to adjust uses of 'this' by adding implicit dereferences. But the GIMPLE dump for operator() shows that we miss some adjustments: bool main()::::operator() > (struct ._anon_0 & self) { bool D.3091; struct ._anon_0 & self.1; struct A a [value-expr: self.__a]; // should be self->__a self.1 = self; _1 = self.1.__a.n; // should be self.1->__a D.3091 = _1 == 42; return D.3091; } Apparently this is because cp_genericize_r, which is responsible for the invisiref use adjustments, never walks DECL_VALUE_EXPR. This patch makes us walk it. For GCC 16, restrict the walking to xobj lambdas. PR c++/121500 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_genericize_r): Walk DECL_VALUE_EXPR within an xobj lambda. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-lambda20.C: New test. Reviewed-by: Jason Merrill --- gcc/cp/cp-gimplify.cc | 16 ++++++++++++++++ .../g++.dg/cpp23/explicit-obj-lambda20.C | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda20.C diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index cf25cbe2eef..eb30d780d6c 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1922,6 +1922,22 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) return NULL_TREE; } + if ((TREE_CODE (stmt) == VAR_DECL + || TREE_CODE (stmt) == PARM_DECL + || TREE_CODE (stmt) == RESULT_DECL) + && DECL_HAS_VALUE_EXPR_P (stmt) + /* Walk DECL_VALUE_EXPR mainly for benefit of xobj lambdas so that we + adjust any invisiref object parm uses within the capture proxies. + TODO: For GCC 17 do this walking unconditionally. */ + && current_function_decl + && DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl) + && LAMBDA_FUNCTION_P (current_function_decl)) + { + tree ve = DECL_VALUE_EXPR (stmt); + cp_walk_tree (&ve, cp_genericize_r, data, NULL); + SET_DECL_VALUE_EXPR (stmt, ve); + } + switch (TREE_CODE (stmt)) { case ADDR_EXPR: diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda20.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda20.C new file mode 100644 index 00000000000..4274ff02b76 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda20.C @@ -0,0 +1,17 @@ +// PR c++/121500 +// { dg-do run { target c++23 } } + +struct A { + A() = default; + A(const A& other) : n(other.n) { } + int n = 42; +}; + +int main() { + A a; + auto l = [a](this auto self) { + return a.n == 42; + }; + if (!l()) + __builtin_abort(); +} -- 2.47.3