diff options
Diffstat (limited to 'clang/lib/Sema/SemaCoroutine.cpp')
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp new file mode 100644 index 00000000000..6545b6709a2 --- /dev/null +++ b/clang/lib/Sema/SemaCoroutine.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. +} |