forked from OSchip/llvm-project
107 lines
3.6 KiB
C++
107 lines
3.6 KiB
C++
//===--- 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.
|
|
}
|