diff options
Diffstat (limited to 'clang/include/clang')
| -rw-r--r-- | clang/include/clang/AST/DataRecursiveASTVisitor.h | 8 | ||||
| -rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 123 | ||||
| -rw-r--r-- | clang/include/clang/AST/OperationKinds.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 30 | ||||
| -rw-r--r-- | clang/include/clang/AST/StmtCXX.h | 100 | ||||
| -rw-r--r-- | clang/include/clang/AST/StmtVisitor.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 19 | ||||
| -rw-r--r-- | clang/include/clang/Basic/StmtNodes.td | 8 | ||||
| -rw-r--r-- | clang/include/clang/Sema/ScopeInfo.h | 26 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 21 |
10 files changed, 307 insertions, 34 deletions
diff --git a/clang/include/clang/AST/DataRecursiveASTVisitor.h b/clang/include/clang/AST/DataRecursiveASTVisitor.h index 46dcb6ca7b8..25e2c069baf 100644 --- a/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -43,7 +43,7 @@ OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \ OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \ OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \ - OPERATOR(Extension) + OPERATOR(Extension) OPERATOR(Coawait) // All binary operators (excluding compound assign operators). #define BINOP_LIST() \ @@ -2306,6 +2306,12 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +// Coroutine support. +DEF_TRAVERSE_STMT(CoroutineBodyStmt, {}) +DEF_TRAVERSE_STMT(CoreturnStmt, {}) +DEF_TRAVERSE_STMT(CoawaitExpr, {}) +DEF_TRAVERSE_STMT(CoyieldExpr, {}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(CharacterLiteral, {}) diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index e8493f1933c..055542650f4 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -4008,6 +4008,129 @@ 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: +/// +/// <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 }; + 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{Operand, Ready, Suspend, Resume} {} + CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand) + : Expr(CoawaitExprClass, Ty, VK_RValue, OK_Ordinary, + true, true, true, Operand->containsUnexpandedParameterPack()), + CoawaitLoc(CoawaitLoc), SubExprs{Operand} { + assert(Operand->isTypeDependent() && Ty->isDependentType() && + "wrong constructor for non-dependent co_await expression"); + } + CoawaitExpr(EmptyShell Empty) : Expr(CoawaitExprClass, Empty) {} + + SourceLocation getKeywordLoc() const { return CoawaitLoc; } + Expr *getOperand() const { + return static_cast<Expr*>(SubExprs[SubExpr::Operand]); + } + + Expr *getReadyExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Ready]); + } + Expr *getSuspendExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Suspend]); + } + Expr *getResumeExpr() const { + return static_cast<Expr*>(SubExprs[SubExpr::Resume]); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return CoawaitLoc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getOperand()->getLocEnd(); + } + + child_range children() { + return child_range(SubExprs, SubExprs + SubExpr::Count); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoawaitExprClass; + } +}; + +/// \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; + + 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; } + + SourceLocation getLocStart() const LLVM_READONLY { return CoyieldLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return Operand->getLocEnd(); + } + + child_range children() { + Stmt **Which = PromiseCall ? &PromiseCall : &Operand; + return child_range(Which, Which + 1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoyieldExprClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h index e3f01266772..2235c1012fb 100644 --- a/clang/include/clang/AST/OperationKinds.h +++ b/clang/include/clang/AST/OperationKinds.h @@ -334,7 +334,8 @@ enum UnaryOperatorKind { UO_Plus, UO_Minus, // [C99 6.5.3.3] Unary arithmetic UO_Not, UO_LNot, // [C99 6.5.3.3] Unary arithmetic UO_Real, UO_Imag, // "__real expr"/"__imag expr" Extension. - UO_Extension // __extension__ marker. + UO_Extension, // __extension__ marker. + UO_Coawait // [C++ Coroutines] co_await operator }; /// \brief The kind of bridging performed by the Objective-C bridge cast. diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 2fabfa988ea..341acd99e06 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -43,7 +43,7 @@ OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \ OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \ OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \ - OPERATOR(Extension) + OPERATOR(Extension) OPERATOR(Coawait) // All binary operators (excluding compound assign operators). #define BINOP_LIST() \ @@ -2346,6 +2346,34 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +// For coroutines expressions, traverse either the operand +// as written or the implied calls, depending on what the +// derived class requests. +DEF_TRAVERSE_STMT(CoroutineBodyStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseStmt(S->getBody())); + return true; + } +}) +DEF_TRAVERSE_STMT(CoreturnStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseStmt(S->getOperand())); + return true; + } +}) +DEF_TRAVERSE_STMT(CoawaitExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseStmt(S->getOperand())); + return true; + } +}) +DEF_TRAVERSE_STMT(CoyieldExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseStmt(S->getOperand())); + return true; + } +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(CharacterLiteral, {}) diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index 567a7728843..1dfc74425ee 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -131,12 +131,16 @@ class CXXForRangeStmt : public Stmt { // SubExprs[RANGE] is an expression or declstmt. // SubExprs[COND] and SubExprs[INC] are expressions. Stmt *SubExprs[END]; + SourceLocation CoawaitLoc; SourceLocation ColonLoc; SourceLocation RParenLoc; + + friend class ASTStmtReader; public: CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd, Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, - SourceLocation FL, SourceLocation CL, SourceLocation RPL); + SourceLocation FL, SourceLocation CAL, SourceLocation CL, + SourceLocation RPL); CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { } @@ -181,13 +185,10 @@ public: void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; } void setBody(Stmt *S) { SubExprs[BODY] = S; } - SourceLocation getForLoc() const { return ForLoc; } - void setForLoc(SourceLocation Loc) { ForLoc = Loc; } + SourceLocation getCoawaitLoc() const { return CoawaitLoc; } SourceLocation getColonLoc() const { return ColonLoc; } - void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } SourceLocation getRParenLoc() const { return RParenLoc; } - void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } SourceLocation getLocEnd() const LLVM_READONLY { @@ -287,6 +288,95 @@ public: } }; +/// \brief Represents the body of a coroutine. This wraps the normal function +/// body and holds the additional semantic context required to set up and tear +/// down the coroutine frame. +class CoroutineBodyStmt : public Stmt { + enum SubStmt { Body, Count }; + Stmt *SubStmts[SubStmt::Count]; + + friend class ASTStmtReader; +public: + CoroutineBodyStmt(Stmt *Body) + : Stmt(CoroutineBodyStmtClass), SubStmts{Body} {} + + /// \brief Retrieve the body of the coroutine as written. This will be either + /// a CompoundStmt or a TryStmt. + Stmt *getBody() const { + return SubStmts[SubStmt::Body]; + } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBody()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getBody()->getLocEnd(); + } + + child_range children() { + return child_range(SubStmts, SubStmts + SubStmt::Count); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoroutineBodyStmtClass; + } +}; + +/// \brief Represents a 'co_return' statement in the C++ Coroutines TS. +/// +/// This statament models the initialization of the coroutine promise +/// (encapsulating the eventual notional return value) from an expression +/// (or braced-init-list). +/// +/// This initialization is modeled 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; + + friend class ASTStmtReader; +public: + CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand) + : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc), + Operand(Operand), PromiseCall(nullptr) {} + + 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); } + + /// \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; } + + SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return Operand->getLocEnd(); + } + + child_range children() { + Stmt **Which = PromiseCall ? &PromiseCall : &Operand; + return child_range(Which, Which + 1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CoreturnStmtClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h index ac357bc667e..df4a2d8bc3d 100644 --- a/clang/include/clang/AST/StmtVisitor.h +++ b/clang/include/clang/AST/StmtVisitor.h @@ -94,6 +94,7 @@ public: case UO_Real: DISPATCH(UnaryReal, UnaryOperator); case UO_Imag: DISPATCH(UnaryImag, UnaryOperator); case UO_Extension: DISPATCH(UnaryExtension, UnaryOperator); + case UO_Coawait: DISPATCH(UnaryCoawait, UnaryOperator); } } @@ -158,7 +159,7 @@ public: UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) - UNARYOP_FALLBACK(Extension) + UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(Coawait) #undef UNARYOP_FALLBACK // Base case, ignore it. :) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9bf458d5136..6e90942cc42 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7839,7 +7839,8 @@ def err_module_import_in_implementation : Error< } let CategoryName = "Coroutines Issue" in { -def err_return_in_coroutine : Error<"return statement in coroutine">; +def err_return_in_coroutine : Error< + "return statement not allowed in coroutine; did you mean 'co_return'?">; def note_declared_coroutine_here : Note< "function is a coroutine due to use of " "'%select{co_await|co_yield|co_return}0' here">; @@ -7853,10 +7854,24 @@ def err_coroutine_constexpr : Error< "'%0' cannot be used in a constexpr function">; def err_coroutine_varargs : Error< "'%0' cannot be used in a varargs function">; -def ext_coroutine_without_coawait_coyield : ExtWarn< +def ext_coroutine_without_co_await_co_yield : ExtWarn< "'co_return' used in a function " "that uses neither 'co_await' nor 'co_yield'">, InGroup<DiagGroup<"coreturn-without-coawait">>; +def err_co_await_no_viable_function : Error< + "invalid co_await operand of type %0; " + "no viable '%1' function %select{|for awaited type %3 }2available">; +def err_implied_std_coroutine_traits_not_found : Error< + "you need to include <coroutine> before defining a coroutine">; +def err_malformed_std_coroutine_traits : Error< + "std::coroutine_traits must be a class template">; +def err_implied_std_coroutine_traits_promise_type_not_found : Error< + "this function cannot be a coroutine: %0 has no member named 'promise_type'">; +def err_implied_std_coroutine_traits_promise_type_not_class : Error< + "this function cannot be a coroutine: %0 is not a class">; +def err_coroutine_traits_missing_specialization : Error< + "this function cannot be a coroutine: missing definition of " + "specialization %0">; } let CategoryName = "Documentation Issue" in { diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 7bf7537bc90..6e665322e2d 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -48,6 +48,10 @@ def CXXCatchStmt : Stmt; def CXXTryStmt : Stmt; def CXXForRangeStmt : Stmt; +// C++ Coroutines TS statements +def CoroutineBodyStmt : Stmt; +def CoreturnStmt : Stmt; + // Expressions def Expr : Stmt<1>; def PredefinedExpr : DStmt<Expr>; @@ -140,6 +144,10 @@ def MaterializeTemporaryExpr : DStmt<Expr>; def LambdaExpr : DStmt<Expr>; def CXXFoldExpr : DStmt<Expr>; +// C++ Coroutines TS expressions +def CoawaitExpr : DStmt<Expr>; +def CoyieldExpr : DStmt<Expr>; + // Obj-C Expressions. def ObjCStringLiteral : DStmt<Expr>; def ObjCBoxedExpr : DStmt<Expr>; diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index bc0fd20195f..8f29d7c34c1 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -89,40 +89,43 @@ protected: public: /// \brief What kind of scope we are describing. /// - ScopeKind Kind; + ScopeKind Kind : 2; /// \brief Whether this function contains a VLA, \@try, try, C++ /// initializer, or anything else that can't be jumped past. - bool HasBranchProtectedScope; + bool HasBranchProtectedScope : 1; /// \brief Whether this function contains any switches or direct gotos. - bool HasBranchIntoScope; + bool HasBranchIntoScope : 1; /// \brief Whether this function contains any indirect gotos. - bool HasIndirectGoto; + bool HasIndirectGoto : 1; /// \brief Whether a statement was dropped because it was invalid. - bool HasDroppedStmt; + bool HasDroppedStmt : 1; /// A flag that is set when parsing a method that must call super's /// implementation, such as \c -dealloc, \c -finalize, or any method marked /// with \c __attribute__((objc_requires_super)). - bool ObjCShouldCallSuper; + bool ObjCShouldCallSuper : 1; /// True when this is a method marked as a designated initializer. - bool ObjCIsDesignatedInit; + bool ObjCIsDesignatedInit : 1; /// This starts true for a method marked as designated initializer and will /// be set to false if there is an invocation to a designated initializer of /// the super class. - bool ObjCWarnForNoDesignatedInitChain; + bool ObjCWarnForNoDesignatedInitChain : 1; /// True when this is an initializer method not marked as a designated /// initializer within a class that has at least one initializer marked as a /// designated initializer. - bool ObjCIsSecondaryInit; + bool ObjCIsSecondaryInit : 1; /// This starts true for a secondary initializer method and will be set to /// false if there is an invocation of an initializer on 'self'. - bool ObjCWarnForNoInitDelegation; + bool ObjCWarnForNoInitDelegation : 1; + + /// First 'return' statement in the current function. + SourceLocation FirstReturnLoc; /// First C++ 'try' statement in the current function. SourceLocation FirstCXXTryLoc; @@ -142,6 +145,9 @@ public: /// optimization, or if we need to infer a return type. SmallVector<ReturnStmt*, 4> Returns; + /// \brief The promise object for this coroutine, if any. + VarDecl *CoroutinePromise; + /// \brief The list of coroutine control flow constructs (co_await, co_yield, /// co_return) that occur within the function or block. Empty if and only if /// this function or block is not (yet known to be) a coroutine. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4415e7b57a1..3ee700efc3c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2492,17 +2492,8 @@ public: FRS_DiagnosticIssued }; - // An enum to represent whether something is dealing with a call to begin() - // or a call to end() in a range-based for loop. - enum BeginEndFunction { - BEF_begin, - BEF_end - }; - - ForRangeStatus BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, + ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, SourceLocation RangeLoc, - VarDecl *Decl, - BeginEndFunction BEF, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, @@ -3324,7 +3315,7 @@ public: BFRK_Check }; - StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, + StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, @@ -7699,10 +7690,14 @@ public: //===--------------------------------------------------------------------===// // C++ Coroutines TS // - ExprResult ActOnCoawaitExpr(SourceLocation KwLoc, Expr *E); - ExprResult ActOnCoyieldExpr(SourceLocation KwLoc, Expr *E); + ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); + ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E); + ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E); + ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); + StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E); + void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body); //===--------------------------------------------------------------------===// |

