llvm/clang/lib/CodeGen/ItaniumCXXABI.cpp

//===------- ItaniumCXXABI.cpp - Emit LLVM Code from ASTs for a Module ----===//
//
// 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 provides C++ code generation targeting the Itanium C++ ABI.  The class
// in this file generates structures that follow the Itanium C++ ABI, which is
// documented at:
//  https://itanium-cxx-abi.github.io/cxx-abi/abi.html
//  https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
// It also supports the closely-related ARM ABI, documented at:
// https://developer.arm.com/documentation/ihi0041/g/
//
//===----------------------------------------------------------------------===//

#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGRecordLayout.h"
#include "CGVTables.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/ScopedPrinter.h"

#include <optional>

usingnamespaceclang;
usingnamespaceCodeGen;

namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {};

class ARMCXXABI : public ItaniumCXXABI {};

class AppleARM64CXXABI : public ARMCXXABI {};

class FuchsiaCXXABI final : public ItaniumCXXABI {};

class WebAssemblyCXXABI final : public ItaniumCXXABI {};

class XLCXXABI final : public ItaniumCXXABI {};
}

CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {}

llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {}

/// In the Itanium and ARM ABIs, method pointers have the form:
///   struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr;
///
/// In the Itanium ABI:
///  - method pointers are virtual if (memptr.ptr & 1) is nonzero
///  - the this-adjustment is (memptr.adj)
///  - the virtual offset is (memptr.ptr - 1)
///
/// In the ARM ABI:
///  - method pointers are virtual if (memptr.adj & 1) is nonzero
///  - the this-adjustment is (memptr.adj >> 1)
///  - the virtual offset is (memptr.ptr)
/// ARM uses 'adj' for the virtual flag because Thumb functions
/// may be only single-byte aligned.
///
/// If the member is virtual, the adjusted 'this' pointer points
/// to a vtable pointer from which the virtual offset is applied.
///
/// If the member is non-virtual, memptr.ptr is the address of
/// the function to call.
CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
    CodeGenFunction &CGF, const Expr *E, Address ThisAddr,
    llvm::Value *&ThisPtrForCall,
    llvm::Value *MemFnPtr, const MemberPointerType *MPT) {}

/// Compute an l-value by applying the given pointer-to-member to a
/// base object.
llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
    CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
    const MemberPointerType *MPT) {}

// See if it's possible to return a constant signed pointer.
static llvm::Constant *pointerAuthResignConstant(
    llvm::Value *Ptr, const CGPointerAuthInfo &CurAuthInfo,
    const CGPointerAuthInfo &NewAuthInfo, CodeGenModule &CGM) {}

/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
/// conversion.
///
/// Bitcast conversions are always a no-op under Itanium.
///
/// Obligatory offset/adjustment diagram:
///         <-- offset -->          <-- adjustment -->
///   |--------------------------|----------------------|--------------------|
///   ^Derived address point     ^Base address point    ^Member address point
///
/// So when converting a base member pointer to a derived member pointer,
/// we add the offset to the adjustment because the address point has
/// decreased;  and conversely, when converting a derived MP to a base MP
/// we subtract the offset from the adjustment because the address point
/// has increased.
///
/// The standard forbids (at compile time) conversion to and from
/// virtual bases, which is why we don't have to consider them here.
///
/// The standard forbids (at run time) casting a derived MP to a base
/// MP when the derived MP does not point to a member of the base.
/// This is why -1 is a reasonable choice for null data member
/// pointers.
llvm::Value *
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
                                           const CastExpr *E,
                                           llvm::Value *src) {}

static llvm::Constant *
pointerAuthResignMemberFunctionPointer(llvm::Constant *Src, QualType DestType,
                                       QualType SrcType, CodeGenModule &CGM) {}

llvm::Constant *
ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
                                           llvm::Constant *src) {}

llvm::Constant *
ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {}

llvm::Constant *
ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
                                     CharUnits offset) {}

llvm::Constant *
ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {}

llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
                                                  CharUnits ThisAdjustment) {}

llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,
                                                 QualType MPType) {}

/// The comparison algorithm is pretty easy: the member pointers are
/// the same if they're either bitwise identical *or* both null.
///
/// ARM is different here only because null-ness is more complicated.
llvm::Value *
ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
                                           llvm::Value *L,
                                           llvm::Value *R,
                                           const MemberPointerType *MPT,
                                           bool Inequality) {}

llvm::Value *
ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
                                          llvm::Value *MemPtr,
                                          const MemberPointerType *MPT) {}

bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {}

/// The Itanium ABI requires non-zero initialization only for data
/// member pointers, for which '0' is a valid offset.
bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {}

/// The Itanium ABI always places an offset to the complete object
/// at entry -2 in the vtable.
void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
                                            const CXXDeleteExpr *DE,
                                            Address Ptr,
                                            QualType ElementType,
                                            const CXXDestructorDecl *Dtor) {}

void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {}

static llvm::FunctionCallee getAllocateExceptionFn(CodeGenModule &CGM) {}

static llvm::FunctionCallee getThrowFn(CodeGenModule &CGM) {}

void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {}

static llvm::FunctionCallee getItaniumDynamicCastFn(CodeGenFunction &CGF) {}

static llvm::FunctionCallee getBadCastFn(CodeGenFunction &CGF) {}

/// Compute the src2dst_offset hint as described in the
/// Itanium C++ ABI [2.9.7]
static CharUnits computeOffsetHint(ASTContext &Context,
                                   const CXXRecordDecl *Src,
                                   const CXXRecordDecl *Dst) {}

static llvm::FunctionCallee getBadTypeidFn(CodeGenFunction &CGF) {}

bool ItaniumCXXABI::shouldTypeidBeNullChecked(QualType SrcRecordTy) {}

void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {}

llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
                                       QualType SrcRecordTy,
                                       Address ThisPtr,
                                       llvm::Type *StdTypeInfoPtrTy) {}

bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
                                                       QualType SrcRecordTy) {}

llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
    CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
    QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {}

llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
    CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
    QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
    llvm::BasicBlock *CastFail) {}

llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF,
                                                  Address ThisAddr,
                                                  QualType SrcRecordTy) {}

bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {}

llvm::Value *
ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
                                         Address This,
                                         const CXXRecordDecl *ClassDecl,
                                         const CXXRecordDecl *BaseClassDecl) {}

void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {}

CGCXXABI::AddedStructorArgCounts
ItaniumCXXABI::buildStructorSignature(GlobalDecl GD,
                                      SmallVectorImpl<CanQualType> &ArgTys) {}

void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {}

void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
                                              QualType &ResTy,
                                              FunctionArgList &Params) {}

void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {}

CGCXXABI::AddedStructorArgs ItaniumCXXABI::getImplicitConstructorArgs(
    CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
    bool ForVirtualBase, bool Delegating) {}

llvm::Value *ItaniumCXXABI::getCXXDestructorImplicitParam(
    CodeGenFunction &CGF, const CXXDestructorDecl *DD, CXXDtorType Type,
    bool ForVirtualBase, bool Delegating) {}

void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
                                       const CXXDestructorDecl *DD,
                                       CXXDtorType Type, bool ForVirtualBase,
                                       bool Delegating, Address This,
                                       QualType ThisTy) {}

// Check if any non-inline method has the specified attribute.
template <typename T>
static bool CXXRecordNonInlineHasAttr(const CXXRecordDecl *RD) {}

static void setVTableSelectiveDLLImportExport(CodeGenModule &CGM,
                                              llvm::GlobalVariable *VTable,
                                              const CXXRecordDecl *RD) {}

void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
                                          const CXXRecordDecl *RD) {}

bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
    CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {}

llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
    CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
    const CXXRecordDecl *NearestVBase) {}

llvm::Constant *
ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
                                     const CXXRecordDecl *VTableClass) {}

llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
    CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
    const CXXRecordDecl *NearestVBase) {}

llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
                                                     CharUnits VPtrOffset) {}

CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
                                                  GlobalDecl GD,
                                                  Address This,
                                                  llvm::Type *Ty,
                                                  SourceLocation Loc) {}

llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
    CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
    Address This, DeleteOrMemberCallExpr E, llvm::CallBase **CallOrInvoke) {}

void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {}

bool ItaniumCXXABI::canSpeculativelyEmitVTableAsBaseClass(
    const CXXRecordDecl *RD) const {}

bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {}
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
                                          Address InitialPtr,
                                          const CXXRecordDecl *UnadjustedClass,
                                          int64_t NonVirtualAdjustment,
                                          int64_t VirtualAdjustment,
                                          bool IsReturnAdjustment) {}

llvm::Value *
ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF, Address This,
                                     const CXXRecordDecl *UnadjustedClass,
                                     const ThunkInfo &TI) {}

llvm::Value *
ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret,
                                       const CXXRecordDecl *UnadjustedClass,
                                       const ReturnAdjustment &RA) {}

void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
                                    RValue RV, QualType ResultType) {}

/************************** Array allocation cookies **************************/

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {}

Address ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
                                             Address NewPtr,
                                             llvm::Value *NumElements,
                                             const CXXNewExpr *expr,
                                             QualType ElementType) {}

llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
                                                Address allocPtr,
                                                CharUnits cookieSize) {}

CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {}

Address ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
                                         Address newPtr,
                                         llvm::Value *numElements,
                                         const CXXNewExpr *expr,
                                         QualType elementType) {}

llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
                                            Address allocPtr,
                                            CharUnits cookieSize) {}

/*********************** Static local initialization **************************/

static llvm::FunctionCallee getGuardAcquireFn(CodeGenModule &CGM,
                                              llvm::PointerType *GuardPtrTy) {}

static llvm::FunctionCallee getGuardReleaseFn(CodeGenModule &CGM,
                                              llvm::PointerType *GuardPtrTy) {}

static llvm::FunctionCallee getGuardAbortFn(CodeGenModule &CGM,
                                            llvm::PointerType *GuardPtrTy) {}

namespace {
  struct CallGuardAbort final : EHScopeStack::Cleanup {};
}

/// The ARM code here follows the Itanium code closely enough that we
/// just special-case it at particular places.
void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
                                    const VarDecl &D,
                                    llvm::GlobalVariable *var,
                                    bool shouldPerformInit) {}

/// Register a global destructor using __cxa_atexit.
static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
                                        llvm::FunctionCallee dtor,
                                        llvm::Constant *addr, bool TLS) {}

static llvm::Function *createGlobalInitOrCleanupFn(CodeGen::CodeGenModule &CGM,
                                                   StringRef FnName) {}

void CodeGenModule::unregisterGlobalDtorsWithUnAtExit() {}

void CodeGenModule::registerGlobalDtorsWithAtExit() {}

/// Register a global destructor as best as we know how.
void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                       llvm::FunctionCallee dtor,
                                       llvm::Constant *addr) {}

static bool isThreadWrapperReplaceable(const VarDecl *VD,
                                       CodeGen::CodeGenModule &CGM) {}

/// Get the appropriate linkage for the wrapper function. This is essentially
/// the weak form of the variable's linkage; every translation unit which needs
/// the wrapper emits a copy, and we want the linker to merge them.
static llvm::GlobalValue::LinkageTypes
getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {}

llvm::Function *
ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
                                             llvm::Value *Val) {}

void ItaniumCXXABI::EmitThreadLocalInitFuncs(
    CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
    ArrayRef<llvm::Function *> CXXThreadLocalInits,
    ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {}

LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
                                                   const VarDecl *VD,
                                                   QualType LValType) {}

/// Return whether the given global decl needs a VTT parameter, which it does
/// if it's a base constructor or destructor with virtual bases.
bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {}

llvm::Constant *
ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) {}

namespace {
class ItaniumRTTIBuilder {};
}

llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
    QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) {}

llvm::Constant *
ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {}

/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
/// info for that type is defined in the standard library.
static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {}

static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {}

/// IsStandardLibraryRTTIDescriptor - Returns whether the type
/// information for the given type exists in the standard library.
static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {}

/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
/// the given type exists somewhere else, and that we should not emit the type
/// information in this translation unit.  Assumes that it is not a
/// standard-library type.
static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
                                            QualType Ty) {}

/// IsIncompleteClassType - Returns whether the given record type is incomplete.
static bool IsIncompleteClassType(const RecordType *RecordTy) {}

/// ContainsIncompleteClassType - Returns whether the given type contains an
/// incomplete class type. This is true if
///
///   * The given type is an incomplete class type.
///   * The given type is a pointer type whose pointee type contains an
///     incomplete class type.
///   * The given type is a member pointer type whose class is an incomplete
///     class type.
///   * The given type is a member pointer type whoise pointee type contains an
///     incomplete class type.
/// is an indirect or direct pointer to an incomplete class type.
static bool ContainsIncompleteClassType(QualType Ty) {}

// CanUseSingleInheritance - Return whether the given record decl has a "single,
// public, non-virtual base at offset zero (i.e. the derived class is dynamic
// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {}

void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {}

/// Return the linkage that the type info and type info name constants
/// should have for the given type.
static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
                                                             QualType Ty) {}

llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {}

llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
      QualType Ty,
      llvm::GlobalVariable::LinkageTypes Linkage,
      llvm::GlobalValue::VisibilityTypes Visibility,
      llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {}

/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
/// for the given Objective-C object type.
void ItaniumRTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {}

/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {}

namespace {
  /// SeenBases - Contains virtual and non-virtual bases seen when traversing
  /// a class hierarchy.
  struct SeenBases {};
}

/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
/// abi::__vmi_class_type_info.
///
static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
                                             SeenBases &Bases) {}

static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {}

/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
/// classes with bases that do not satisfy the abi::__si_class_type_info
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {}

/// Compute the flags for a __pbase_type_info, and remove the corresponding
/// pieces from \p Type.
static unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type) {}

/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
/// used for pointer types.
void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {}

/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
/// struct, used for member pointer types.
void
ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {}

llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty) {}

void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) {}

/// What sort of uniqueness rules should we use for the RTTI for the
/// given type?
ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness(
    QualType CanTy, llvm::GlobalValue::LinkageTypes Linkage) const {}

// Find out how to codegen the complete destructor and constructor
namespace {
enum class StructorCodegen {};
}
static StructorCodegen getCodegenToUse(CodeGenModule &CGM,
                                       const CXXMethodDecl *MD) {}

static void emitConstructorDestructorAlias(CodeGenModule &CGM,
                                           GlobalDecl AliasDecl,
                                           GlobalDecl TargetDecl) {}

void ItaniumCXXABI::emitCXXStructor(GlobalDecl GD) {}

static llvm::FunctionCallee getBeginCatchFn(CodeGenModule &CGM) {}

static llvm::FunctionCallee getEndCatchFn(CodeGenModule &CGM) {}

static llvm::FunctionCallee getGetExceptionPtrFn(CodeGenModule &CGM) {}

namespace {
  /// A cleanup to call __cxa_end_catch.  In many cases, the caught
  /// exception type lets us state definitively that the thrown exception
  /// type does not have a destructor.  In particular:
  ///   - Catch-alls tell us nothing, so we have to conservatively
  ///     assume that the thrown exception might have a destructor.
  ///   - Catches by reference behave according to their base types.
  ///   - Catches of non-record types will only trigger for exceptions
  ///     of non-record types, which never have destructors.
  ///   - Catches of record types can trigger for arbitrary subclasses
  ///     of the caught type, so we have to assume the actual thrown
  ///     exception type might have a throwing destructor, even if the
  ///     caught type's destructor is trivial or nothrow.
  struct CallEndCatch final : EHScopeStack::Cleanup {};
}

/// Emits a call to __cxa_begin_catch and enters a cleanup to call
/// __cxa_end_catch. If -fassume-nothrow-exception-dtor is specified, we assume
/// that the exception object's dtor is nothrow, therefore the __cxa_end_catch
/// call can be marked as nounwind even if EndMightThrow is true.
///
/// \param EndMightThrow - true if __cxa_end_catch might throw
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
                                   llvm::Value *Exn,
                                   bool EndMightThrow) {}

/// A "special initializer" callback for initializing a catch
/// parameter during catch initialization.
static void InitCatchParam(CodeGenFunction &CGF,
                           const VarDecl &CatchParam,
                           Address ParamAddr,
                           SourceLocation Loc) {}

/// Begins a catch statement by initializing the catch variable and
/// calling __cxa_begin_catch.
void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
                                   const CXXCatchStmt *S) {}

/// Get or define the following function:
///   void @__clang_call_terminate(i8* %exn) nounwind noreturn
/// This code is used only in C++.
static llvm::FunctionCallee getClangCallTerminateFn(CodeGenModule &CGM) {}

llvm::CallInst *
ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
                                                   llvm::Value *Exn) {}

std::pair<llvm::Value *, const CXXRecordDecl *>
ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
                             const CXXRecordDecl *RD) {}

llvm::Constant *
ItaniumCXXABI::getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD) {}

void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
                                       const CXXCatchStmt *C) {}

llvm::CallInst *
WebAssemblyCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
                                                       llvm::Value *Exn) {}

/// Register a global destructor as best as we know how.
void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                  llvm::FunctionCallee Dtor,
                                  llvm::Constant *Addr) {}

void XLCXXABI::emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
                                     llvm::Constant *addr) {}