From 38f11825d18eab5bc140f891dc4c024e45283a90 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 llvm-svn: 362348 --- clang/lib/Sema/TreeTransform.h | 23 ++++++++++++++++------- clang/test/SemaCXX/coroutines.cpp | 10 ++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index f461935..592787a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/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/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp index 99964ef..1286ca4 100644 --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/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.7.4