r253725 - [coroutines] Synthesize yield_value call for co_yield.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 20 14:40:06 PST 2015
Author: rsmith
Date: Fri Nov 20 16:40:06 2015
New Revision: 253725
URL: http://llvm.org/viewvc/llvm-project?rev=253725&view=rev
Log:
[coroutines] Synthesize yield_value call for co_yield.
Modified:
cfe/trunk/lib/Sema/SemaCoroutine.cpp
cfe/trunk/test/SemaCXX/coroutines.cpp
Modified: cfe/trunk/lib/Sema/SemaCoroutine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCoroutine.cpp?rev=253725&r1=253724&r2=253725&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCoroutine.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCoroutine.cpp Fri Nov 20 16:40:06 2015
@@ -128,9 +128,12 @@ checkCoroutineContext(Sema &S, SourceLoc
assert(ScopeInfo && "missing function scope for function");
// If we don't have a promise variable, build one now.
- if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) {
+ if (!ScopeInfo->CoroutinePromise) {
QualType T =
- lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc);
+ FD->getType()->isDependentType()
+ ? S.Context.DependentTy
+ : lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(),
+ Loc);
if (T.isNull())
return nullptr;
@@ -165,6 +168,23 @@ struct ReadySuspendResumeResult {
Expr *Results[3];
};
+static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
+ StringRef Name,
+ MutableArrayRef<Expr *> Args) {
+ DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
+
+ // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
+ CXXScopeSpec SS;
+ ExprResult Result = S.BuildMemberReferenceExpr(
+ Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
+ SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
+ /*Scope=*/nullptr);
+ if (Result.isInvalid())
+ return ExprError();
+
+ return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
+}
+
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
@@ -174,22 +194,11 @@ static ReadySuspendResumeResult buildCoa
const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
- DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc);
-
Expr *Operand = new (S.Context) OpaqueValueExpr(
Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E);
- // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
- CXXScopeSpec SS;
- ExprResult Result = S.BuildMemberReferenceExpr(
- Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS,
- SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
- /*Scope=*/nullptr);
- if (Result.isInvalid())
- return Calls;
-
// FIXME: Pass coroutine handle to await_suspend.
- Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr);
+ ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
if (Result.isInvalid())
return Calls;
Calls.Results[I] = Result.get();
@@ -236,11 +245,36 @@ ExprResult Sema::BuildCoawaitExpr(Source
return Res;
}
+static ExprResult buildYieldValueCall(Sema &S, FunctionScopeInfo *Coroutine,
+ SourceLocation Loc, Expr *E) {
+ assert(Coroutine->CoroutinePromise && "no promise for coroutine");
+
+ // Form a reference to the promise.
+ auto *Promise = Coroutine->CoroutinePromise;
+ ExprResult PromiseRef = S.BuildDeclRefExpr(
+ Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
+ if (PromiseRef.isInvalid())
+ return ExprError();
+
+ // Call 'yield_value', passing in E.
+ return buildMemberCall(S, PromiseRef.get(), Loc, "yield_value", E);
+}
+
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
- // FIXME: Build yield_value call.
- ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
+ if (!Coroutine)
+ return ExprError();
+
+ // Build yield_value call.
+ ExprResult Awaitable = buildYieldValueCall(*this, Coroutine, Loc, E);
if (Awaitable.isInvalid())
return ExprError();
+
+ // Build 'operator co_await' call.
+ Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
+ if (Awaitable.isInvalid())
+ return ExprError();
+
return BuildCoyieldExpr(Loc, Awaitable.get());
}
ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
Modified: cfe/trunk/test/SemaCXX/coroutines.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/coroutines.cpp?rev=253725&r1=253724&r2=253725&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/coroutines.cpp (original)
+++ cfe/trunk/test/SemaCXX/coroutines.cpp Fri Nov 20 16:40:06 2015
@@ -29,6 +29,13 @@ double bad_promise_type(double) {
co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
}
+template<> struct std::coroutine_traits<double, int> {
+ struct promise_type {};
+};
+double bad_promise_type_2(int) {
+ co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}}
+}
+
struct promise; // expected-note {{forward declaration}}
template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };
@@ -37,7 +44,18 @@ void undefined_promise() { // expected-e
co_await a;
}
-struct promise {};
+struct yielded_thing { int a, b, c; const char *p; };
+
+struct promise {
+ awaitable yield_value(int); // expected-note {{candidate}}
+ awaitable yield_value(yielded_thing); // expected-note {{candidate}}
+};
+
+void yield() {
+ co_yield 0;
+ co_yield {1, 2, 3, "foo"}; // FIXME expected-error {{expected expression}}
+ co_yield "foo"; // expected-error {{no matching}}
+}
void mixed_yield() {
co_yield 0; // expected-note {{use of 'co_yield'}}
More information about the cfe-commits
mailing list