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