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
> 
> 

Reply via email to