[clang] [C++20][Coroutines] lambda-coroutine with promise_type ctor. (PR #84519)
Andreas Fertig via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 10 23:41:17 PDT 2024
https://github.com/andreasfertig updated https://github.com/llvm/llvm-project/pull/84519
>From cdeb381fb177a3d2991bdec8495cc952a5453712 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/docs/ReleaseNotes.rst | 4 ++
clang/lib/Sema/SemaCoroutine.cpp | 19 ++++-
.../SemaCXX/coroutine-promise-ctor-lambda.cpp | 71 +++++++++++++++++++
...tine-promise-ctor-static-callop-lambda.cpp | 47 ++++++++++++
4 files changed, 138 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/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 690fc7ed271a3d..13c2de49196628 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -95,6 +95,10 @@ C++20 Feature Support
templates (`P1814R0 <https://wg21.link/p1814r0>`_).
(#GH54051).
+- Clang now treats a lambda-coroutine with a `promise_type` with a constructor
+ or a user-defined `operator new` correctly, passing the lambdas
+ `this`-pointer as the first argument of the parameter list.
+
C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 301a5ff72a3b2a..d9a523fca13d99 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)) {
+ 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