blob: 6545b6709a202bc8ff273aacba9bfa370486661b [file] [log] [blame]
Richard Smithcfd53b42015-10-22 06:13:50 +00001//===--- 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"
15using namespace clang;
16using namespace sema;
17
18static FunctionScopeInfo *
19checkCoroutineContext(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
51ExprResult 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
60ExprResult 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
69StmtResult 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
78void 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}