llvm/clang/lib/Sema/SemaCoroutine.cpp

//===-- SemaCoroutine.cpp - Semantic Analysis for Coroutines --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file implements semantic analysis for C++ Coroutines.
//
//  This file contains references to sections of the Coroutines TS, which
//  can be found at http://wg21.link/coroutines.
//
//===----------------------------------------------------------------------===//

#include "CoroutineStmtBuilder.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallSet.h"

usingnamespaceclang;
usingnamespacesema;

static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
                                 SourceLocation Loc, bool &Res) {}

static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
                         SourceLocation Loc) {}

/// Look up the std::coroutine_traits<...>::promise_type for the given
/// function type.
static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
                                  SourceLocation KwLoc) {}

/// Look up the std::coroutine_handle<PromiseType>.
static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
                                          SourceLocation Loc) {}

static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
                                    StringRef Keyword) {}

/// Build a call to 'operator co_await' if there is a suitable operator for
/// the given expression.
ExprResult Sema::BuildOperatorCoawaitCall(SourceLocation Loc, Expr *E,
                                          UnresolvedLookupExpr *Lookup) {}

static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
                                           SourceLocation Loc, Expr *E) {}

static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
                                       SourceLocation Loc) {}

struct ReadySuspendResumeResult {};

static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
                                  StringRef Name, MultiExprArg Args) {}

// See if return type is coroutine-handle and if so, invoke builtin coro-resume
// on its address. This is to enable the support for coroutine-handle
// returning await_suspend that results in a guaranteed tail call to the target
// coroutine.
static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
                           SourceLocation Loc) {}

/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
/// The generated AST tries to clean up temporary objects as early as
/// possible so that they don't live across suspension points if possible.
/// Having temporary objects living across suspension points unnecessarily can
/// lead to large frame size, and also lead to memory corruptions if the
/// coroutine frame is destroyed after coming back from suspension. This is done
/// by wrapping both the await_ready call and the await_suspend call with
/// ExprWithCleanups. In the end of this function, we also need to explicitly
/// set cleanup state so that the CoawaitExpr is also wrapped with an
/// ExprWithCleanups to clean up the awaiter associated with the co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
                                                  SourceLocation Loc, Expr *E) {}

static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
                                   SourceLocation Loc, StringRef Name,
                                   MultiExprArg Args) {}

VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {}

/// Check that this is a context in which a coroutine suspension can appear.
static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
                                                StringRef Keyword,
                                                bool IsImplicit = false) {}

/// Recursively check \p E and all its children to see if any call target
/// (including constructor call) is declared noexcept. Also any value returned
/// from the call has a noexcept destructor.
static void checkNoThrow(Sema &S, const Stmt *E,
                         llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) {}

bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {}

// [stmt.return.coroutine]p1:
//   A coroutine shall not enclose a return statement ([stmt.return]).
static void checkReturnStmtInCoroutine(Sema &S, FunctionScopeInfo *FSI) {}

bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
                                   StringRef Keyword) {}

// Recursively walks up the scope hierarchy until either a 'catch' or a function
// scope is found, whichever comes first.
static bool isWithinCatchScope(Scope *S) {}

// [expr.await]p2, emphasis added: "An await-expression shall appear only in
// a *potentially evaluated* expression within the compound-statement of a
// function-body *outside of a handler* [...] A context within a function
// where an await-expression can appear is called a suspension context of the
// function."
static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
                                   StringRef Keyword) {}

ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {}

ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {}

static bool isAttributedCoroAwaitElidable(const QualType &QT) {}

static void applySafeElideContext(Expr *Operand) {}

// Attempts to resolve and build a CoawaitExpr from "raw" inputs, bailing out to
// DependentCoawaitExpr if needed.
ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
                                            UnresolvedLookupExpr *Lookup) {}

ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
                                          Expr *Awaiter, bool IsImplicit) {}

ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {}
ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {}

StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {}

StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
                                   bool IsImplicit) {}

/// Look up the std::nothrow object.
static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {}

static TypeSourceInfo *getTypeSourceInfoForStdAlignValT(Sema &S,
                                                        SourceLocation Loc) {}

// Find an appropriate delete for the promise.
static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType,
                                 FunctionDecl *&OperatorDelete) {}


void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {}

static CompoundStmt *buildCoroutineBody(Stmt *Body, ASTContext &Context) {}

CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD,
                                           sema::FunctionScopeInfo &Fn,
                                           Stmt *Body)
    :{}

bool CoroutineStmtBuilder::buildStatements() {}

bool CoroutineStmtBuilder::buildDependentStatements() {}

bool CoroutineStmtBuilder::makePromiseStmt() {}

bool CoroutineStmtBuilder::makeInitialAndFinalSuspend() {}

static bool diagReturnOnAllocFailure(Sema &S, Expr *E,
                                     CXXRecordDecl *PromiseRecordDecl,
                                     FunctionScopeInfo &Fn) {}

bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {}

// Collect placement arguments for allocation function of coroutine FD.
// Return true if we collect placement arguments succesfully. Return false,
// otherwise.
static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
                                 SmallVectorImpl<Expr *> &PlacementArgs) {}

bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {}

bool CoroutineStmtBuilder::makeOnFallthrough() {}

bool CoroutineStmtBuilder::makeOnException() {}

bool CoroutineStmtBuilder::makeReturnObject() {}

static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) {}

bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {}

// Create a static_cast\<T&&>(expr).
static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) {}

/// Build a variable declaration for move parameter.
static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type,
                             IdentifierInfo *II) {}

// Build statements that move coroutine function parameters to the coroutine
// frame, and store them on the function scope info.
bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {}

StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {}

ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
                                               SourceLocation FuncLoc) {}