[clang] [C++20][Coroutines] lambda-coroutine with promise_type ctor. (PR #84519)

Andreas Fertig via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 8 22:50:25 PST 2024


https://github.com/andreasfertig updated https://github.com/llvm/llvm-project/pull/84519

>From 3083833f9e87947c7e45c5ed5bd6a983294717c9 Mon Sep 17 00:00:00 2001
From: Andreas Fertig <andy at cppinsights.io>
Date: Fri, 8 Mar 2024 17:49:15 +0100
Subject: [PATCH] [C++20][Coroutines] lambda-coroutine with promise_type ctor.

This is a follow-up of #84064. It turned out that a coroutine-lambda
with a `promise_type` and a user-defined constructor ignores the `this`
pointer. Per http://eel.is/c++draft/dcl.fct.def.coroutine#4, in such a
case, the first parameter to the constructor is an lvalue of `*this`.
---
 clang/lib/Sema/SemaCoroutine.cpp              | 19 ++++-
 .../SemaCXX/coroutine-promise-ctor-lambda.cpp | 71 +++++++++++++++++++
 ...tine-promise-ctor-static-callop-lambda.cpp | 47 ++++++++++++
 3 files changed, 134 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/SemaCXX/coroutine-promise-ctor-lambda.cpp
 create mode 100644 clang/test/SemaCXX/cxx23-coroutine-promise-ctor-static-callop-lambda.cpp

diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 301a5ff72a3b2a..fd8eb81ba55fa4 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -596,8 +596,21 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
 
   // Add implicit object parameter.
   if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
-    if (MD->isImplicitObjectMemberFunction() && !isLambdaCallOperator(MD)) {
-      ExprResult ThisExpr = ActOnCXXThis(Loc);
+    if (MD->isImplicitObjectMemberFunction()) {
+      ExprResult ThisExpr{};
+
+      if (isLambdaCallOperator(MD) && !MD->isStatic()) {
+        Qualifiers ThisQuals = MD->getMethodQualifiers();
+        CXXRecordDecl *Record = MD->getParent();
+
+        Sema::CXXThisScopeRAII ThisScope(*this, Record, ThisQuals,
+                                         /*Enabled=*/Record != nullptr);
+
+        ThisExpr = ActOnCXXThis(Loc, /*ThisRefersToClosureObject=*/true);
+      } else {
+        ThisExpr = ActOnCXXThis(Loc);
+      }
+
       if (ThisExpr.isInvalid())
         return nullptr;
       ThisExpr = CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
@@ -1387,7 +1400,7 @@ static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
         CXXRecordDecl *Record = MD->getParent();
 
         Sema::CXXThisScopeRAII ThisScope(S, Record, ThisQuals,
-                                         Record != nullptr);
+                                         /*Enabled=*/Record != nullptr);
 
         ThisExpr = S.ActOnCXXThis(Loc, /*ThisRefersToClosureObject=*/true);
       } else {
diff --git a/clang/test/SemaCXX/coroutine-promise-ctor-lambda.cpp b/clang/test/SemaCXX/coroutine-promise-ctor-lambda.cpp
new file mode 100644
index 00000000000000..92e9a006c3a8d9
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-promise-ctor-lambda.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -I%S/Inputs -std=c++20 %s
+
+// expected-no-diagnostics
+
+#include "std-coroutine.h"
+
+using size_t = decltype(sizeof(0));
+
+struct Generator {
+  struct promise_type {
+    int _val{};
+
+    Generator get_return_object() noexcept
+    {
+      return {};
+    }
+
+    std::suspend_never initial_suspend() noexcept
+    {
+      return {};
+    }
+
+    std::suspend_always final_suspend() noexcept
+    {
+      return {};
+    }
+
+    void return_void() noexcept {}
+    void unhandled_exception() noexcept {}
+
+    template<typename This, typename... TheRest>
+    promise_type(This&,
+                 TheRest&&...)
+    {
+    }
+  };
+};
+
+struct CapturingThisTest
+{
+    int x{};
+
+    void AsPointer()
+    {
+      auto lamb = [=,this]() -> Generator {
+        int y = x;
+        co_return;
+      };
+
+      static_assert(sizeof(decltype(lamb)) == sizeof(void*));
+    }
+
+    void AsStarThis()
+    {
+      auto lamb = [*this]() -> Generator {
+        int y = x;
+        co_return;
+      };
+
+      static_assert(sizeof(decltype(lamb)) == sizeof(int));
+    }
+};
+
+int main()
+{
+  auto lamb = []() -> Generator {
+    co_return;
+  };
+
+  static_assert(sizeof(decltype(lamb)) == 1);
+}
diff --git a/clang/test/SemaCXX/cxx23-coroutine-promise-ctor-static-callop-lambda.cpp b/clang/test/SemaCXX/cxx23-coroutine-promise-ctor-static-callop-lambda.cpp
new file mode 100644
index 00000000000000..0e9e63bce86b87
--- /dev/null
+++ b/clang/test/SemaCXX/cxx23-coroutine-promise-ctor-static-callop-lambda.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -I%S/Inputs -std=c++23 %s
+
+// expected-no-diagnostics
+
+#include "std-coroutine.h"
+
+using size_t = decltype(sizeof(0));
+
+struct Generator {
+  struct promise_type {
+    int _val{};
+
+    Generator get_return_object() noexcept
+    {
+      return {};
+    }
+
+    std::suspend_never initial_suspend() noexcept
+    {
+      return {};
+    }
+
+    std::suspend_always final_suspend() noexcept
+    {
+      return {};
+    }
+
+    void return_void() noexcept {}
+    void unhandled_exception() noexcept {}
+
+    template<typename... TheRest>
+    promise_type(TheRest&&...)
+    {
+    }
+  };
+};
+
+
+int main()
+{
+  auto lamb = []() static -> Generator {
+    co_return;
+  };
+
+  static_assert(sizeof(decltype(lamb)) == 1);
+}
+



More information about the cfe-commits mailing list