Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++20][Coroutines] lambda-coroutine with promise_type ctor. #84519

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^

Expand Down
23 changes: 19 additions & 4 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -1387,9 +1400,10 @@ 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);
ThisExpr = S.BuildCXXThisExpr(
Loc, MD->getThisType().getNonReferenceType(), true, true);
} else {
ThisExpr = S.ActOnCXXThis(Loc);
}
Expand Down Expand Up @@ -1659,6 +1673,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
if (NewExpr.isInvalid())
return false;


// Make delete call.

QualType OpDeleteQualType = OperatorDelete->getType();
Expand Down
71 changes: 71 additions & 0 deletions clang/test/SemaCXX/coroutine-promise-ctor-lambda.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
}

9 changes: 9 additions & 0 deletions clang/test/SemaCXX/gh84064-1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ struct CapturingThisTest

static_assert(sizeof(decltype(lamb)) == sizeof(int));
}

void NoCapture()
{
auto lamb = []() -> Generator {
co_return;
};

static_assert(sizeof(decltype(lamb)) == 1);
}
};

int main()
Expand Down
Loading