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;
-
- enum SubExpr { Operand, Ready, Suspend, Resume, Count };
+/// 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 { 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 {
}
SourceLocation getLocStart() const LLVM_READONLY {
- return CoawaitLoc;
+ return KeywordLoc;
}
SourceLocation getLocEnd() const LLVM_READONLY {
- return getOperand()->getLocEnd();
+ return getCommonExpr()->getLocEnd();
}
child_range children() {
}
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); }
+ 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) {}
- /// \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 *getOperand() const {
+ // FIXME: Dig out the actual operand or store it.
+ return getCommonExpr();
+ }
- SourceLocation getLocStart() const LLVM_READONLY { return CoyieldLoc; }
- SourceLocation getLocEnd() const LLVM_READONLY {
- return Operand->getLocEnd();
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CoawaitExprClass;
}
+};
- child_range children() {
- Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
- return child_range(Which, Which + 1);
+/// \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) {