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 } 107