[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 09:16:38 PST 2024
https://github.com/andreasfertig created https://github.com/llvm/llvm-project/pull/84519
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`.
>From ff5f858b64b3aca3ffd36d75b5f2c96ebf895f4d 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 | 17 ++++-
.../SemaCXX/coroutine-promise-ctor-lambda.cpp | 71 +++++++++++++++++++
...tine-promise-ctor-static-callop-lambda.cpp | 47 ++++++++++++
3 files changed, 133 insertions(+), 2 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..79da92083a2be7 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,
+ Record != nullptr);
+
+ ThisExpr = ActOnCXXThis(Loc, /*ThisRefersToClosureObject=*/true);
+ } else {
+ ThisExpr = ActOnCXXThis(Loc);
+ }
+
if (ThisExpr.isInvalid())
return nullptr;
ThisExpr = CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
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