summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h8
-rw-r--r--include/clang/AST/ExprCXX.h123
-rw-r--r--include/clang/AST/OperationKinds.h3
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h30
-rw-r--r--include/clang/AST/StmtCXX.h100
-rw-r--r--include/clang/AST/StmtVisitor.h3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td19
-rw-r--r--include/clang/Basic/StmtNodes.td8
-rw-r--r--include/clang/Sema/ScopeInfo.h26
-rw-r--r--include/clang/Sema/Sema.h21
-rw-r--r--lib/AST/ASTImporter.cpp5
-rw-r--r--lib/AST/Expr.cpp8
-rw-r--r--lib/AST/ExprClassification.cpp4
-rw-r--r--lib/AST/ExprConstant.cpp3
-rw-r--r--lib/AST/ItaniumMangle.cpp12
-rw-r--r--lib/AST/StmtCXX.cpp6
-rw-r--r--lib/AST/StmtPrinter.cpp25
-rw-r--r--lib/AST/StmtProfile.cpp16
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp1
-rw-r--r--lib/CodeGen/CGStmt.cpp4
-rw-r--r--lib/Parse/ParseExpr.cpp2
-rw-r--r--lib/Parse/ParseExprCXX.cpp2
-rw-r--r--lib/Parse/ParseStmt.cpp11
-rw-r--r--lib/Sema/ScopeInfo.cpp2
-rw-r--r--lib/Sema/SemaCoroutine.cpp231
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp1
-rw-r--r--lib/Sema/SemaOverload.cpp20
-rw-r--r--lib/Sema/SemaStmt.cpp83
-rw-r--r--lib/Sema/TreeTransform.h78
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp27
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp21
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp4
-rw-r--r--test/Parser/cxx1z-coroutines.cpp2
-rw-r--r--test/SemaCXX/coroutines.cpp88
-rw-r--r--tools/libclang/CXCursor.cpp4
36 files changed, 871 insertions, 132 deletions
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 46dcb6ca7b..25e2c069ba 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/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/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index e8493f1933..055542650f 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/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/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index e3f0126677..2235c1012f 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/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/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 2fabfa988e..341acd99e0 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/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/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 567a772884..1dfc74425e 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/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/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index ac357bc667..df4a2d8bc3 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9bf458d513..6e90942cc4 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/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/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 7bf7537bc9..6e665322e2 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/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/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index bc0fd20195..8f29d7c34c 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 4415e7b57a..3ee700efc3 100644
--- a/include/clang/Sema/Sema.h
+++ b/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);
//===--------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 6816dd11d9..ccc6931a5f 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -4915,13 +4915,14 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
if (!ToBody && S->getBody())
return nullptr;
SourceLocation ToForLoc = Importer.Import(S->getForLoc());
+ SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd,
ToCond, ToInc,
ToLoopVar, ToBody,
- ToForLoc, ToColonLoc,
- ToRParenLoc);
+ ToForLoc, ToCoawaitLoc,
+ ToColonLoc, ToRParenLoc);
}
Stmt *ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1dd54d293d..dbc890d292 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1079,6 +1079,7 @@ StringRef UnaryOperator::getOpcodeStr(Opcode Op) {
case UO_Real: return "__real";
case UO_Imag: return "__imag";
case UO_Extension: return "__extension__";
+ case UO_Coawait: return "co_await";
}
llvm_unreachable("Unknown unary operator");
}
@@ -1095,6 +1096,7 @@ UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
case OO_Minus: return UO_Minus;
case OO_Tilde: return UO_Not;
case OO_Exclaim: return UO_LNot;
+ case OO_Coawait: return UO_Coawait;
}
}
@@ -1108,6 +1110,7 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
case UO_Minus: return OO_Minus;
case UO_Not: return OO_Tilde;
case UO_LNot: return OO_Exclaim;
+ case UO_Coawait: return OO_Coawait;
default: return OO_None;
}
}
@@ -2050,6 +2053,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case UO_LNot:
case UO_Deref:
break;
+ case UO_Coawait:
+ // This is just the 'operator co_await' call inside the guts of a
+ // dependent co_await call.
case UO_PostInc:
case UO_PostDec:
case UO_PreInc:
@@ -3005,6 +3011,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXNewExprClass:
case CXXDeleteExprClass:
case ExprWithCleanupsClass:
+ case CoawaitExprClass:
+ case CoyieldExprClass:
// These always have a side-effect.
return true;
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 882c786c35..a5a44353a2 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -186,6 +186,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXFoldExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
+ case Expr::CoyieldExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -397,6 +398,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
"Only 1-element init lists can be glvalues.");
return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
+
+ case Expr::CoawaitExprClass:
+ return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
}
llvm_unreachable("unhandled expression kind in classification");
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 08fcd260a3..e59902ddd8 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -9017,6 +9017,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::AtomicExprClass:
case Expr::LambdaExprClass:
case Expr::CXXFoldExprClass:
+ case Expr::CoawaitExprClass:
+ case Expr::CoyieldExprClass:
return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::InitListExprClass: {
@@ -9102,6 +9104,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case UO_PreDec:
case UO_AddrOf:
case UO_Deref:
+ case UO_Coawait:
// C99 6.6/3 allows increment and decrement within unevaluated
// subexpressions of constant expressions, but they can never be ICEs
// because an ICE cannot contain an lvalue operand.
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 86bc8e6775..c3432839c2 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -3514,6 +3514,18 @@ recurse:
case Expr::CXXThisExprClass:
Out << "fpT";
break;
+
+ case Expr::CoawaitExprClass:
+ // FIXME: Propose a non-vendor mangling.
+ Out << "v18co_await";
+ mangleExpression(cast<CoawaitExpr>(E)->getOperand());
+ break;
+
+ case Expr::CoyieldExprClass:
+ // FIXME: Propose a non-vendor mangling.
+ Out << "v18co_yield";
+ mangleExpression(cast<CoawaitExpr>(E)->getOperand());
+ break;
}
}
diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp
index aa721468e2..e39a01daf9 100644
--- a/lib/AST/StmtCXX.cpp
+++ b/lib/AST/StmtCXX.cpp
@@ -52,8 +52,10 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
Stmt *Body, SourceLocation FL,
- SourceLocation CL, SourceLocation RPL)
- : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
+ SourceLocation CAL, SourceLocation CL,
+ SourceLocation RPL)
+ : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
+ RParenLoc(RPL) {
SubExprs[RANGE] = Range;
SubExprs[BEGINEND] = BeginEndStmt;
SubExprs[COND] = Cond;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index bf155f5680..52aa59e252 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -2163,6 +2163,31 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << ")";
}
+// C++ Coroutines TS
+
+void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+ Visit(S->getBody());
+}
+
+void StmtPrinter::VisitCoreturnStmt(CoreturnStmt *S) {
+ OS << "co_return";
+ if (S->getOperand()) {
+ OS << " ";
+ Visit(S->getOperand());
+ }
+ OS << ";";
+}
+
+void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
+ OS << "co_await ";
+ PrintExpr(S->getOperand());
+}
+
+void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) {
+ OS << "co_yield ";
+ PrintExpr(S->getOperand());
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 93b80e5d99..28507c1e53 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -1362,6 +1362,22 @@ void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
ID.AddInteger(S->getOperator());
}
+void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitCoreturnStmt(const CoreturnStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitCoyieldExpr(const CoyieldExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
VisitExpr(E);
}
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
index 0b564398db..ffe95ea22a 100644
--- a/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -445,6 +445,7 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
case UO_Real:
case UO_Imag:
case UO_Extension:
+ case UO_Coawait:
return new (Arena) til::Undefined(UO);
}
return new (Arena) til::Undefined(UO);
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index f915518c26..b1cb395b8e 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -141,6 +141,10 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::GCCAsmStmtClass: // Intentional fall-through.
case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CoreturnStmtClass:
+ CGM.ErrorUnsupported(S, "coroutine");
+ break;
case Stmt::CapturedStmtClass: {
const CapturedStmt *CS = cast<CapturedStmt>(S);
EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index f3316461ac..490bd5ada6 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1048,7 +1048,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation CoawaitLoc = ConsumeToken();
Res = ParseCastExpression(false);
if (!Res.isInvalid())
- Res = Actions.ActOnCoawaitExpr(CoawaitLoc, Res.get());
+ Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get());
return Res;
}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index bd9b9f9731..d5f188104e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1568,7 +1568,7 @@ ExprResult Parser::ParseCoyieldExpression() {
SourceLocation Loc = ConsumeToken();
ExprResult Expr = ParseAssignmentExpression();
if (!Expr.isInvalid())
- Expr = Actions.ActOnCoyieldExpr(Loc, Expr.get());
+ Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get());
return Expr;
}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index af7008f8e7..35cb0fef78 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1691,13 +1691,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
StmtResult ForEachStmt;
if (ForRange) {
- ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc,
- FirstPart.get(),
- ForRangeInit.ColonLoc,
- ForRangeInit.RangeExpr.get(),
- T.getCloseLocation(),
- Sema::BFRK_Build);
-
+ ForRangeStmt = Actions.ActOnCXXForRangeStmt(
+ getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
+ ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(),
+ T.getCloseLocation(), Sema::BFRK_Build);
// Similarly, we need to do the semantic analysis for a for-range
// statement immediately in order to close over temporaries correctly.
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index ba8c3642bc..6a400a2efe 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -33,11 +33,13 @@ void FunctionScopeInfo::Clear() {
ObjCWarnForNoDesignatedInitChain = false;
ObjCIsSecondaryInit = false;
ObjCWarnForNoInitDelegation = false;
+ FirstReturnLoc = SourceLocation();
FirstCXXTryLoc = SourceLocation();
FirstSEHTryLoc = SourceLocation();
SwitchStack.clear();
Returns.clear();
+ CoroutineStmts.clear();
ErrorTrap.reset();
PossiblyUnreachableDiags.clear();
WeakObjectUses.clear();
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index 6545b6709a..a2a79001f0 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -12,12 +12,89 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Overload.h"
using namespace clang;
using namespace sema;
+/// Look up the std::coroutine_traits<...>::promise_type for the given
+/// function type.
+static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
+ SourceLocation Loc) {
+ // FIXME: Cache std::coroutine_traits once we've found it.
+ NamespaceDecl *Std = S.getStdNamespace();
+ if (!Std) {
+ S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+ return QualType();
+ }
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
+ Loc, Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Result, Std)) {
+ S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+ return QualType();
+ }
+
+ ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
+ if (!CoroTraits) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
+ return QualType();
+ }
+
+ // Form template argument list for coroutine_traits<R, P1, P2, ...>.
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(TemplateArgumentLoc(
+ TemplateArgument(FnType->getReturnType()),
+ S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
+ for (QualType T : FnType->getParamTypes())
+ Args.addArgument(TemplateArgumentLoc(
+ TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
+
+ // Build the template-id.
+ QualType CoroTrait =
+ S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args);
+ if (CoroTrait.isNull())
+ return QualType();
+ if (S.RequireCompleteType(Loc, CoroTrait,
+ diag::err_coroutine_traits_missing_specialization))
+ return QualType();
+
+ CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl();
+ assert(RD && "specialization of class template is not a class?");
+
+ // Look up the ::promise_type member.
+ LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc,
+ Sema::LookupOrdinaryName);
+ S.LookupQualifiedName(R, RD);
+ auto *Promise = R.getAsSingle<TypeDecl>();
+ if (!Promise) {
+ S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found)
+ << RD;
+ return QualType();
+ }
+
+ // The promise type is required to be a class type.
+ QualType PromiseType = S.Context.getTypeDeclType(Promise);
+ if (!PromiseType->getAsCXXRecordDecl()) {
+ S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
+ << PromiseType;
+ return QualType();
+ }
+
+ return PromiseType;
+}
+
+/// Check that this is a context in which a coroutine suspension can appear.
static FunctionScopeInfo *
checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
// 'co_await' and 'co_yield' are permitted in unevaluated operands.
+ // FIXME: Not in 'noexcept'.
if (S.isUnevaluatedContext())
return nullptr;
@@ -42,36 +119,143 @@ checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
} else {
auto *ScopeInfo = S.getCurFunction();
assert(ScopeInfo && "missing function scope for function");
+
+ // If we don't have a promise variable, build one now.
+ if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) {
+ QualType T =
+ lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc);
+ if (T.isNull())
+ return nullptr;
+
+ // Create and default-initialize the promise.
+ ScopeInfo->CoroutinePromise =
+ VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
+ &S.PP.getIdentifierTable().get("__promise"), T,
+ S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
+ S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
+ if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
+ S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false);
+ }
+
return ScopeInfo;
}
return nullptr;
}
-ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) {
- auto *Context = checkCoroutineContext(*this, Loc, "co_await");
- ExprResult Res = ExprError();
+/// Build a call to 'operator co_await' if there is a suitable operator for
+/// the given expression.
+static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
+ SourceLocation Loc, Expr *E) {
+ UnresolvedSet<16> Functions;
+ SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
+ Functions);
+ return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
+}
+
+struct ReadySuspendResumeResult {
+ bool IsInvalid;
+ Expr *Results[3];
+};
+
+/// Build calls to await_ready, await_suspend, and await_resume for a co_await
+/// expression.
+static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
+ Expr *E) {
+ // Assume invalid until we see otherwise.
+ ReadySuspendResumeResult Calls = {true, {}};
+
+ const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
+ for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
+ DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc);
+
+ Expr *Operand = new (S.Context) OpaqueValueExpr(
+ Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E);
+
+ // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
+ CXXScopeSpec SS;
+ ExprResult Result = S.BuildMemberReferenceExpr(
+ Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS,
+ SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
+ /*Scope=*/nullptr);
+ if (Result.isInvalid())
+ return Calls;
- if (Context && !Res.isInvalid())
- Context->CoroutineStmts.push_back(Res.get());
+ // FIXME: Pass coroutine handle to await_suspend.
+ Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr);
+ if (Result.isInvalid())
+ return Calls;
+ Calls.Results[I] = Result.get();
+ }
+
+ Calls.IsInvalid = false;
+ return Calls;
+}
+
+ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ if (Awaitable.isInvalid())
+ return ExprError();
+ return BuildCoawaitExpr(Loc, Awaitable.get());
+}
+ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
+
+ if (E->getType()->isDependentType()) {
+ Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
+ if (Coroutine)
+ Coroutine->CoroutineStmts.push_back(Res);
+ return Res;
+ }
+
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(E);
+ if (R.isInvalid()) return ExprError();
+ E = R.get();
+ }
+
+ // 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) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2]);
+ if (Coroutine)
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
-ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) {
- auto *Context = checkCoroutineContext(*this, Loc, "co_yield");
- ExprResult Res = ExprError();
+ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ // FIXME: Build yield_value call.
+ ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ if (Awaitable.isInvalid())
+ return ExprError();
+ return BuildCoyieldExpr(Loc, Awaitable.get());
+}
+ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
- if (Context && !Res.isInvalid())
- Context->CoroutineStmts.push_back(Res.get());
+ // FIXME: Build await_* calls.
+ Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E);
+ if (Coroutine)
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
- auto *Context = checkCoroutineContext(*this, Loc, "co_return");
- StmtResult Res = StmtError();
+ return BuildCoreturnStmt(Loc, E);
+}
+StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
- if (Context && !Res.isInvalid())
- Context->CoroutineStmts.push_back(Res.get());
+ // FIXME: Build return_* calls.
+ Stmt *Res = new (Context) CoreturnStmt(Loc, E);
+ if (Coroutine)
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
@@ -81,26 +265,25 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) {
// Coroutines [stmt.return]p1:
// A return statement shall not appear in a coroutine.
- if (!Fn->Returns.empty()) {
- Diag(Fn->Returns.front()->getLocStart(), diag::err_return_in_coroutine);
+ if (Fn->FirstReturnLoc.isValid()) {
+ Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
auto *First = Fn->CoroutineStmts[0];
Diag(First->getLocStart(), diag::note_declared_coroutine_here)
- << 0; // FIXME: Indicate the kind here
+ << (isa<CoawaitExpr>(First) ? 0 :
+ isa<CoyieldExpr>(First) ? 1 : 2);
}
bool AnyCoawaits = false;
bool AnyCoyields = false;
for (auto *CoroutineStmt : Fn->CoroutineStmts) {
- (void)CoroutineStmt;
- AnyCoawaits = AnyCoyields = true; // FIXME
+ AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt);
+ AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt);
}
if (!AnyCoawaits && !AnyCoyields)
Diag(Fn->CoroutineStmts.front()->getLocStart(),
- diag::ext_coroutine_without_coawait_coyield);
+ diag::ext_coroutine_without_co_await_co_yield);
- // FIXME: If we have a deduced return type, resolve it now.
- // FIXME: Compute the promise type.
- // FIXME: Perform analysis of initial and final suspend, and set_exception call.
- // FIXME: Complete the semantic analysis of the CoroutineStmts.
+ // FIXME: Perform analysis of initial and final suspend,
+ // and set_exception call.
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index a18824f155..f993a28a13 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -1063,8 +1063,10 @@ CanThrowResult Sema::canThrow(const Expr *E) {
// Many other things have subexpressions, so we have to test those.
// Some are simple:
+ case Expr::CoawaitExprClass:
case Expr::ConditionalOperatorClass:
case Expr::CompoundLiteralExprClass:
+ case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXStdInitializerListExprClass:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index badb2ef118..857925da99 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10901,6 +10901,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
break;
case UO_Extension:
+ case UO_Coawait:
resultType = Input.get()->getType();
VK = Input.get()->getValueKind();
OK = Input.get()->getObjectKind();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index d4a220037e..084e25a1cb 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -8228,15 +8228,16 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Array_New:
case OO_Array_Delete:
case OO_Call:
- case OO_Coawait:
llvm_unreachable(
"Special operators don't use AddBuiltinOperatorCandidates");
case OO_Comma:
case OO_Arrow:
+ case OO_Coawait:
// C++ [over.match.oper]p3:
- // -- For the operator ',', the unary operator '&', or the
- // operator '->', the built-in candidates set is empty.
+ // -- For the operator ',', the unary operator '&', the
+ // operator '->', or the operator 'co_await', the
+ // built-in candidates set is empty.
break;
case OO_Plus: // '+' is either unary or binary
@@ -12481,13 +12482,14 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
/// otherwise CallExpr is set to ExprError() and some non-success value
/// is returned.
Sema::ForRangeStatus
-Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
- SourceLocation RangeLoc, VarDecl *Decl,
- BeginEndFunction BEF,
+Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
+ SourceLocation RangeLoc,
const DeclarationNameInfo &NameInfo,
LookupResult &MemberLookup,
OverloadCandidateSet *CandidateSet,
Expr *Range, ExprResult *CallExpr) {
+ Scope *S = nullptr;
+
CandidateSet->clear();
if (!MemberLookup.empty()) {
ExprResult MemberRef =
@@ -12499,15 +12501,11 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
/*TemplateArgs=*/nullptr, S);
if (MemberRef.isInvalid()) {
*CallExpr = ExprError();
- Diag(Range->getLocStart(), diag::note_in_for_range)
- << RangeLoc << BEF << Range->getType();
return FRS_DiagnosticIssued;
}
*CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
- Diag(Range->getLocStart(), diag::note_in_for_range)
- << RangeLoc << BEF << Range->getType();
return FRS_DiagnosticIssued;
}
} else {
@@ -12538,8 +12536,6 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
/*AllowTypoCorrection=*/false);
if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
*CallExpr = ExprError();
- Diag(Range->getLocStart(), diag::note_in_for_range)
- << RangeLoc << BEF << Range->getType();
return FRS_DiagnosticIssued;
}
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index fec1200095..f8668c3893 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1859,13 +1859,19 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
}
namespace {
+// 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
+};
/// Produce a note indicating which begin/end function was implicitly called
/// by a C++11 for-range statement. This is often not obvious from the code,
/// nor from the diagnostics produced when analysing the implicit expressions
/// required in a for-range statement.
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
- Sema::BeginEndFunction BEF) {
+ BeginEndFunction BEF) {
CallExpr *CE = dyn_cast<CallExpr>(E);
if (!CE)
return;
@@ -1923,10 +1929,11 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
///
/// The body of the loop is not available yet, since it cannot be analysed until
/// we have determined the type of the for-range-declaration.
-StmtResult
-Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
- Stmt *First, SourceLocation ColonLoc, Expr *Range,
- SourceLocation RParenLoc, BuildForRangeKind Kind) {
+StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
+ SourceLocation CoawaitLoc, Stmt *First,
+ SourceLocation ColonLoc, Expr *Range,
+ SourceLocation RParenLoc,
+ BuildForRangeKind Kind) {
if (!First)
return StmtError();
@@ -1950,7 +1957,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// Coroutines: 'for co_await' implicitly co_awaits its range.
if (CoawaitLoc.isValid()) {
- ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range);
+ ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
if (Coawait.isInvalid()) return StmtError();
Range = Coawait.get();
}
@@ -1990,7 +1997,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
/// CandidateSet and BEF are set and some non-success value is returned on
/// failure.
-static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
+static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
Expr *BeginRange, Expr *EndRange,
QualType RangeType,
VarDecl *BeginVar,
@@ -1999,7 +2006,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
OverloadCandidateSet *CandidateSet,
ExprResult *BeginExpr,
ExprResult *EndExpr,
- Sema::BeginEndFunction *BEF) {
+ BeginEndFunction *BEF) {
DeclarationNameInfo BeginNameInfo(
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
@@ -2020,7 +2027,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
SourceLocation RangeLoc = BeginVar->getLocation();
- *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin;
+ *BEF = BeginMemberLookup.empty() ? BEF_end : BEF_begin;
SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch)
<< RangeLoc << BeginRange->getType() << *BEF;
@@ -2034,29 +2041,35 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
}
- *BEF = Sema::BEF_begin;
+ *BEF = BEF_begin;
Sema::ForRangeStatus RangeStatus =
- SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar,
- Sema::BEF_begin, BeginNameInfo,
+ SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, BeginNameInfo,
BeginMemberLookup, CandidateSet,
BeginRange, BeginExpr);
- if (RangeStatus != Sema::FRS_Success)
+ if (RangeStatus != Sema::FRS_Success) {
+ if (RangeStatus == Sema::FRS_DiagnosticIssued)
+ SemaRef.Diag(BeginRange->getLocStart(), diag::note_in_for_range)
+ << ColonLoc << BEF_begin << BeginRange->getType();
return RangeStatus;
+ }
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
return Sema::FRS_DiagnosticIssued;
}
- *BEF = Sema::BEF_end;
+ *BEF = BEF_end;
RangeStatus =
- SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar,
- Sema::BEF_end, EndNameInfo,
+ SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, EndNameInfo,
EndMemberLookup, CandidateSet,
EndRange, EndExpr);
- if (RangeStatus != Sema::FRS_Success)
+ if (RangeStatus != Sema::FRS_Success) {
+ if (RangeStatus == Sema::FRS_DiagnosticIssued)
+ SemaRef.Diag(EndRange->getLocStart(), diag::note_in_for_range)
+ << ColonLoc << BEF_end << EndRange->getType();
return RangeStatus;
+ }
if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF);
@@ -2086,10 +2099,9 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
if (AdjustedRange.isInvalid())
return StmtResult();
- StmtResult SR =
- SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc,
- AdjustedRange.get(), RParenLoc,
- Sema::BFRK_Check);
+ StmtResult SR = SemaRef.ActOnCXXForRangeStmt(
+ S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(),
+ RParenLoc, Sema::BFRK_Check);
if (SR.isInvalid())
return StmtResult();
}
@@ -2099,8 +2111,8 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
// case there are any other (non-fatal) problems with it.
SemaRef.Diag(RangeLoc, diag::err_for_range_dereference)
<< Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*");
- return SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc,
- AdjustedRange.get(), RParenLoc,
+ return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl,
+ ColonLoc, AdjustedRange.get(), RParenLoc,
Sema::BFRK_Rebuild);
}
@@ -2127,6 +2139,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
SourceLocation RParenLoc, BuildForRangeKind Kind) {
+ // FIXME: This should not be used during template instantiation. We should
+ // pick up the set of unqualified lookup results for the != and + operators
+ // in the initial parse.
+ //
+ // Testcase (accepts-invalid):
+ // template<typename T> void f() { for (auto x : T()) {} }
+ // namespace N { struct X { X begin(); X end(); int operator*(); }; }
+ // bool operator!=(N::X, N::X); void operator++(N::X);
+ // void g() { f<N::X>(); }
Scope *S = getCurScope();
DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
@@ -2226,9 +2247,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
} else {
OverloadCandidateSet CandidateSet(RangeLoc,
OverloadCandidateSet::CSK_Normal);
- Sema::BeginEndFunction BEFFailure;
+ BeginEndFunction BEFFailure;
ForRangeStatus RangeStatus =
- BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
+ BuildNonArrayForRange(*this, BeginRangeRef.get(),
EndRangeRef.get(), RangeType,
BeginVar, EndVar, ColonLoc, &CandidateSet,
&BeginExpr, &EndExpr, &BEFFailure);
@@ -2325,7 +2346,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
- IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get());
+ IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
if (!IncrExpr.isInvalid())
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
if (IncrExpr.isInvalid()) {
@@ -2364,10 +2385,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
if (Kind == BFRK_Check)
return StmtResult();
- // FIXME: Pass in CoawaitLoc in the dependent case.
return new (Context) CXXForRangeStmt(
RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(),
- IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, ColonLoc, RParenLoc);
+ IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
+ ColonLoc, RParenLoc);
}
/// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
@@ -2925,6 +2946,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (CurCap->HasImplicitReturnType || NRVOCandidate)
FunctionScopes.back()->Returns.push_back(Result);
+ if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
+ FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
+
return Result;
}
@@ -3291,6 +3315,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (Result->getNRVOCandidate())
FunctionScopes.back()->Returns.push_back(Result);
+ if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
+ FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
+
return Result;
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 117ae56969..176e57165f 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1287,6 +1287,30 @@ public:
Constraints, Clobbers, Exprs, EndLoc);
}
+ /// \brief Build a new co_return statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result) {
+ return getSema().BuildCoreturnStmt(CoreturnLoc, Result);
+ }
+
+ /// \brief Build a new co_await expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result) {
+ return getSema().BuildCoawaitExpr(CoawaitLoc, Result);
+ }
+
+ /// \brief Build a new co_yield expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildCoyieldExpr(SourceLocation CoyieldLoc, Expr *Result) {
+ return getSema().BuildCoyieldExpr(CoyieldLoc, Result);
+ }
+
/// \brief Build a new Objective-C \@try statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1715,6 +1739,7 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
+ SourceLocation CoawaitLoc,
SourceLocation ColonLoc,
Stmt *Range, Stmt *BeginEnd,
Expr *Cond, Expr *Inc,
@@ -1737,7 +1762,6 @@ public:
}
}
- SourceLocation CoawaitLoc; // FIXME
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
Range, BeginEnd,
Cond, Inc, LoopVar, RParenLoc,
@@ -6403,6 +6427,56 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
TransformedExprs, S->getEndLoc());
}
+// C++ Coroutines TS
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
+ // The coroutine body should be re-formed by the caller if necessary.
+ return getDerived().TransformStmt(S->getBody());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) {
+ ExprResult Result = getDerived().TransformInitializer(S->getOperand(),
+ /*NotCopyInit*/false);
+ if (Result.isInvalid())
+ return StmtError();
+
+ // Always rebuild; we don't know if this needs to be injected into a new
+ // context or if the promise type has changed.
+ return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) {
+ ExprResult Result = getDerived().TransformInitializer(E->getOperand(),
+ /*NotCopyInit*/false);
+ if (Result.isInvalid())
+ return ExprError();
+
+ // Always rebuild; we don't know if this needs to be injected into a new
+ // context or if the promise type has changed.
+ return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCoyieldExpr(CoyieldExpr *E) {
+ ExprResult Result = getDerived().TransformInitializer(E->getOperand(),
+ /*NotCopyInit*/false);
+ if (Result.isInvalid())
+ return ExprError();
+
+ // Always rebuild; we don't know if this needs to be injected into a new
+ // context or if the promise type has changed.
+ return getDerived().RebuildCoyieldExpr(E->getKeywordLoc(), Result.get());
+}
+
+// Objective-C Statements.
+
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
@@ -6692,6 +6766,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
Inc.get() != S->getInc() ||
LoopVar.get() != S->getLoopVarStmt()) {
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+ S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
BeginEnd.get(), Cond.get(),
Inc.get(), LoopVar.get(),
@@ -6708,6 +6783,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
// it now so we have a new statement to attach the body to.
if (Body.get() != S->getBody() && NewStmt.get() == S) {
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+ S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
BeginEnd.get(), Cond.get(),
Inc.get(), LoopVar.get(),
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 5f9f052292..ab82eee10e 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -381,6 +381,26 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
Constraints, Exprs, Clobbers);
}
+void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
++Idx;
@@ -1178,9 +1198,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
- S->setForLoc(ReadSourceLocation(Record, Idx));
- S->setColonLoc(ReadSourceLocation(Record, Idx));
- S->setRParenLoc(ReadSourceLocation(Record, Idx));
+ S->ForLoc = ReadSourceLocation(Record, Idx);
+ S->CoawaitLoc = ReadSourceLocation(Record, Idx);
+ S->ColonLoc = ReadSourceLocation(Record, Idx);
+ S->RParenLoc = ReadSourceLocation(Record, Idx);
S->setRangeStmt(Reader.ReadSubStmt());
S->setBeginEndStmt(Reader.ReadSubStmt());
S->setCond(Reader.ReadSubExpr());
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7fce321791..74dc56e72f 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -287,6 +287,26 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
Code = serialization::STMT_MSASM;
}
+void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
// NumCaptures
@@ -1135,6 +1155,7 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) {
void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getCoawaitLoc(), Record);
Writer.AddSourceLocation(S->getColonLoc(), Record);
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Writer.AddStmt(S->getRangeStmt());
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index eee4928c48..afef624f5d 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -765,6 +765,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::FunctionParmPackExprClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CoawaitExprClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CoyieldExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHLeaveStmtClass:
diff --git a/test/Parser/cxx1z-coroutines.cpp b/test/Parser/cxx1z-coroutines.cpp
index 3e698404a6..1ea2635aac 100644
--- a/test/Parser/cxx1z-coroutines.cpp
+++ b/test/Parser/cxx1z-coroutines.cpp
@@ -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;
+ auto y = co_yield t; // expected-error {{void}} FIXME
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}}
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp
index ae24dd2979..3e18187295 100644
--- a/test/SemaCXX/coroutines.cpp
+++ b/test/SemaCXX/coroutines.cpp
@@ -1,37 +1,68 @@
// RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s
+struct awaitable {
+ bool await_ready();
+ void await_suspend(); // FIXME: coroutine_handle
+ void await_resume();
+} a;
+
+void no_coroutine_traits() {
+ co_await a; // expected-error {{need to include <coroutine>}}
+}
+
+namespace std {
+ template<typename ...T> struct coroutine_traits; // expected-note {{declared here}}
+};
+
+void no_specialization() {
+ co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}}
+}
+
+template<typename ...T> struct std::coroutine_traits<int, T...> {};
+
+int no_promise_type() {
+ co_await a; // expected-error {{this function cannot be a coroutine: 'coroutine_traits<int>' has no member named 'promise_type'}}
+}
+
+struct promise; // expected-note {{forward declaration}}
+template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };
+
+ // FIXME: This diagnostic is terrible.
+void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
+ co_await a;
+}
+
+struct promise {};
+
void mixed_yield() {
- // FIXME: diagnose
- co_yield 0;
- return;
+ co_yield 0; // expected-note {{use of 'co_yield'}}
+ return; // expected-error {{not allowed in coroutine}}
}
void mixed_await() {
- // FIXME: diagnose
- co_await 0;
- return;
+ co_await a; // expected-note {{use of 'co_await'}}
+ return; // expected-error {{not allowed in coroutine}}
}
void only_coreturn() {
- // FIXME: diagnose
- co_return;
+ co_return; // expected-warning {{'co_return' used in a function that uses neither 'co_await' nor 'co_yield'}}
}
void mixed_coreturn(bool b) {
- // FIXME: diagnose
if (b)
- co_return;
+ // expected-warning@+1 {{'co_return' used in a function that uses neither}}
+ co_return; // expected-note {{use of 'co_return'}}
else
- return;
+ return; // expected-error {{not allowed in coroutine}}
}
struct CtorDtor {
CtorDtor() {
co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
}
- CtorDtor(int n) {
+ CtorDtor(awaitable a) {
// The spec doesn't say this is ill-formed, but it must be.
- co_await n; // expected-error {{'co_await' cannot be used in a constructor}}
+ co_await a; // expected-error {{'co_await' cannot be used in a constructor}}
}
~CtorDtor() {
co_return 0; // expected-error {{'co_return' cannot be used in a destructor}}
@@ -42,10 +73,35 @@ struct CtorDtor {
}
};
-constexpr void constexpr_coroutine() {
- co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
+constexpr void constexpr_coroutine() { // expected-error {{never produces a constant expression}}
+ co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} expected-note {{subexpression}}
}
void varargs_coroutine(const char *, ...) {
- co_await 0; // expected-error {{'co_await' cannot be used in a varargs function}}
+ co_await a; // expected-error {{'co_await' cannot be used in a varargs function}}
+}
+
+struct outer {};
+
+namespace dependent_operator_co_await_lookup {
+ template<typename T> void await_template(T t) {
+ // no unqualified lookup results
+ co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}}
+ // expected-error@-1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}}
+ };
+ template void await_template(awaitable);
+
+ struct indirectly_awaitable { indirectly_awaitable(outer); };
+ awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}}
+ template void await_template(indirectly_awaitable);
+
+ struct not_awaitable {};
+ template void await_template(not_awaitable); // expected-note {{instantiation}}
+
+ template<typename T> void await_template_2(T t) {
+ // one unqualified lookup result
+ co_await t;
+ };
+ template void await_template(outer); // expected-note {{instantiation}}
+ template void await_template_2(outer);
}
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 9a866c509d..0e47bf983d 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -227,6 +227,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::AtomicExprClass:
case Stmt::BinaryConditionalOperatorClass:
case Stmt::TypeTraitExprClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CoawaitExprClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CoyieldExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass: