Author: rsmith Date: Sat Nov 21 20:57:17 2015 New Revision: 253811 URL: http://llvm.org/viewvc/llvm-project?rev=253811&view=rev Log: [coroutines] Factor out co_await representation into common base class for co_await and co_yield, and use it to hold await_* calls.
Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/include/clang/Basic/StmtNodes.td cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/lib/Sema/SemaCoroutine.cpp cfe/trunk/test/Parser/cxx1z-coroutines.cpp cfe/trunk/test/SemaCXX/coroutines.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Sat Nov 21 20:57:17 2015 @@ -4826,6 +4826,14 @@ public: const_semantics_iterator semantics_end() const { return getSubExprsBuffer() + getNumSubExprs(); } + + llvm::iterator_range<semantics_iterator> semantics() { + return llvm::make_range(semantics_begin(), semantics_end()); + } + llvm::iterator_range<const_semantics_iterator> semantics() const { + return llvm::make_range(semantics_begin(), semantics_end()); + } + Expr *getSemanticExpr(unsigned index) { assert(index + 1 < getNumSubExprs()); return getSubExprsBuffer()[index + 1]; Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Sat Nov 21 20:57:17 2015 @@ -4008,65 +4008,61 @@ public: child_range children() { return child_range(SubExprs, SubExprs + 2); } }; -/// \brief Represents a 'co_await' expression. This expression checks whether its -/// operand is ready, and suspends the coroutine if not. Then (after the resume -/// if suspended) it resumes the coroutine and extracts the value from the -/// operand. This implies making four calls: +/// \brief Represents an expression that might suspend coroutine execution; +/// either a co_await or co_yield expression. /// -/// <operand>.operator co_await() or operator co_await(<operand>) -/// <result>.await_ready() -/// <result>.await_suspend(h) -/// <result>.await_resume() -/// -/// where h is a handle to the coroutine, and <result> is the result of calling -/// operator co_await() if it exists or the original operand otherwise. -/// -/// Note that the coroutine is prepared for suspension before the 'await_suspend' -/// call, but resumes after that call, which may cause parts of the -/// 'await_suspend' expression to occur much later than expected. -class CoawaitExpr : public Expr { - SourceLocation CoawaitLoc; +/// Evaluation of this expression first evaluates its 'ready' expression. If +/// that returns 'false': +/// -- execution of the coroutine is suspended +/// -- the 'suspend' expression is evaluated +/// -- if the 'suspend' expression returns 'false', the coroutine is +/// resumed +/// -- otherwise, control passes back to the resumer. +/// If the coroutine is not suspended, or when it is resumed, the 'resume' +/// expression is evaluated, and its result is the result of the overall +/// expression. +class CoroutineSuspendExpr : public Expr { + SourceLocation KeywordLoc; - enum SubExpr { Operand, Ready, Suspend, Resume, Count }; + enum SubExpr { Common, Ready, Suspend, Resume, Count }; Stmt *SubExprs[SubExpr::Count]; friend class ASTStmtReader; public: - CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready, - Expr *Suspend, Expr *Resume) - : Expr(CoawaitExprClass, Resume->getType(), Resume->getValueKind(), - Resume->getObjectKind(), - Resume->isTypeDependent(), - Resume->isValueDependent(), - Operand->isInstantiationDependent(), - Operand->containsUnexpandedParameterPack()), - CoawaitLoc(CoawaitLoc) { - SubExprs[CoawaitExpr::Operand] = Operand; - SubExprs[CoawaitExpr::Ready] = Ready; - SubExprs[CoawaitExpr::Suspend] = Suspend; - SubExprs[CoawaitExpr::Resume] = Resume; - } - CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand) - : Expr(CoawaitExprClass, Ty, VK_RValue, OK_Ordinary, - true, true, true, Operand->containsUnexpandedParameterPack()), - CoawaitLoc(CoawaitLoc) { - assert(Operand->isTypeDependent() && Ty->isDependentType() && - "wrong constructor for non-dependent co_await expression"); - SubExprs[CoawaitExpr::Operand] = Operand; - SubExprs[CoawaitExpr::Ready] = nullptr; - SubExprs[CoawaitExpr::Suspend] = nullptr; - SubExprs[CoawaitExpr::Resume] = nullptr; - } - CoawaitExpr(EmptyShell Empty) : Expr(CoawaitExprClass, Empty) { - SubExprs[CoawaitExpr::Operand] = nullptr; - SubExprs[CoawaitExpr::Ready] = nullptr; - SubExprs[CoawaitExpr::Suspend] = nullptr; - SubExprs[CoawaitExpr::Resume] = nullptr; - } - - SourceLocation getKeywordLoc() const { return CoawaitLoc; } - Expr *getOperand() const { - return static_cast<Expr*>(SubExprs[SubExpr::Operand]); + CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common, + Expr *Ready, Expr *Suspend, Expr *Resume) + : Expr(SC, Resume->getType(), Resume->getValueKind(), + Resume->getObjectKind(), Resume->isTypeDependent(), + Resume->isValueDependent(), Common->isInstantiationDependent(), + Common->containsUnexpandedParameterPack()), + KeywordLoc(KeywordLoc) { + SubExprs[SubExpr::Common] = Common; + SubExprs[SubExpr::Ready] = Ready; + SubExprs[SubExpr::Suspend] = Suspend; + SubExprs[SubExpr::Resume] = Resume; + } + CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, QualType Ty, + Expr *Common) + : Expr(SC, Ty, VK_RValue, OK_Ordinary, true, true, true, + Common->containsUnexpandedParameterPack()), + KeywordLoc(KeywordLoc) { + assert(Common->isTypeDependent() && Ty->isDependentType() && + "wrong constructor for non-dependent co_await/co_yield expression"); + SubExprs[SubExpr::Common] = Common; + SubExprs[SubExpr::Ready] = nullptr; + SubExprs[SubExpr::Suspend] = nullptr; + SubExprs[SubExpr::Resume] = nullptr; + } + CoroutineSuspendExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { + SubExprs[SubExpr::Common] = nullptr; + SubExprs[SubExpr::Ready] = nullptr; + SubExprs[SubExpr::Suspend] = nullptr; + SubExprs[SubExpr::Resume] = nullptr; + } + + SourceLocation getKeywordLoc() const { return KeywordLoc; } + Expr *getCommonExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Common]); } Expr *getReadyExpr() const { @@ -4080,10 +4076,10 @@ public: } SourceLocation getLocStart() const LLVM_READONLY { - return CoawaitLoc; + return KeywordLoc; } SourceLocation getLocEnd() const LLVM_READONLY { - return getOperand()->getLocEnd(); + return getCommonExpr()->getLocEnd(); } child_range children() { @@ -4091,52 +4087,50 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == CoawaitExprClass; + return T->getStmtClass() == CoawaitExprClass || + T->getStmtClass() == CoyieldExprClass; } }; -/// \brief Represents a 'co_yield' expression. This expression provides a value -/// to the coroutine promise and optionally suspends the coroutine. This implies -/// a making call to <promise>.yield_value(<operand>), which we name the "promise -/// call". -class CoyieldExpr : public Expr { - SourceLocation CoyieldLoc; - - /// The operand of the 'co_yield' expression. - Stmt *Operand; - /// The implied call to the promise object. May be null if the - /// coroutine has not yet been finalized. - Stmt *PromiseCall; - +/// \brief Represents a 'co_await' expression. +class CoawaitExpr : public CoroutineSuspendExpr { friend class ASTStmtReader; public: - CoyieldExpr(SourceLocation CoyieldLoc, QualType Void, Expr *Operand) - : Expr(CoyieldExprClass, Void, VK_RValue, OK_Ordinary, false, false, - Operand->isInstantiationDependent(), - Operand->containsUnexpandedParameterPack()), - CoyieldLoc(CoyieldLoc), Operand(Operand), PromiseCall(nullptr) {} - CoyieldExpr(EmptyShell Empty) : Expr(CoyieldExprClass, Empty) {} - - SourceLocation getKeywordLoc() const { return CoyieldLoc; } - Expr *getOperand() const { return static_cast<Expr*>(Operand); } - - /// \brief Get the call to the promise objet that is implied by an evaluation - /// of this expression. Will be nullptr if the coroutine has not yet been - /// finalized. - 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; } + CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready, + Expr *Suspend, Expr *Resume) + : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready, + Suspend, Resume) {} + CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand) + : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {} + CoawaitExpr(EmptyShell Empty) + : CoroutineSuspendExpr(CoawaitExprClass, Empty) {} - SourceLocation getLocStart() const LLVM_READONLY { return CoyieldLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return Operand->getLocEnd(); + Expr *getOperand() const { + // FIXME: Dig out the actual operand or store it. + return getCommonExpr(); } - child_range children() { - Stmt **Which = PromiseCall ? &PromiseCall : &Operand; - return child_range(Which, Which + 1); + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoawaitExprClass; + } +}; + +/// \brief Represents a 'co_yield' expression. +class CoyieldExpr : public CoroutineSuspendExpr { + friend class ASTStmtReader; +public: + CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready, + Expr *Suspend, Expr *Resume) + : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready, + Suspend, Resume) {} + CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand) + : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {} + CoyieldExpr(EmptyShell Empty) + : CoroutineSuspendExpr(CoyieldExprClass, Empty) {} + + Expr *getOperand() const { + // FIXME: Dig out the actual operand or store it. + return getCommonExpr(); } static bool classof(const Stmt *T) { Modified: cfe/trunk/include/clang/Basic/StmtNodes.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/StmtNodes.td (original) +++ cfe/trunk/include/clang/Basic/StmtNodes.td Sat Nov 21 20:57:17 2015 @@ -145,8 +145,9 @@ def LambdaExpr : DStmt<Expr>; def CXXFoldExpr : DStmt<Expr>; // C++ Coroutines TS expressions -def CoawaitExpr : DStmt<Expr>; -def CoyieldExpr : DStmt<Expr>; +def CoroutineSuspendExpr : DStmt<Expr, 1>; +def CoawaitExpr : DStmt<CoroutineSuspendExpr>; +def CoyieldExpr : DStmt<CoroutineSuspendExpr>; // Obj-C Expressions. def ObjCStringLiteral : DStmt<Expr>; Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Sat Nov 21 20:57:17 2015 @@ -7493,18 +7493,16 @@ void AnalyzeImplicitConversions(Sema &S, CheckImplicitConversion(S, E, T, CC); // Now continue drilling into this expression. - - if (PseudoObjectExpr * POE = dyn_cast<PseudoObjectExpr>(E)) { - if (POE->getResultExpr()) - E = POE->getResultExpr(); - } - - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { - if (OVE->getSourceExpr()) - AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); - return; + + if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { + // The bound subexpressions in a PseudoObjectExpr are not reachable + // as transitive children. + // FIXME: Use a more uniform representation for this. + for (auto *SE : POE->semantics()) + if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE)) + AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); } - + // Skip past explicit casts. if (isa<ExplicitCastExpr>(E)) { E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts(); Modified: cfe/trunk/lib/Sema/SemaCoroutine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCoroutine.cpp?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCoroutine.cpp (original) +++ cfe/trunk/lib/Sema/SemaCoroutine.cpp Sat Nov 21 20:57:17 2015 @@ -300,8 +300,22 @@ ExprResult Sema::BuildCoyieldExpr(Source E = R.get(); } - // FIXME: Build await_* calls. - Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E); + if (E->getType()->isDependentType()) { + Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E); + Coroutine->CoroutineStmts.push_back(Res); + return Res; + } + + // FIXME: If E is a prvalue, create a temporary. + // FIXME: If E is an xvalue, convert to lvalue. + + // Build the await_ready, await_suspend, await_resume calls. + ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E); + if (RSS.IsInvalid) + return ExprError(); + + Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1], + RSS.Results[2]); Coroutine->CoroutineStmts.push_back(Res); return Res; } Modified: cfe/trunk/test/Parser/cxx1z-coroutines.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-coroutines.cpp?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx1z-coroutines.cpp (original) +++ cfe/trunk/test/Parser/cxx1z-coroutines.cpp Sat Nov 21 20:57:17 2015 @@ -9,7 +9,7 @@ U f(T t) { 1 + co_yield t; // expected-error {{expected expression}} auto x = co_await t; - auto y = co_yield t; // expected-error {{void}} FIXME + auto y = co_yield t; for co_await (int x : t) {} for co_await (int x = 0; x != 10; ++x) {} // expected-error {{'co_await' modifier can only be applied to range-based for loop}} Modified: cfe/trunk/test/SemaCXX/coroutines.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/coroutines.cpp?rev=253811&r1=253810&r2=253811&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/coroutines.cpp (original) +++ cfe/trunk/test/SemaCXX/coroutines.cpp Sat Nov 21 20:57:17 2015 @@ -46,9 +46,12 @@ void undefined_promise() { // expected-e struct yielded_thing { const char *p; short a, b; }; +struct not_awaitable {}; + 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 yield() { @@ -58,6 +61,8 @@ void yield() { co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} co_yield {"foo"}; co_yield "foo"; // expected-error {{no matching}} + co_yield 1.0; + co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}} } void mixed_yield() { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits