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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits