r253816 - [coroutines] Build implicit return_value / return_void calls for co_return.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sat Nov 21 23:05:17 PST 2015


Author: rsmith
Date: Sun Nov 22 01:05:16 2015
New Revision: 253816

URL: http://llvm.org/viewvc/llvm-project?rev=253816&view=rev
Log:
[coroutines] Build implicit return_value / return_void calls for co_return.

Modified:
    cfe/trunk/include/clang/AST/StmtCXX.h
    cfe/trunk/lib/Sema/SemaCoroutine.cpp
    cfe/trunk/test/SemaCXX/coroutines.cpp

Modified: cfe/trunk/include/clang/AST/StmtCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtCXX.h?rev=253816&r1=253815&r2=253816&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtCXX.h (original)
+++ cfe/trunk/include/clang/AST/StmtCXX.h Sun Nov 22 01:05:16 2015
@@ -328,50 +328,47 @@ public:
 ///
 /// This statament models the initialization of the coroutine promise
 /// (encapsulating the eventual notional return value) from an expression
-/// (or braced-init-list).
+/// (or braced-init-list), followed by termination of the coroutine.
 ///
-/// This initialization is modeled by a call to one of:
+/// This initialization is modeled by the evaluation of the operand
+/// followed by a call to one of:
 ///   <promise>.return_value(<operand>)
 ///   <promise>.return_void()
 /// which we name the "promise call".
 class CoreturnStmt : public Stmt {
   SourceLocation CoreturnLoc;
 
-  /// The operand of the 'co_return' statement.
-  Stmt *Operand;
-  /// The implied call to the promise object. May be null if the
-  /// coroutine has not yet been finalized.
-  Stmt *PromiseCall;
+  enum SubStmt { Operand, PromiseCall, Count };
+  Stmt *SubStmts[SubStmt::Count];
 
   friend class ASTStmtReader;
 public:
-  CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand)
-      : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
-        Operand(Operand), PromiseCall(nullptr) {}
+  CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
+      : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
+    SubStmts[SubStmt::Operand] = Operand;
+    SubStmts[SubStmt::PromiseCall] = PromiseCall;
+  }
 
   SourceLocation getKeywordLoc() const { return CoreturnLoc; }
 
   /// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
   /// if none was specified.
-  Expr *getOperand() const { return static_cast<Expr*>(Operand); }
+  Expr *getOperand() const { return static_cast<Expr*>(SubStmts[Operand]); }
 
   /// \brief Retrieve the promise call that results from this 'co_return'
   /// statement. Will be nullptr if either the coroutine has not yet been
   /// finalized or the coroutine has no eventual return type.
-  Expr *getPromiseCall() const { return static_cast<Expr*>(PromiseCall); }
-
-  /// \brief Set the resolved promise call. This is delayed until the
-  /// complete coroutine body has been parsed and the promise type is known.
-  void finalize(Stmt *PC) { PromiseCall = PC; }
+  Expr *getPromiseCall() const {
+    return static_cast<Expr*>(SubStmts[PromiseCall]);
+  }
 
   SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
   SourceLocation getLocEnd() const LLVM_READONLY {
-    return Operand->getLocEnd();
+    return getOperand()->getLocEnd();
   }
 
   child_range children() {
-    Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
-    return child_range(Which, Which + 1);
+    return child_range(SubStmts, SubStmts + SubStmt::Count);
   }
 
   static bool classof(const Stmt *T) {

Modified: cfe/trunk/lib/Sema/SemaCoroutine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCoroutine.cpp?rev=253816&r1=253815&r2=253816&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCoroutine.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCoroutine.cpp Sun Nov 22 01:05:16 2015
@@ -253,8 +253,9 @@ ExprResult Sema::BuildCoawaitExpr(Source
   return Res;
 }
 
-static ExprResult buildYieldValueCall(Sema &S, FunctionScopeInfo *Coroutine,
-                                      SourceLocation Loc, Expr *E) {
+static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine,
+                                   SourceLocation Loc, StringRef Name,
+                                   MutableArrayRef<Expr *> Args) {
   assert(Coroutine->CoroutinePromise && "no promise for coroutine");
 
   // Form a reference to the promise.
@@ -265,7 +266,7 @@ static ExprResult buildYieldValueCall(Se
     return ExprError();
 
   // Call 'yield_value', passing in E.
-  return buildMemberCall(S, PromiseRef.get(), Loc, "yield_value", E);
+  return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
 }
 
 ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
@@ -280,7 +281,8 @@ ExprResult Sema::ActOnCoyieldExpr(Scope
     return ExprError();
 
   // Build yield_value call.
-  ExprResult Awaitable = buildYieldValueCall(*this, Coroutine, Loc, E);
+  ExprResult Awaitable =
+      buildPromiseCall(*this, Coroutine, Loc, "yield_value", E);
   if (Awaitable.isInvalid())
     return ExprError();
 
@@ -338,8 +340,22 @@ StmtResult Sema::BuildCoreturnStmt(Sourc
   if (!Coroutine)
     return StmtError();
 
-  // FIXME: Build return_* calls.
-  Stmt *Res = new (Context) CoreturnStmt(Loc, E);
+  // FIXME: If the operand is a reference to a variable that's about to go out
+  // ot scope, we should treat the operand as an xvalue for this overload
+  // resolution.
+  ExprResult PC;
+  if (E && !E->getType()->isVoidType()) {
+    PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E);
+  } else {
+    E = MakeFullDiscardedValueExpr(E).get();
+    PC = buildPromiseCall(*this, Coroutine, Loc, "return_void", None);
+  }
+  if (PC.isInvalid())
+    return StmtError();
+
+  Expr *PCE = ActOnFinishFullExpr(PC.get()).get();
+
+  Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE);
   Coroutine->CoroutineStmts.push_back(Res);
   return Res;
 }

Modified: cfe/trunk/test/SemaCXX/coroutines.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/coroutines.cpp?rev=253816&r1=253815&r2=253816&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/coroutines.cpp (original)
+++ cfe/trunk/test/SemaCXX/coroutines.cpp Sun Nov 22 01:05:16 2015
@@ -52,6 +52,8 @@ struct promise {
   awaitable yield_value(int); // expected-note {{candidate}}
   awaitable yield_value(yielded_thing); // expected-note {{candidate}}
   not_awaitable yield_value(void()); // expected-note {{candidate}}
+  void return_void();
+  void return_value(int); // expected-note {{here}}
 };
 
 void yield() {
@@ -65,6 +67,17 @@ void yield() {
   co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
 }
 
+void coreturn(int n) {
+  co_await a;
+  if (n == 0)
+    co_return 3;
+  if (n == 1)
+    co_return {4};
+  if (n == 2)
+    co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}}
+  co_return;
+}
+
 void mixed_yield() {
   co_yield 0; // expected-note {{use of 'co_yield'}}
   return; // expected-error {{not allowed in coroutine}}




More information about the cfe-commits mailing list