forked from OSchip/llvm-project
[coroutines] Initial stub Sema functionality for handling coroutine await / yield / return.
llvm-svn: 250993
This commit is contained in:
parent
f8bdb0a9e4
commit
cfd53b4e99
|
@ -7827,6 +7827,27 @@ def err_module_import_in_implementation : Error<
|
|||
"@import of module '%0' in implementation of '%1'; use #import">;
|
||||
}
|
||||
|
||||
let CategoryName = "Coroutines Issue" in {
|
||||
def err_return_in_coroutine : Error<"return statement in coroutine">;
|
||||
def note_declared_coroutine_here : Note<
|
||||
"function is a coroutine due to use of "
|
||||
"'%select{co_await|co_yield|co_return}0' here">;
|
||||
def err_coroutine_objc_method : Error<
|
||||
"Objective-C methods as coroutines are not yet supported">;
|
||||
def err_coroutine_outside_function : Error<
|
||||
"'%0' cannot be used outside a function">;
|
||||
def err_coroutine_ctor_dtor : Error<
|
||||
"'%1' cannot be used in a %select{constructor|destructor}0">;
|
||||
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<
|
||||
"'co_return' used in a function "
|
||||
"that uses neither 'co_await' nor 'co_yield'">,
|
||||
InGroup<DiagGroup<"coreturn-without-coawait">>;
|
||||
}
|
||||
|
||||
let CategoryName = "Documentation Issue" in {
|
||||
def warn_not_a_doxygen_trailing_member_comment : Warning<
|
||||
"not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore;
|
||||
|
|
|
@ -142,6 +142,11 @@ public:
|
|||
/// optimization, or if we need to infer a return type.
|
||||
SmallVector<ReturnStmt*, 4> Returns;
|
||||
|
||||
/// \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.
|
||||
SmallVector<Stmt*, 4> CoroutineStmts;
|
||||
|
||||
/// \brief The stack of currently active compound stamement scopes in the
|
||||
/// function.
|
||||
SmallVector<CompoundScopeInfo, 4> CompoundScopes;
|
||||
|
|
|
@ -3334,11 +3334,14 @@ public:
|
|||
BFRK_Check
|
||||
};
|
||||
|
||||
StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *LoopVar,
|
||||
StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc,
|
||||
SourceLocation CoawaitLoc,
|
||||
Stmt *LoopVar,
|
||||
SourceLocation ColonLoc, Expr *Collection,
|
||||
SourceLocation RParenLoc,
|
||||
BuildForRangeKind Kind);
|
||||
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
|
||||
SourceLocation CoawaitLoc,
|
||||
SourceLocation ColonLoc,
|
||||
Stmt *RangeDecl, Stmt *BeginEndDecl,
|
||||
Expr *Cond, Expr *Inc,
|
||||
|
@ -7703,7 +7706,18 @@ public:
|
|||
void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
|
||||
Expr *MinBlocks, unsigned SpellingListIndex);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Coroutines TS
|
||||
//
|
||||
ExprResult ActOnCoawaitExpr(SourceLocation KwLoc, Expr *E);
|
||||
ExprResult ActOnCoyieldExpr(SourceLocation KwLoc, Expr *E);
|
||||
StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E);
|
||||
|
||||
void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// OpenMP directives and clauses.
|
||||
//
|
||||
private:
|
||||
void *VarDataSharingAttributesStack;
|
||||
/// \brief Initialization of data-sharing attributes stack.
|
||||
|
|
|
@ -1045,10 +1045,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
}
|
||||
|
||||
case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression
|
||||
SourceLocation SavedLoc = ConsumeToken();
|
||||
SourceLocation CoawaitLoc = ConsumeToken();
|
||||
Res = ParseCastExpression(false);
|
||||
(void)SavedLoc;
|
||||
// FIXME: Pass to Sema.
|
||||
if (!Res.isInvalid())
|
||||
Res = Actions.ActOnCoawaitExpr(CoawaitLoc, Res.get());
|
||||
return Res;
|
||||
}
|
||||
|
||||
|
|
|
@ -1567,8 +1567,8 @@ ExprResult Parser::ParseCoyieldExpression() {
|
|||
|
||||
SourceLocation Loc = ConsumeToken();
|
||||
ExprResult Expr = ParseAssignmentExpression();
|
||||
(void)Loc;
|
||||
// FIXME: Pass to Sema.
|
||||
if (!Expr.isInvalid())
|
||||
Expr = Actions.ActOnCoyieldExpr(Loc, Expr.get());
|
||||
return Expr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1691,8 +1691,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
|||
StmtResult ForEachStmt;
|
||||
|
||||
if (ForRange) {
|
||||
// FIXME: Pass CoawaitLoc to Sema.
|
||||
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.get(),
|
||||
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc,
|
||||
FirstPart.get(),
|
||||
ForRangeInit.ColonLoc,
|
||||
ForRangeInit.RangeExpr.get(),
|
||||
T.getCloseLocation(),
|
||||
|
@ -1851,7 +1851,8 @@ StmtResult Parser::ParseReturnStatement() {
|
|||
return StmtError();
|
||||
}
|
||||
}
|
||||
// FIXME: Pass IsCoreturn to Sema.
|
||||
if (IsCoreturn)
|
||||
return Actions.ActOnCoreturnStmt(ReturnLoc, R.get());
|
||||
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ add_clang_library(clangSema
|
|||
SemaChecking.cpp
|
||||
SemaCodeComplete.cpp
|
||||
SemaConsumer.cpp
|
||||
SemaCoroutine.cpp
|
||||
SemaCUDA.cpp
|
||||
SemaDecl.cpp
|
||||
SemaDeclAttr.cpp
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
//===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements semantic analysis for C++ Coroutines.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
static FunctionScopeInfo *
|
||||
checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
|
||||
// 'co_await' and 'co_yield' are permitted in unevaluated operands.
|
||||
if (S.isUnevaluatedContext())
|
||||
return nullptr;
|
||||
|
||||
// Any other usage must be within a function.
|
||||
auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
|
||||
if (!FD) {
|
||||
S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
|
||||
? diag::err_coroutine_objc_method
|
||||
: diag::err_coroutine_outside_function) << Keyword;
|
||||
} else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) {
|
||||
// Coroutines TS [special]/6:
|
||||
// A special member function shall not be a coroutine.
|
||||
//
|
||||
// FIXME: We assume that this really means that a coroutine cannot
|
||||
// be a constructor or destructor.
|
||||
S.Diag(Loc, diag::err_coroutine_ctor_dtor)
|
||||
<< isa<CXXDestructorDecl>(FD) << Keyword;
|
||||
} else if (FD->isConstexpr()) {
|
||||
S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword;
|
||||
} else if (FD->isVariadic()) {
|
||||
S.Diag(Loc, diag::err_coroutine_varargs) << Keyword;
|
||||
} else {
|
||||
auto *ScopeInfo = S.getCurFunction();
|
||||
assert(ScopeInfo && "missing function scope for function");
|
||||
return ScopeInfo;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) {
|
||||
auto *Context = checkCoroutineContext(*this, Loc, "co_await");
|
||||
ExprResult Res = ExprError();
|
||||
|
||||
if (Context && !Res.isInvalid())
|
||||
Context->CoroutineStmts.push_back(Res.get());
|
||||
return Res;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) {
|
||||
auto *Context = checkCoroutineContext(*this, Loc, "co_yield");
|
||||
ExprResult Res = ExprError();
|
||||
|
||||
if (Context && !Res.isInvalid())
|
||||
Context->CoroutineStmts.push_back(Res.get());
|
||||
return Res;
|
||||
}
|
||||
|
||||
StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
|
||||
auto *Context = checkCoroutineContext(*this, Loc, "co_return");
|
||||
StmtResult Res = StmtError();
|
||||
|
||||
if (Context && !Res.isInvalid())
|
||||
Context->CoroutineStmts.push_back(Res.get());
|
||||
return Res;
|
||||
}
|
||||
|
||||
void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) {
|
||||
FunctionScopeInfo *Fn = getCurFunction();
|
||||
assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
|
||||
|
||||
// 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);
|
||||
auto *First = Fn->CoroutineStmts[0];
|
||||
Diag(First->getLocStart(), diag::note_declared_coroutine_here)
|
||||
<< 0; // FIXME: Indicate the kind here
|
||||
}
|
||||
|
||||
bool AnyCoawaits = false;
|
||||
bool AnyCoyields = false;
|
||||
for (auto *CoroutineStmt : Fn->CoroutineStmts) {
|
||||
(void)CoroutineStmt;
|
||||
AnyCoawaits = AnyCoyields = true; // FIXME
|
||||
}
|
||||
|
||||
if (!AnyCoawaits && !AnyCoyields)
|
||||
Diag(Fn->CoroutineStmts.front()->getLocStart(),
|
||||
diag::ext_coroutine_without_coawait_coyield);
|
||||
|
||||
// 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.
|
||||
}
|
|
@ -10907,6 +10907,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
|||
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
|
||||
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
|
||||
|
||||
if (getLangOpts().Coroutines && !getCurFunction()->CoroutineStmts.empty())
|
||||
CheckCompletedCoroutineBody(FD, Body);
|
||||
|
||||
if (FD) {
|
||||
FD->setBody(Body);
|
||||
|
||||
|
|
|
@ -1924,7 +1924,7 @@ 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,
|
||||
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
Stmt *First, SourceLocation ColonLoc, Expr *Range,
|
||||
SourceLocation RParenLoc, BuildForRangeKind Kind) {
|
||||
if (!First)
|
||||
|
@ -1948,6 +1948,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
|
|||
return StmtError();
|
||||
}
|
||||
|
||||
// Coroutines: 'for co_await' implicitly co_awaits its range.
|
||||
if (CoawaitLoc.isValid()) {
|
||||
ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range);
|
||||
if (Coawait.isInvalid()) return StmtError();
|
||||
Range = Coawait.get();
|
||||
}
|
||||
|
||||
// Build auto && __range = range-init
|
||||
SourceLocation RangeLoc = Range->getLocStart();
|
||||
VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
|
||||
|
@ -1969,7 +1976,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
|
|||
return StmtError();
|
||||
}
|
||||
|
||||
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
|
||||
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
|
||||
/*BeginEndDecl=*/nullptr, /*Cond=*/nullptr,
|
||||
/*Inc=*/nullptr, DS, RParenLoc, Kind);
|
||||
}
|
||||
|
@ -2063,6 +2070,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
|
|||
/// and emit no diagnostics.
|
||||
static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
|
||||
SourceLocation ForLoc,
|
||||
SourceLocation CoawaitLoc,
|
||||
Stmt *LoopVarDecl,
|
||||
SourceLocation ColonLoc,
|
||||
Expr *Range,
|
||||
|
@ -2079,7 +2087,7 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
|
|||
return StmtResult();
|
||||
|
||||
StmtResult SR =
|
||||
SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc,
|
||||
SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc,
|
||||
AdjustedRange.get(), RParenLoc,
|
||||
Sema::BFRK_Check);
|
||||
if (SR.isInvalid())
|
||||
|
@ -2091,7 +2099,7 @@ 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, LoopVarDecl, ColonLoc,
|
||||
return SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc,
|
||||
AdjustedRange.get(), RParenLoc,
|
||||
Sema::BFRK_Rebuild);
|
||||
}
|
||||
|
@ -2114,7 +2122,8 @@ struct InvalidateOnErrorScope {
|
|||
|
||||
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
|
||||
StmtResult
|
||||
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
||||
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
SourceLocation ColonLoc,
|
||||
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
|
||||
Expr *Inc, Stmt *LoopVarDecl,
|
||||
SourceLocation RParenLoc, BuildForRangeKind Kind) {
|
||||
|
@ -2244,6 +2253,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
|||
// If building the range failed, try dereferencing the range expression
|
||||
// unless a diagnostic was issued or the end function is problematic.
|
||||
StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
|
||||
CoawaitLoc,
|
||||
LoopVarDecl, ColonLoc,
|
||||
Range, RangeLoc,
|
||||
RParenLoc);
|
||||
|
@ -2314,7 +2324,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
|||
return StmtError();
|
||||
|
||||
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
|
||||
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
|
||||
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
|
||||
IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get());
|
||||
if (!IncrExpr.isInvalid())
|
||||
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
|
||||
if (IncrExpr.isInvalid()) {
|
||||
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
|
||||
<< RangeLoc << 2 << BeginRangeRef.get()->getType() ;
|
||||
|
@ -2351,6 +2364,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
|||
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);
|
||||
|
|
|
@ -1737,7 +1737,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
|
||||
SourceLocation CoawaitLoc; // FIXME
|
||||
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
|
||||
Range, BeginEnd,
|
||||
Cond, Inc, LoopVar, RParenLoc,
|
||||
Sema::BFRK_Rebuild);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s
|
||||
|
||||
void mixed_yield() {
|
||||
// FIXME: diagnose
|
||||
co_yield 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void mixed_await() {
|
||||
// FIXME: diagnose
|
||||
co_await 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void only_coreturn() {
|
||||
// FIXME: diagnose
|
||||
co_return;
|
||||
}
|
||||
|
||||
void mixed_coreturn(bool b) {
|
||||
// FIXME: diagnose
|
||||
if (b)
|
||||
co_return;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
struct CtorDtor {
|
||||
CtorDtor() {
|
||||
co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
|
||||
}
|
||||
CtorDtor(int n) {
|
||||
// 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}}
|
||||
}
|
||||
~CtorDtor() {
|
||||
co_return 0; // expected-error {{'co_return' cannot be used in a destructor}}
|
||||
}
|
||||
// FIXME: The spec says this is ill-formed.
|
||||
void operator=(CtorDtor&) {
|
||||
co_yield 0;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr void constexpr_coroutine() {
|
||||
co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
|
||||
}
|
||||
|
||||
void varargs_coroutine(const char *, ...) {
|
||||
co_await 0; // expected-error {{'co_await' cannot be used in a varargs function}}
|
||||
}
|
Loading…
Reference in New Issue