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 #include "clang/AST/Decl.h"
16 #include "clang/AST/ExprCXX.h"
17 #include "clang/AST/StmtCXX.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "clang/Sema/Overload.h"
20 using namespace clang;
21 using namespace sema;
22 
23 /// Look up the std::coroutine_traits<...>::promise_type for the given
24 /// function type.
25 static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
26                                   SourceLocation Loc) {
27   // FIXME: Cache std::coroutine_traits once we've found it.
28   NamespaceDecl *Std = S.getStdNamespace();
29   if (!Std) {
30     S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
31     return QualType();
32   }
33 
34   LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
35                       Loc, Sema::LookupOrdinaryName);
36   if (!S.LookupQualifiedName(Result, Std)) {
37     S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
38     return QualType();
39   }
40 
41   ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
42   if (!CoroTraits) {
43     Result.suppressDiagnostics();
44     // We found something weird. Complain about the first thing we found.
45     NamedDecl *Found = *Result.begin();
46     S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
47     return QualType();
48   }
49 
50   // Form template argument list for coroutine_traits<R, P1, P2, ...>.
51   TemplateArgumentListInfo Args(Loc, Loc);
52   Args.addArgument(TemplateArgumentLoc(
53       TemplateArgument(FnType->getReturnType()),
54       S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
55   // FIXME: If the function is a non-static member function, add the type
56   // of the implicit object parameter before the formal parameters.
57   for (QualType T : FnType->getParamTypes())
58     Args.addArgument(TemplateArgumentLoc(
59         TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
60 
61   // Build the template-id.
62   QualType CoroTrait =
63       S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args);
64   if (CoroTrait.isNull())
65     return QualType();
66   if (S.RequireCompleteType(Loc, CoroTrait,
67                             diag::err_coroutine_traits_missing_specialization))
68     return QualType();
69 
70   CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl();
71   assert(RD && "specialization of class template is not a class?");
72 
73   // Look up the ::promise_type member.
74   LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc,
75                  Sema::LookupOrdinaryName);
76   S.LookupQualifiedName(R, RD);
77   auto *Promise = R.getAsSingle<TypeDecl>();
78   if (!Promise) {
79     S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found)
80       << RD;
81     return QualType();
82   }
83 
84   // The promise type is required to be a class type.
85   QualType PromiseType = S.Context.getTypeDeclType(Promise);
86   if (!PromiseType->getAsCXXRecordDecl()) {
87     // Use the fully-qualified name of the type.
88     auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, Std);
89     NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
90                                       CoroTrait.getTypePtr());
91     PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
92 
93     S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
94       << PromiseType;
95     return QualType();
96   }
97 
98   return PromiseType;
99 }
100 
101 /// Check that this is a context in which a coroutine suspension can appear.
102 static FunctionScopeInfo *
103 checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
104   // 'co_await' and 'co_yield' are not permitted in unevaluated operands.
105   if (S.isUnevaluatedContext()) {
106     S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
107     return nullptr;
108   }
109 
110   // Any other usage must be within a function.
111   auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
112   if (!FD) {
113     S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
114                     ? diag::err_coroutine_objc_method
115                     : diag::err_coroutine_outside_function) << Keyword;
116   } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) {
117     // Coroutines TS [special]/6:
118     //   A special member function shall not be a coroutine.
119     //
120     // FIXME: We assume that this really means that a coroutine cannot
121     //        be a constructor or destructor.
122     S.Diag(Loc, diag::err_coroutine_ctor_dtor)
123       << isa<CXXDestructorDecl>(FD) << Keyword;
124   } else if (FD->isConstexpr()) {
125     S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword;
126   } else if (FD->isVariadic()) {
127     S.Diag(Loc, diag::err_coroutine_varargs) << Keyword;
128   } else {
129     auto *ScopeInfo = S.getCurFunction();
130     assert(ScopeInfo && "missing function scope for function");
131 
132     // If we don't have a promise variable, build one now.
133     if (!ScopeInfo->CoroutinePromise) {
134       QualType T =
135           FD->getType()->isDependentType()
136               ? S.Context.DependentTy
137               : lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(),
138                                   Loc);
139       if (T.isNull())
140         return nullptr;
141 
142       // Create and default-initialize the promise.
143       ScopeInfo->CoroutinePromise =
144           VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
145                           &S.PP.getIdentifierTable().get("__promise"), T,
146                           S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
147       S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
148       if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
149         S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false);
150     }
151 
152     return ScopeInfo;
153   }
154 
155   return nullptr;
156 }
157 
158 /// Build a call to 'operator co_await' if there is a suitable operator for
159 /// the given expression.
160 static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
161                                            SourceLocation Loc, Expr *E) {
162   UnresolvedSet<16> Functions;
163   SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
164                                        Functions);
165   return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
166 }
167 
168 struct ReadySuspendResumeResult {
169   bool IsInvalid;
170   Expr *Results[3];
171 };
172 
173 static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
174                                   StringRef Name,
175                                   MutableArrayRef<Expr *> Args) {
176   DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
177 
178   // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
179   CXXScopeSpec SS;
180   ExprResult Result = S.BuildMemberReferenceExpr(
181       Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
182       SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
183       /*Scope=*/nullptr);
184   if (Result.isInvalid())
185     return ExprError();
186 
187   return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
188 }
189 
190 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
191 /// expression.
192 static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
193                                                   Expr *E) {
194   // Assume invalid until we see otherwise.
195   ReadySuspendResumeResult Calls = {true, {}};
196 
197   const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
198   for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
199     Expr *Operand = new (S.Context) OpaqueValueExpr(
200         Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
201 
202     // FIXME: Pass coroutine handle to await_suspend.
203     ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
204     if (Result.isInvalid())
205       return Calls;
206     Calls.Results[I] = Result.get();
207   }
208 
209   Calls.IsInvalid = false;
210   return Calls;
211 }
212 
213 ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
214   if (E->getType()->isPlaceholderType()) {
215     ExprResult R = CheckPlaceholderExpr(E);
216     if (R.isInvalid()) return ExprError();
217     E = R.get();
218   }
219 
220   ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
221   if (Awaitable.isInvalid())
222     return ExprError();
223   return BuildCoawaitExpr(Loc, Awaitable.get());
224 }
225 ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
226   auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
227   if (!Coroutine)
228     return ExprError();
229 
230   if (E->getType()->isPlaceholderType()) {
231     ExprResult R = CheckPlaceholderExpr(E);
232     if (R.isInvalid()) return ExprError();
233     E = R.get();
234   }
235 
236   if (E->getType()->isDependentType()) {
237     Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
238     Coroutine->CoroutineStmts.push_back(Res);
239     return Res;
240   }
241 
242   // If the expression is a temporary, materialize it as an lvalue so that we
243   // can use it multiple times.
244   if (E->getValueKind() == VK_RValue)
245     E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
246 
247   // Build the await_ready, await_suspend, await_resume calls.
248   ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
249   if (RSS.IsInvalid)
250     return ExprError();
251 
252   Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
253                                         RSS.Results[2]);
254   Coroutine->CoroutineStmts.push_back(Res);
255   return Res;
256 }
257 
258 static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine,
259                                    SourceLocation Loc, StringRef Name,
260                                    MutableArrayRef<Expr *> Args) {
261   assert(Coroutine->CoroutinePromise && "no promise for coroutine");
262 
263   // Form a reference to the promise.
264   auto *Promise = Coroutine->CoroutinePromise;
265   ExprResult PromiseRef = S.BuildDeclRefExpr(
266       Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
267   if (PromiseRef.isInvalid())
268     return ExprError();
269 
270   // Call 'yield_value', passing in E.
271   return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
272 }
273 
274 ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
275   auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
276   if (!Coroutine)
277     return ExprError();
278 
279   // Build yield_value call.
280   ExprResult Awaitable =
281       buildPromiseCall(*this, Coroutine, Loc, "yield_value", E);
282   if (Awaitable.isInvalid())
283     return ExprError();
284 
285   // Build 'operator co_await' call.
286   Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
287   if (Awaitable.isInvalid())
288     return ExprError();
289 
290   return BuildCoyieldExpr(Loc, Awaitable.get());
291 }
292 ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
293   auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
294   if (!Coroutine)
295     return ExprError();
296 
297   if (E->getType()->isPlaceholderType()) {
298     ExprResult R = CheckPlaceholderExpr(E);
299     if (R.isInvalid()) return ExprError();
300     E = R.get();
301   }
302 
303   if (E->getType()->isDependentType()) {
304     Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
305     Coroutine->CoroutineStmts.push_back(Res);
306     return Res;
307   }
308 
309   // If the expression is a temporary, materialize it as an lvalue so that we
310   // can use it multiple times.
311   if (E->getValueKind() == VK_RValue)
312     E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
313 
314   // Build the await_ready, await_suspend, await_resume calls.
315   ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
316   if (RSS.IsInvalid)
317     return ExprError();
318 
319   Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
320                                         RSS.Results[2]);
321   Coroutine->CoroutineStmts.push_back(Res);
322   return Res;
323 }
324 
325 StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
326   return BuildCoreturnStmt(Loc, E);
327 }
328 StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
329   auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
330   if (!Coroutine)
331     return StmtError();
332 
333   if (E && E->getType()->isPlaceholderType() &&
334       !E->getType()->isSpecificPlaceholderType(BuiltinType::Overload)) {
335     ExprResult R = CheckPlaceholderExpr(E);
336     if (R.isInvalid()) return StmtError();
337     E = R.get();
338   }
339 
340   // FIXME: If the operand is a reference to a variable that's about to go out
341   // ot scope, we should treat the operand as an xvalue for this overload
342   // resolution.
343   ExprResult PC;
344   if (E && !E->getType()->isVoidType()) {
345     PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E);
346   } else {
347     E = MakeFullDiscardedValueExpr(E).get();
348     PC = buildPromiseCall(*this, Coroutine, Loc, "return_void", None);
349   }
350   if (PC.isInvalid())
351     return StmtError();
352 
353   Expr *PCE = ActOnFinishFullExpr(PC.get()).get();
354 
355   Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE);
356   Coroutine->CoroutineStmts.push_back(Res);
357   return Res;
358 }
359 
360 void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) {
361   FunctionScopeInfo *Fn = getCurFunction();
362   assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
363 
364   // Coroutines [stmt.return]p1:
365   //   A return statement shall not appear in a coroutine.
366   if (Fn->FirstReturnLoc.isValid()) {
367     Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
368     auto *First = Fn->CoroutineStmts[0];
369     Diag(First->getLocStart(), diag::note_declared_coroutine_here)
370       << (isa<CoawaitExpr>(First) ? 0 :
371           isa<CoyieldExpr>(First) ? 1 : 2);
372   }
373 
374   bool AnyCoawaits = false;
375   bool AnyCoyields = false;
376   for (auto *CoroutineStmt : Fn->CoroutineStmts) {
377     AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt);
378     AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt);
379   }
380 
381   if (!AnyCoawaits && !AnyCoyields)
382     Diag(Fn->CoroutineStmts.front()->getLocStart(),
383          diag::ext_coroutine_without_co_await_co_yield);
384 
385   // FIXME: Perform analysis of initial and final suspend,
386   // and set_exception call.
387 }
388