forked from OSchip/llvm-project
[coroutines] Creation of promise object, lookup of operator co_await, building
of await_* calls, and AST representation for same. llvm-svn: 251387
This commit is contained in:
parent
d5510d1e5c
commit
9f690bd80b
|
@ -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, {})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, {})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. :)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
if (Context && !Res.isInvalid())
|
||||
Context->CoroutineStmts.push_back(Res.get());
|
||||
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;
|
||||
|
||||
// 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.
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue