diff options
| author | Eric Fiselier <eric@efcs.ca> | 2017-06-15 19:43:36 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2017-06-15 19:43:36 +0000 |
| commit | cddaf8728fd2786bf3af3a81814c2fe2b13d8692 (patch) | |
| tree | 1d69077933feed592a58949d2fd371a7c4e4bef9 /clang/lib/CodeGen | |
| parent | b560fdf3b84e18e3fb19d12cb2bd610dc2316118 (diff) | |
| download | bcm5719-llvm-cddaf8728fd2786bf3af3a81814c2fe2b13d8692.tar.gz bcm5719-llvm-cddaf8728fd2786bf3af3a81814c2fe2b13d8692.zip | |
[coroutines] Allow co_await and co_yield expressions that return an lvalue to compile
Summary:
The title says it all.
Reviewers: GorNishanov, rsmith
Reviewed By: GorNishanov
Subscribers: rjmccall, cfe-commits
Differential Revision: https://reviews.llvm.org/D34194
llvm-svn: 305496
Diffstat (limited to 'clang/lib/CodeGen')
| -rw-r--r-- | clang/lib/CodeGen/CGCoroutine.cpp | 53 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 2 |
3 files changed, 55 insertions, 5 deletions
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index bc5f6327c9a..daefb0edcb4 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -148,10 +148,16 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) { // // See llvm's docs/Coroutines.rst for more details. // -static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, +namespace { + struct LValueOrRValue { + LValue LV; + RValue RV; + }; +} +static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, CoroutineSuspendExpr const &S, AwaitKind Kind, AggValueSlot aggSlot, - bool ignoreResult) { + bool ignoreResult, bool forLValue) { auto *E = S.getCommonExpr(); // FIXME: rsmith 5/22/2017. Does it still make sense for us to have a @@ -217,7 +223,12 @@ static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, // Emit await_resume expression. CGF.EmitBlock(ReadyBlock); - return CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); + LValueOrRValue Res; + if (forLValue) + Res.LV = CGF.EmitLValue(S.getResumeExpr()); + else + Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); + return Res; } RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E, @@ -225,13 +236,13 @@ RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E, bool ignoreResult) { return emitSuspendExpression(*this, *CurCoro.Data, E, CurCoro.Data->CurrentAwaitKind, aggSlot, - ignoreResult); + ignoreResult, /*forLValue*/false).RV; } RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E, AggValueSlot aggSlot, bool ignoreResult) { return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield, - aggSlot, ignoreResult); + aggSlot, ignoreResult, /*forLValue*/false).RV; } void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { @@ -240,6 +251,38 @@ void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { EmitBranchThroughCleanup(CurCoro.Data->FinalJD); } + +#ifndef NDEBUG +static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx, + const CoroutineSuspendExpr *E) { + const auto *RE = E->getResumeExpr(); + // Is it possible for RE to be a CXXBindTemporaryExpr wrapping + // a MemberCallExpr? + assert(isa<CallExpr>(RE) && "unexpected suspend expression type"); + return cast<CallExpr>(RE)->getCallReturnType(Ctx); +} +#endif + +LValue +CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) { + assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + return emitSuspendExpression(*this, *CurCoro.Data, *E, + CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(), + /*ignoreResult*/false, /*forLValue*/true).LV; +} + +LValue +CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) { + assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + return emitSuspendExpression(*this, *CurCoro.Data, *E, + AwaitKind::Yield, AggValueSlot::ignored(), + /*ignoreResult*/false, /*forLValue*/true).LV; +} + // Hunts for the parameter reference in the parameter copy/move declaration. namespace { struct GetParamRef : public StmtVisitor<GetParamRef> { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1b3103fd71f..15829888ead 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1158,6 +1158,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::MaterializeTemporaryExprClass: return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E)); + + case Expr::CoawaitExprClass: + return EmitCoawaitLValue(cast<CoawaitExpr>(E)); + case Expr::CoyieldExprClass: + return EmitCoyieldLValue(cast<CoyieldExpr>(E)); } } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index a179276a07a..831eedf9e47 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2550,9 +2550,11 @@ public: RValue EmitCoawaitExpr(const CoawaitExpr &E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); + LValue EmitCoawaitLValue(const CoawaitExpr *E); RValue EmitCoyieldExpr(const CoyieldExpr &E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); + LValue EmitCoyieldLValue(const CoyieldExpr *E); RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID); void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); |

