Richard Smith | cfd53b4 | 2015-10-22 06:13:50 +0000 | [diff] [blame] | 1 | //===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements semantic analysis for C++ Coroutines. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "clang/Sema/SemaInternal.h" |
| 15 | using namespace clang; |
| 16 | using namespace sema; |
| 17 | |
| 18 | static FunctionScopeInfo * |
| 19 | checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { |
| 20 | // 'co_await' and 'co_yield' are permitted in unevaluated operands. |
| 21 | if (S.isUnevaluatedContext()) |
| 22 | return nullptr; |
| 23 | |
| 24 | // Any other usage must be within a function. |
| 25 | auto *FD = dyn_cast<FunctionDecl>(S.CurContext); |
| 26 | if (!FD) { |
| 27 | S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) |
| 28 | ? diag::err_coroutine_objc_method |
| 29 | : diag::err_coroutine_outside_function) << Keyword; |
| 30 | } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) { |
| 31 | // Coroutines TS [special]/6: |
| 32 | // A special member function shall not be a coroutine. |
| 33 | // |
| 34 | // FIXME: We assume that this really means that a coroutine cannot |
| 35 | // be a constructor or destructor. |
| 36 | S.Diag(Loc, diag::err_coroutine_ctor_dtor) |
| 37 | << isa<CXXDestructorDecl>(FD) << Keyword; |
| 38 | } else if (FD->isConstexpr()) { |
| 39 | S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword; |
| 40 | } else if (FD->isVariadic()) { |
| 41 | S.Diag(Loc, diag::err_coroutine_varargs) << Keyword; |
| 42 | } else { |
| 43 | auto *ScopeInfo = S.getCurFunction(); |
| 44 | assert(ScopeInfo && "missing function scope for function"); |
| 45 | return ScopeInfo; |
| 46 | } |
| 47 | |
| 48 | return nullptr; |
| 49 | } |
| 50 | |
| 51 | ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) { |
| 52 | auto *Context = checkCoroutineContext(*this, Loc, "co_await"); |
| 53 | ExprResult Res = ExprError(); |
| 54 | |
| 55 | if (Context && !Res.isInvalid()) |
| 56 | Context->CoroutineStmts.push_back(Res.get()); |
| 57 | return Res; |
| 58 | } |
| 59 | |
| 60 | ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) { |
| 61 | auto *Context = checkCoroutineContext(*this, Loc, "co_yield"); |
| 62 | ExprResult Res = ExprError(); |
| 63 | |
| 64 | if (Context && !Res.isInvalid()) |
| 65 | Context->CoroutineStmts.push_back(Res.get()); |
| 66 | return Res; |
| 67 | } |
| 68 | |
| 69 | StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { |
| 70 | auto *Context = checkCoroutineContext(*this, Loc, "co_return"); |
| 71 | StmtResult Res = StmtError(); |
| 72 | |
| 73 | if (Context && !Res.isInvalid()) |
| 74 | Context->CoroutineStmts.push_back(Res.get()); |
| 75 | return Res; |
| 76 | } |
| 77 | |
| 78 | void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) { |
| 79 | FunctionScopeInfo *Fn = getCurFunction(); |
| 80 | assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine"); |
| 81 | |
| 82 | // Coroutines [stmt.return]p1: |
| 83 | // A return statement shall not appear in a coroutine. |
| 84 | if (!Fn->Returns.empty()) { |
| 85 | Diag(Fn->Returns.front()->getLocStart(), diag::err_return_in_coroutine); |
| 86 | auto *First = Fn->CoroutineStmts[0]; |
| 87 | Diag(First->getLocStart(), diag::note_declared_coroutine_here) |
| 88 | << 0; // FIXME: Indicate the kind here |
| 89 | } |
| 90 | |
| 91 | bool AnyCoawaits = false; |
| 92 | bool AnyCoyields = false; |
| 93 | for (auto *CoroutineStmt : Fn->CoroutineStmts) { |
| 94 | (void)CoroutineStmt; |
| 95 | AnyCoawaits = AnyCoyields = true; // FIXME |
| 96 | } |
| 97 | |
| 98 | if (!AnyCoawaits && !AnyCoyields) |
| 99 | Diag(Fn->CoroutineStmts.front()->getLocStart(), |
| 100 | diag::ext_coroutine_without_coawait_coyield); |
| 101 | |
| 102 | // FIXME: If we have a deduced return type, resolve it now. |
| 103 | // FIXME: Compute the promise type. |
| 104 | // FIXME: Perform analysis of initial and final suspend, and set_exception call. |
| 105 | // FIXME: Complete the semantic analysis of the CoroutineStmts. |
| 106 | } |