static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { // 'co_await' and 'co_yield' are not permitted in unevaluated operands. if (S.isUnevaluatedContext()) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; return false; } // Any other usage must be within a function. auto *FD = dyn_cast<FunctionDecl>(S.CurContext); if (!FD) { S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) ? diag::err_coroutine_objc_method : diag::err_coroutine_outside_function) << Keyword; return false; } // An enumeration for mapping the diagnostic type to the correct diagnostic // selection index. enum InvalidFuncDiag { DiagCtor = 0, DiagDtor, DiagCopyAssign, DiagMoveAssign, DiagMain, DiagConstexpr, DiagAutoRet, DiagVarargs, }; bool Diagnosed = false; auto DiagInvalid = [&](InvalidFuncDiag ID) { S.Diag(Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword; Diagnosed = true; return false; }; // Diagnose when a constructor, destructor, copy/move assignment operator, // or the function 'main' are declared as a coroutine. auto *MD = dyn_cast<CXXMethodDecl>(FD); if (MD && isa<CXXConstructorDecl>(MD)) return DiagInvalid(DiagCtor); else if (MD && isa<CXXDestructorDecl>(MD)) return DiagInvalid(DiagDtor); else if (MD && MD->isCopyAssignmentOperator()) return DiagInvalid(DiagCopyAssign); else if (MD && MD->isMoveAssignmentOperator()) return DiagInvalid(DiagMoveAssign); else if (FD->isMain()) return DiagInvalid(DiagMain); // Emit a diagnostics for each of the following conditions which is not met. if (FD->isConstexpr()) DiagInvalid(DiagConstexpr); if (FD->getReturnType()->isUndeducedType()) DiagInvalid(DiagAutoRet); if (FD->isVariadic()) DiagInvalid(DiagVarargs); return !Diagnosed; }