From 3932cbe66b32a3d4d4e7d3d0ed92435ded8290d0 Mon Sep 17 00:00:00 2001 From: Brian Gesiak Date: Mon, 3 Jun 2019 00:47:32 +0000 Subject: [PATCH] [coroutines][PR41909] Don't build dependent coroutine statements for generic lambda Summary: https://bugs.llvm.org/show_bug.cgi?id=41909 describes an issue in which a generic lambda that takes a dependent argument `auto set` causes the template instantiation machinery for coroutine body statements to crash with an ICE. The issue is two-fold: 1. The paths taken by the template instantiator contain several asserts that the coroutine promise must not have a dependent type. 2. The template instantiator unconditionally builds corotuine statements that depend on the promise type, which cannot be dependent. To work around the issue, prevent the template instantiator from building dependent coroutine statements if the coroutine promise type is dependent. Since we only expect this to occur in the case of a generic lambda, limit the workaround behavior to just that case. Reviewers: GorNishanov, EricWF, lewissbaker, tks2103 Reviewed By: GorNishanov Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62550 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362348 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/TreeTransform.h | 23 ++++++++++++++++------- test/SemaCXX/coroutines.cpp | 10 ++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f46193502b..592787a587 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7163,13 +7163,22 @@ TreeTransform::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { Builder.ReturnValue = Res.get(); if (S->hasDependentPromiseType()) { - assert(!Promise->getType()->isDependentType() && - "the promise type must no longer be dependent"); - assert(!S->getFallthroughHandler() && !S->getExceptionHandler() && - !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() && - "these nodes should not have been built yet"); - if (!Builder.buildDependentStatements()) - return StmtError(); + // 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"); + assert(!S->getFallthroughHandler() && !S->getExceptionHandler() && + !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() && + "these nodes should not have been built yet"); + if (!Builder.buildDependentStatements()) + return StmtError(); + } } else { if (auto *OnFallthrough = S->getFallthroughHandler()) { StmtResult Res = getDerived().TransformStmt(OnFallthrough); diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index 99964ef6bc..1286ca4628 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -720,6 +720,16 @@ coro ok_static_coawait() { co_await 42; } +template void ok_generic_lambda_coawait_PR41909() { + [](auto& arg) -> coro { // expected-warning {{expression result unused}} + co_await 12; + }; + [](auto &arg) -> coro { + co_await 24; + }("argument"); +} +template void ok_generic_lambda_coawait_PR41909(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909' requested here}} + template<> struct std::experimental::coroutine_traits { using promise_type = promise; }; -- 2.40.0