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