On Sat, 7 Feb 2026, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
> look OK for stage1 perhaps?
> 
> FWIW I couldn't get a structured binding (which are also implemented via
> DECL_VALUE_EXPR) testcase to misbehave, because for e.g.
> 
>   template<class T>
>   void f(T t) {
>     auto [x,y] = t;
>     ...
>   }
> 
> we lower it to:
> 
>   struct A D.2730;
>   int x [value-expr: D.2730.n];
>   int y [value-expr: D.2730.m];
>   ...
>   A::A (&D.2730, t);
> 
> i.e. the value-exprs are in terms of a local copy of the invisiref parm
> so they don't need adjustment.  Whereas for this PR the value-exprs are
> directly in terms of the invisiref parm.
> 
> For auto& [x,y] = t; we do:
> 
>   struct A & D.2720;
>   int x [value-expr: D.2720->n];
>   int y [value-expr: D.2720->m];
>   D.2720 = t;
> 
> -- >8 --
> 
> 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()::<lambda(this auto:1)>::operator()<main()::<lambda(this 
> auto:1)> > (struct ._anon_0 & self)
>   {
>     bool D.3091;
>     struct ._anon_0 & self.1;
>     struct A data [value-expr: self.__data]; // should be self->__data
> 
>     self.1 = self;
>     _1 = self.1.__data.n; // same

BTW this might be something the gimplifier could sanity check?
(i.e. the LHS of a COMPONENT_REF should never be a pointer/reference)

>     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.
> 
>       PR c++/121500
> 
> gcc/cp/ChangeLog:
> 
>       * cp-gimplify.cc (cp_genericize_r): Walk DECL_VALUE_EXPR.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp23/explicit-obj-lambda20.C: New test.
> ---
>  gcc/cp/cp-gimplify.cc                            | 10 ++++++++++
>  .../g++.dg/cpp23/explicit-obj-lambda20.C         | 16 ++++++++++++++++
>  2 files changed, 26 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 9d96ce99ea92..11fa6cff40ba 100644
> --- a/gcc/cp/cp-gimplify.cc
> +++ b/gcc/cp/cp-gimplify.cc
> @@ -1914,6 +1914,16 @@ 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)
> +    if (tree ve = DECL_VALUE_EXPR (stmt))
> +      {
> +     cp_walk_tree (&ve, cp_genericize_r, data, NULL);
> +     SET_DECL_VALUE_EXPR (stmt, ve);
> +     p_set->add (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 000000000000..f55b4b78b96e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda20.C
> @@ -0,0 +1,16 @@
> +// 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() {
> +   auto l = [data = A()](this auto self) {
> +     return data.n == 42;
> +   };
> +   if (!l())
> +     __builtin_abort();
> +}
> -- 
> 2.53.0.40.g3e0db84c88
> 
> 

Reply via email to