diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7190,8 +7190,12 @@ // that may fail. ScopeInfo->setNeedsCoroutineSuspends(false); - // The new CoroutinePromise object needs to be built and put into the current - // FunctionScopeInfo before any transformations or rebuilding occurs. + // We re-build the coroutine promise object (and the coroutine parameters its + // type and constructor depend on) based on the types used in our current + // function. We must do so, and set it on the current FunctionScopeInfo, + // before attempting to transform the other parts of the coroutine body + // statement, such as the implicit suspend statements (because those + // statements reference the FunctionScopeInfo::CoroutinePromise). if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation())) return StmtError(); auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation()); @@ -7200,8 +7204,9 @@ getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise}); ScopeInfo->CoroutinePromise = Promise; - // Transform the implicit coroutine statements we built during the initial - // parse. + // Transform the implicit coroutine statements constructed using dependent + // types during the previous parse: initial and final suspensions, the return + // object, and others. We also transform the coroutine function's body. StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt()); if (InitSuspend.isInvalid()) return StmtError(); @@ -7228,17 +7233,13 @@ return StmtError(); Builder.ReturnValue = Res.get(); + // If during the previous parse the coroutine still had a dependent promise + // statement, we may need to build some implicit coroutine statements + // (such as exception and fallthrough handlers) for the first time. if (S->hasDependentPromiseType()) { - // PR41909: We may find a generic coroutine lambda definition within a - // template function that is being instantiated. In this case, the lambda - // will have a dependent promise type, until it is used in an expression - // that creates an instantiation with a non-dependent promise type. We - // should not assert or build coroutine dependent statements for such a - // generic lambda. - auto *MD = dyn_cast_or_null(FD); - if (!MD || !MD->getParent()->isGenericLambda()) { - assert(!Promise->getType()->isDependentType() && - "the promise type must no longer be dependent"); + // We can only build these statements, however, if the current promise type + // is not dependent. + if (!Promise->getType()->isDependentType()) { assert(!S->getFallthroughHandler() && !S->getExceptionHandler() && !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() && "these nodes should not have been built yet"); diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -731,6 +731,12 @@ [](auto &arg) -> coro { co_await 24; }("argument"); + [](auto &arg) ->coro { // expected-warning {{expression result unused}} + []() -> coro { + co_await 36; + }; + co_await 48; + }; } template void ok_generic_lambda_coawait_PR41909(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909' requested here}}