]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: xobj lambda 'this' capture [PR113563]
authorJason Merrill <jason@redhat.com>
Thu, 29 May 2025 16:36:23 +0000 (12:36 -0400)
committerJason Merrill <jason@redhat.com>
Thu, 29 May 2025 20:21:17 +0000 (16:21 -0400)
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
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda16.C [new file with mode: 0644]

index a2bed9fb36aaec870c078cdabac29229e3998067..34c7defb60499bd781490a4666d35d5d78bbb858 100644 (file)
@@ -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)
     {
index 241f2730878b74822cbe7f47fa677782c2615d5d..1279d78b18682b3b7f793cc60cb00674b03bce82 100644 (file)
@@ -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 (file)
index 0000000..6993638
--- /dev/null
@@ -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; }();
+  }
+};