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 <a...@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); +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits