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