Index: clang/lib/Sema/SemaCoroutine.cpp =================================================================== --- clang/lib/Sema/SemaCoroutine.cpp +++ clang/lib/Sema/SemaCoroutine.cpp @@ -977,19 +977,25 @@ E = R.get(); } + Expr *PCE = nullptr; VarDecl *Promise = FSI->CoroutinePromise; - ExprResult PC; - if (E && (isa(E) || !E->getType()->isVoidType())) { - getNamedReturnInfo(E, SimplerImplicitMoveMode::ForceOn); - PC = buildPromiseCall(*this, Promise, Loc, "return_value", E); + if ((E && E->getType()->isDependentType()) || + Promise->getType()->isDependentType()) { + // It is dependent, do nothing until instantiation time. } else { - E = MakeFullDiscardedValueExpr(E).get(); - PC = buildPromiseCall(*this, Promise, Loc, "return_void", None); - } - if (PC.isInvalid()) - return StmtError(); + ExprResult PC; + if (E && (isa(E) || !E->getType()->isVoidType())) { + getNamedReturnInfo(E, SimplerImplicitMoveMode::ForceOn); + PC = buildPromiseCall(*this, Promise, Loc, "return_value", E); + } else { + E = MakeFullDiscardedValueExpr(E).get(); + PC = buildPromiseCall(*this, Promise, Loc, "return_void", None); + } + if (PC.isInvalid()) + return StmtError(); - Expr *PCE = ActOnFinishFullExpr(PC.get(), /*DiscardedValue*/ false).get(); + PCE = ActOnFinishFullExpr(PC.get(), /*DiscardedValue*/ false).get(); + } Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE, IsImplicit); return Res; Index: clang/test/SemaCXX/coroutine-dep.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/coroutine-dep.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=c++17 -fcoroutines-ts -fsyntax-only %s + +namespace std { +template +struct coroutine_traits { + using promise_type = typename _Result::promise_type; +}; + +template +struct coroutine_handle; + +template <> +struct coroutine_handle { + static coroutine_handle from_address(void *__a) noexcept; + void resume() const noexcept; + void destroy() const noexcept; +}; + +template +struct coroutine_handle : coroutine_handle<> {}; + +struct suspend_always { + bool await_ready() const noexcept; + void await_suspend(coroutine_handle<>) const noexcept; + void await_resume() const noexcept; +}; +} // namespace std + +namespace Void { +class Task { +public: + struct promise_type { + public: + std::suspend_always initial_suspend() noexcept; + std::suspend_always final_suspend() noexcept; + + Task get_return_object() noexcept; + void unhandled_exception() noexcept; + void return_void() noexcept; + }; +}; + +template +Task Foo() noexcept { + co_return T(0); + ; +} +template Task Foo() noexcept; +} // namespace Void + +namespace Value { +class Task { +public: + struct promise_type { + public: + std::suspend_always initial_suspend() noexcept; + std::suspend_always final_suspend() noexcept; + + Task get_return_object() noexcept; + void unhandled_exception() noexcept; + void return_value(int value) noexcept; + }; +}; + +template +Task Foo() noexcept { + co_return T(0); +} +template Task Foo() noexcept; +} // namespace Value