r253811 - [coroutines] Factor out co_await representation into common base class for co_await and co_yield, and use it to hold await_* calls.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Sat Nov 21 18:57:18 PST 2015
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() {
More information about the cfe-commits
mailing list