llvm/clang/lib/AST/ExprConstant.cpp

//===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===//
//
// 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 the Expr constant evaluator.
//
// Constant expression evaluation produces four main results:
//
//  * A success/failure flag indicating whether constant folding was successful.
//    This is the 'bool' return value used by most of the code in this file. A
//    'false' return value indicates that constant folding has failed, and any
//    appropriate diagnostic has already been produced.
//
//  * An evaluated result, valid only if constant folding has not failed.
//
//  * A flag indicating if evaluation encountered (unevaluated) side-effects.
//    These arise in cases such as (sideEffect(), 0) and (sideEffect() || 1),
//    where it is possible to determine the evaluated result regardless.
//
//  * A set of notes indicating why the evaluation was not a constant expression
//    (under the C++11 / C++1y rules only, at the moment), or, if folding failed
//    too, why the expression could not be folded.
//
// If we are checking for a potential constant expression, failure to constant
// fold a potential constant sub-expression will be indicated by a 'false'
// return value (the expression could not be folded) and no diagnostic (the
// expression is not necessarily non-constant).
//
//===----------------------------------------------------------------------===//

#include "ByteCode/Context.h"
#include "ByteCode/Frame.h"
#include "ByteCode/State.h"
#include "ExprConstShared.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFixedPoint.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/SipHash.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
#include <optional>

#define DEBUG_TYPE

usingnamespaceclang;
APFixedPoint;
APInt;
APSInt;
APFloat;
FixedPointSemantics;

namespace {
  struct LValue;
  class CallStackFrame;
  class EvalInfo;

  SourceLocExprScopeGuard;

  static QualType getType(APValue::LValueBase B) {}

  /// Get an LValue path entry, which is known to not be an array index, as a
  /// field declaration.
  static const FieldDecl *getAsField(APValue::LValuePathEntry E) {}
  /// Get an LValue path entry, which is known to not be an array index, as a
  /// base class declaration.
  static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {}
  /// Determine whether this LValue path entry for a base class names a virtual
  /// base class.
  static bool isVirtualBaseClass(APValue::LValuePathEntry E) {}

  /// Given an expression, determine the type used to store the result of
  /// evaluating that expression.
  static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {}

  /// Given a CallExpr, try to get the alloc_size attribute. May return null.
  static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) {}

  /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
  /// This will look through a single cast.
  ///
  /// Returns null if we couldn't unwrap a function with alloc_size.
  static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {}

  /// Determines whether or not the given Base contains a call to a function
  /// with the alloc_size attribute.
  static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {}

  /// Determines whether the given kind of constant expression is only ever
  /// used for name mangling. If so, it's permitted to reference things that we
  /// can't generate code for (in particular, dllimported functions).
  static bool isForManglingOnly(ConstantExprKind Kind) {}

  static bool isTemplateArgument(ConstantExprKind Kind) {}

  /// The bound to claim that an array of unknown bound has.
  /// The value in MostDerivedArraySize is undefined in this case. So, set it
  /// to an arbitrary value that's likely to loudly break things if it's used.
  static const uint64_t AssumedSizeForUnsizedArray =;

  /// Determines if an LValue with the given LValueBase will have an unsized
  /// array in its designator.
  /// Find the path length and type of the most-derived subobject in the given
  /// path, and find the size of the containing array, if any.
  static unsigned
  findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
                           ArrayRef<APValue::LValuePathEntry> Path,
                           uint64_t &ArraySize, QualType &Type, bool &IsArray,
                           bool &FirstEntryIsUnsizedArray) {}

  /// A path from a glvalue to a subobject of that glvalue.
  struct SubobjectDesignator {};

  /// A scope at the end of which an object can need to be destroyed.
  enum class ScopeKind {};

  /// A reference to a particular call and its arguments.
  struct CallRef {};

  /// A stack frame in the constexpr call stack.
  class CallStackFrame : public interp::Frame {};

  /// Temporarily override 'this'.
  class ThisOverrideRAII {};

  // A shorthand time trace scope struct, prints source range, for example
  // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
  class ExprTimeTraceScope {};

  /// RAII object used to change the current ability of
  /// [[msvc::constexpr]] evaulation.
  struct MSConstexprContextRAII {};
}

static bool HandleDestruction(EvalInfo &Info, const Expr *E,
                              const LValue &This, QualType ThisType);
static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
                              APValue::LValueBase LVBase, APValue &Value,
                              QualType T);

namespace {
  /// A cleanup, and a flag indicating whether it is lifetime-extended.
  class Cleanup {};

  /// A reference to an object whose construction we are currently evaluating.
  struct ObjectUnderConstruction {};
  enum class ConstructionPhase {};
}

namespace llvm {
template<> struct DenseMapInfo<ObjectUnderConstruction> {};
}

namespace {
  /// A dynamically-allocated heap object.
  struct DynAlloc {};

  struct DynAllocOrder {};

  /// EvalInfo - This is a private struct used by the evaluator to capture
  /// information about a subexpression as it is folded.  It retains information
  /// about the AST context, but also maintains information about the folded
  /// expression.
  ///
  /// If an expression could be evaluated, it is still possible it is not a C
  /// "integer constant expression" or constant expression.  If not, this struct
  /// captures information about how and why not.
  ///
  /// One bit of information passed *into* the request for constant folding
  /// indicates whether the subexpression is "evaluated" or not according to C
  /// rules.  For example, the RHS of (0 && foo()) is not evaluated.  We can
  /// evaluate the expression regardless of what the RHS is, but C only allows
  /// certain things in certain situations.
  class EvalInfo : public interp::State {};

  /// Object used to treat all foldable expressions as constant expressions.
  struct FoldConstant {};

  /// RAII object used to set the current evaluation mode to ignore
  /// side-effects.
  struct IgnoreSideEffectsRAII {};

  /// RAII object used to optionally suppress diagnostics and side-effects from
  /// a speculative evaluation.
  class SpeculativeEvaluationRAII {};

  /// RAII object wrapping a full-expression or block scope, and handling
  /// the ending of the lifetime of temporaries created within it.
  template<ScopeKind Kind>
  class ScopeRAII {};
  BlockScopeRAII;
  FullExpressionRAII;
  CallScopeRAII;
}

bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
                                         CheckSubobjectKind CSK) {}

void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info,
                                                                const Expr *E) {}

void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
                                                    const Expr *E,
                                                    const APSInt &N) {}

CallStackFrame::CallStackFrame(EvalInfo &Info, SourceRange CallRange,
                               const FunctionDecl *Callee, const LValue *This,
                               const Expr *CallExpr, CallRef Call)
    :{}

CallStackFrame::~CallStackFrame() {}

static bool isRead(AccessKinds AK) {}

static bool isModification(AccessKinds AK) {}

static bool isAnyAccess(AccessKinds AK) {}

/// Is this an access per the C++ definition?
static bool isFormalAccess(AccessKinds AK) {}

/// Is this kind of axcess valid on an indeterminate object value?
static bool isValidIndeterminateAccess(AccessKinds AK) {}

namespace {
  struct ComplexValue {};

  struct LValue {};

  struct MemberPtr {};

  /// Compare two member pointers, which are assumed to be of the same type.
  static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {}
}

static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
                            const LValue &This, const Expr *E,
                            bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
                           bool InvalidBaseOK = false);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
                            bool InvalidBaseOK = false);
static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
                                  EvalInfo &Info);
static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
                                    EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
                           EvalInfo &Info);
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result,
                                  EvalInfo &Info,
                                  std::string *StringResult = nullptr);

/// Evaluate an integer or fixed point expression into an APResult.
static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
                                        EvalInfo &Info);

/// Evaluate only a fixed point expression into an APResult.
static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
                               EvalInfo &Info);

//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//

/// Negate an APSInt in place, converting it to a signed form if necessary, and
/// preserving its value (by extending by up to one bit as needed).
static void negateAsSigned(APSInt &Int) {}

template<typename KeyT>
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
                                         ScopeKind Scope, LValue &LV) {}

/// Allocate storage for a parameter of a function call made in this frame.
APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD,
                                     LValue &LV) {}

APValue &CallStackFrame::createLocal(APValue::LValueBase Base, const void *Key,
                                     QualType T, ScopeKind Scope) {}

APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {}

/// Produce a string describing the given constexpr call.
void CallStackFrame::describe(raw_ostream &Out) const {}

/// Evaluate an expression to see if it had side-effects, and discard its
/// result.
/// \return \c true if the caller should keep evaluating.
static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {}

/// Should this call expression be treated as forming an opaque constant?
static bool IsOpaqueConstantCall(const CallExpr *E) {}

static bool IsOpaqueConstantCall(const LValue &LVal) {}

static bool IsGlobalLValue(APValue::LValueBase B) {}

static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {}

// Information about an LValueBase that is some kind of string.
struct LValueBaseString {};

// Gets the lvalue base of LVal as a string.
static bool GetLValueBaseAsString(const EvalInfo &Info, const LValue &LVal,
                                  LValueBaseString &AsString) {}

// Determine whether two string literals potentially overlap. This will be the
// case if they agree on the values of all the bytes on the overlapping region
// between them.
//
// The overlapping region is the portion of the two string literals that must
// overlap in memory if the pointers actually point to the same address at
// runtime. For example, if LHS is "abcdef" + 3 and RHS is "cdef\0gh" + 1 then
// the overlapping region is "cdef\0", which in this case does agree, so the
// strings are potentially overlapping. Conversely, for "foobar" + 3 versus
// "bazbar" + 3, the overlapping region contains all of both strings, so they
// are not potentially overlapping, even though they agree from the given
// addresses onwards.
//
// See open core issue CWG2765 which is discussing the desired rule here.
static bool ArePotentiallyOverlappingStringLiterals(const EvalInfo &Info,
                                                    const LValue &LHS,
                                                    const LValue &RHS) {}

static bool IsWeakLValue(const LValue &Value) {}

static bool isZeroSized(const LValue &Value) {}

static bool HasSameBase(const LValue &A, const LValue &B) {}

static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {}

enum class CheckEvaluationResultKind {};

/// Materialized temporaries that we've already checked to determine if they're
/// initializsed by a constant expression.
CheckedTemporaries;

static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
                                  EvalInfo &Info, SourceLocation DiagLoc,
                                  QualType Type, const APValue &Value,
                                  ConstantExprKind Kind,
                                  const FieldDecl *SubobjectDecl,
                                  CheckedTemporaries &CheckedTemps);

/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
/// can fold this expression, whether or not it's a constant expression.
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
                                          QualType Type, const LValue &LVal,
                                          ConstantExprKind Kind,
                                          CheckedTemporaries &CheckedTemps) {}

/// Member pointers are constant expressions unless they point to a
/// non-virtual dllimport member function.
static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
                                                 SourceLocation Loc,
                                                 QualType Type,
                                                 const APValue &Value,
                                                 ConstantExprKind Kind) {}

/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
                             const LValue *This = nullptr) {}

static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
                                  EvalInfo &Info, SourceLocation DiagLoc,
                                  QualType Type, const APValue &Value,
                                  ConstantExprKind Kind,
                                  const FieldDecl *SubobjectDecl,
                                  CheckedTemporaries &CheckedTemps) {}

/// Check that this core constant expression value is a valid value for a
/// constant expression. If not, report an appropriate diagnostic. Does not
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
                                    QualType Type, const APValue &Value,
                                    ConstantExprKind Kind) {}

/// Check that this evaluated value is fully-initialized and can be loaded by
/// an lvalue-to-rvalue conversion.
static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
                                  QualType Type, const APValue &Value) {}

/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
/// "the allocated storage is deallocated within the evaluation".
static bool CheckMemoryLeaks(EvalInfo &Info) {}

static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {}

static bool HandleConversionToBool(const APValue &Val, bool &Result) {}

static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
                                       EvalInfo &Info) {}

template<typename T>
static bool HandleOverflow(EvalInfo &Info, const Expr *E,
                           const T &SrcValue, QualType DestType) {}

static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
                                 QualType SrcType, const APFloat &Value,
                                 QualType DestType, APSInt &Result) {}

/// Get rounding mode to use in evaluation of the specified expression.
///
/// If rounding mode is unknown at compile time, still try to evaluate the
/// expression. If the result is exact, it does not depend on rounding mode.
/// So return "tonearest" mode instead of "dynamic".
static llvm::RoundingMode getActiveRoundingMode(EvalInfo &Info, const Expr *E) {}

/// Check if the given evaluation result is allowed for constant evaluation.
static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
                                     APFloat::opStatus St) {}

static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
                                   QualType SrcType, QualType DestType,
                                   APFloat &Result) {}

static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
                                 QualType DestType, QualType SrcType,
                                 const APSInt &Value) {}

static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
                                 const FPOptions FPO,
                                 QualType SrcType, const APSInt &Value,
                                 QualType DestType, APFloat &Result) {}

static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
                                  APValue &Value, const FieldDecl *FD) {}

/// Perform the given integer operation, which is known to need at most BitWidth
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
template<typename Operation>
static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
                                 const APSInt &LHS, const APSInt &RHS,
                                 unsigned BitWidth, Operation Op,
                                 APSInt &Result) {}

/// Perform the given binary integer operation.
static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
                              const APSInt &LHS, BinaryOperatorKind Opcode,
                              APSInt RHS, APSInt &Result) {}

/// Perform the given binary floating-point operation, in-place, on LHS.
static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
                                  APFloat &LHS, BinaryOperatorKind Opcode,
                                  const APFloat &RHS) {}

static bool handleLogicalOpForVector(const APInt &LHSValue,
                                     BinaryOperatorKind Opcode,
                                     const APInt &RHSValue, APInt &Result) {}
static bool handleLogicalOpForVector(const APFloat &LHSValue,
                                     BinaryOperatorKind Opcode,
                                     const APFloat &RHSValue, APInt &Result) {}

static bool handleLogicalOpForVector(const APValue &LHSValue,
                                     BinaryOperatorKind Opcode,
                                     const APValue &RHSValue, APInt &Result) {}

template <typename APTy>
static bool
handleCompareOpForVectorHelper(const APTy &LHSValue, BinaryOperatorKind Opcode,
                               const APTy &RHSValue, APInt &Result) {}

static bool handleCompareOpForVector(const APValue &LHSValue,
                                     BinaryOperatorKind Opcode,
                                     const APValue &RHSValue, APInt &Result) {}

// Perform binary operations for vector types, in place on the LHS.
static bool handleVectorVectorBinOp(EvalInfo &Info, const BinaryOperator *E,
                                    BinaryOperatorKind Opcode,
                                    APValue &LHSValue,
                                    const APValue &RHSValue) {}

/// Cast an lvalue referring to a base subobject to a derived class, by
/// truncating the lvalue's path to the given length.
static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
                               const RecordDecl *TruncatedType,
                               unsigned TruncatedElements) {}

static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
                                   const CXXRecordDecl *Derived,
                                   const CXXRecordDecl *Base,
                                   const ASTRecordLayout *RL = nullptr) {}

static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
                             const CXXRecordDecl *DerivedDecl,
                             const CXXBaseSpecifier *Base) {}

static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
                                 QualType Type, LValue &Result) {}

/// Cast an lvalue referring to a derived class to a known base subobject.
static bool CastToBaseClass(EvalInfo &Info, const Expr *E, LValue &Result,
                            const CXXRecordDecl *DerivedRD,
                            const CXXRecordDecl *BaseRD) {}

/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
                               const FieldDecl *FD,
                               const ASTRecordLayout *RL = nullptr) {}

/// Update LVal to refer to the given indirect field.
static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
                                       LValue &LVal,
                                       const IndirectFieldDecl *IFD) {}

enum class SizeOfType {};

/// Get the size of the given type in char units.
static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc, QualType Type,
                         CharUnits &Size, SizeOfType SOT = SizeOfType::SizeOf) {}

/// Update a pointer value to model pointer arithmetic.
/// \param Info - Information about the ongoing evaluation.
/// \param E - The expression being evaluated, for diagnostic purposes.
/// \param LVal - The pointer value to be updated.
/// \param EltTy - The pointee type represented by LVal.
/// \param Adjustment - The adjustment, in objects of type EltTy, to add.
static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
                                        LValue &LVal, QualType EltTy,
                                        APSInt Adjustment) {}

static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
                                        LValue &LVal, QualType EltTy,
                                        int64_t Adjustment) {}

/// Update an lvalue to refer to a component of a complex number.
/// \param Info - Information about the ongoing evaluation.
/// \param LVal - The lvalue to be updated.
/// \param EltTy - The complex number's component type.
/// \param Imag - False for the real component, true for the imaginary.
static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
                                       LValue &LVal, QualType EltTy,
                                       bool Imag) {}

static bool HandleLValueVectorElement(EvalInfo &Info, const Expr *E,
                                      LValue &LVal, QualType EltTy,
                                      uint64_t Size, uint64_t Idx) {}

/// Try to evaluate the initializer for a variable declaration.
///
/// \param Info   Information about the ongoing evaluation.
/// \param E      An expression to be used when printing diagnostics.
/// \param VD     The variable whose initializer should be obtained.
/// \param Version The version of the variable within the frame.
/// \param Frame  The frame in which the variable was created. Must be null
///               if this variable is not local to the evaluation.
/// \param Result Filled in with a pointer to the value of the variable.
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
                                const VarDecl *VD, CallStackFrame *Frame,
                                unsigned Version, APValue *&Result) {}

/// Get the base index of the given base class within an APValue representing
/// the given derived class.
static unsigned getBaseIndex(const CXXRecordDecl *Derived,
                             const CXXRecordDecl *Base) {}

/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
                                            uint64_t Index) {}

// Expand a string literal into an array of characters.
//
// FIXME: This is inefficient; we should probably introduce something similar
// to the LLVM ConstantDataArray to make this cheaper.
static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
                                APValue &Result,
                                QualType AllocType = QualType()) {}

// Expand an array so that it has more than Index filled elements.
static void expandArray(APValue &Array, unsigned Index) {}

/// Determine whether a type would actually be read by an lvalue-to-rvalue
/// conversion. If it's of class type, we may assume that the copy operation
/// is trivial. Note that this is never true for a union type with fields
/// (because the copy always "reads" the active member) and always true for
/// a non-class type.
static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD);
static bool isReadByLvalueToRvalueConversion(QualType T) {}
static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD) {}

/// Diagnose an attempt to read from any unreadable field within the specified
/// type, which might be a class type.
static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E, AccessKinds AK,
                                  QualType T) {}

static bool lifetimeStartedInEvaluation(EvalInfo &Info,
                                        APValue::LValueBase Base,
                                        bool MutableSubobject = false) {}

static bool CheckArraySize(EvalInfo &Info, const ConstantArrayType *CAT,
                           SourceLocation CallLoc = {}

namespace {
/// A handle to a complete object (an object that is not a subobject of
/// another object).
struct CompleteObject {};
} // end anonymous namespace

static QualType getSubobjectType(QualType ObjType, QualType SubobjType,
                                 bool IsMutable = false) {}

/// Find the designated sub-object of an rvalue.
template<typename SubobjectHandler>
typename SubobjectHandler::result_type
findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
              const SubobjectDesignator &Sub, SubobjectHandler &handler) {}

namespace {
struct ExtractSubobjectHandler {};
} // end anonymous namespace

/// Extract the designated sub-object of an rvalue.
static bool extractSubobject(EvalInfo &Info, const Expr *E,
                             const CompleteObject &Obj,
                             const SubobjectDesignator &Sub, APValue &Result,
                             AccessKinds AK = AK_Read) {}

namespace {
struct ModifySubobjectHandler {};
} // end anonymous namespace

const AccessKinds ModifySubobjectHandler::AccessKind;

/// Update the designated sub-object of an rvalue to the given value.
static bool modifySubobject(EvalInfo &Info, const Expr *E,
                            const CompleteObject &Obj,
                            const SubobjectDesignator &Sub,
                            APValue &NewVal) {}

/// Find the position where two subobject designators diverge, or equivalently
/// the length of the common initial subsequence.
static unsigned FindDesignatorMismatch(QualType ObjType,
                                       const SubobjectDesignator &A,
                                       const SubobjectDesignator &B,
                                       bool &WasArrayIndex) {}

/// Determine whether the given subobject designators refer to elements of the
/// same array object.
static bool AreElementsOfSameArray(QualType ObjType,
                                   const SubobjectDesignator &A,
                                   const SubobjectDesignator &B) {}

/// Find the complete object to which an LValue refers.
static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
                                         AccessKinds AK, const LValue &LVal,
                                         QualType LValType) {}

/// Perform an lvalue-to-rvalue conversion on the given glvalue. This
/// can also be used for 'lvalue-to-lvalue' conversions for looking up the
/// glvalue referred to by an entity of reference type.
///
/// \param Info - Information about the ongoing evaluation.
/// \param Conv - The expression for which we are performing the conversion.
///               Used for diagnostics.
/// \param Type - The type of the glvalue (before stripping cv-qualifiers in the
///               case of a non-class type).
/// \param LVal - The glvalue on which we are attempting to perform this action.
/// \param RVal - The produced value will be placed here.
/// \param WantObjectRepresentation - If true, we're looking for the object
///               representation rather than the value, and in particular,
///               there is no requirement that the result be fully initialized.
static bool
handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
                               const LValue &LVal, APValue &RVal,
                               bool WantObjectRepresentation = false) {}

/// Perform an assignment of Val to LVal. Takes ownership of Val.
static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
                             QualType LValType, APValue &Val) {}

namespace {
struct CompoundAssignSubobjectHandler {};
} // end anonymous namespace

const AccessKinds CompoundAssignSubobjectHandler::AccessKind;

/// Perform a compound assignment of LVal <op>= RVal.
static bool handleCompoundAssignment(EvalInfo &Info,
                                     const CompoundAssignOperator *E,
                                     const LValue &LVal, QualType LValType,
                                     QualType PromotedLValType,
                                     BinaryOperatorKind Opcode,
                                     const APValue &RVal) {}

namespace {
struct IncDecSubobjectHandler {};
} // end anonymous namespace

/// Perform an increment or decrement on LVal.
static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
                         QualType LValType, bool IsIncrement, APValue *Old) {}

/// Build an lvalue for the object argument of a member function call.
static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
                                   LValue &This) {}

/// HandleMemberPointerAccess - Evaluate a member access operation and build an
/// lvalue referring to the result.
///
/// \param Info - Information about the ongoing evaluation.
/// \param LV - An lvalue referring to the base of the member pointer.
/// \param RHS - The member pointer expression.
/// \param IncludeMember - Specifies whether the member itself is included in
///        the resulting LValue subobject designator. This is not possible when
///        creating a bound member function.
/// \return The field or method declaration to which the member pointer refers,
///         or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
                                                  QualType LVType,
                                                  LValue &LV,
                                                  const Expr *RHS,
                                                  bool IncludeMember = true) {}

static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
                                                  const BinaryOperator *BO,
                                                  LValue &LV,
                                                  bool IncludeMember = true) {}

/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
/// the provided lvalue, which currently refers to the base object.
static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
                                    LValue &Result) {}

/// Get the value to use for a default-initialized object of type T.
/// Return false if it encounters something invalid.
static bool handleDefaultInitValue(QualType T, APValue &Result) {}

namespace {
enum EvalStmtResult {};
}

static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {}

static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {}

static bool EvaluateDependentExpr(const Expr *E, EvalInfo &Info) {}

/// Evaluate a condition (either a variable declaration or an expression).
static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
                         const Expr *Cond, bool &Result) {}

namespace {
/// A location where the result (returned value) of evaluating a
/// statement should be stored.
struct StmtResult {};

struct TempVersionRAII {};

}

static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
                                   const Stmt *S,
                                   const SwitchCase *SC = nullptr);

/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info,
                                       const Stmt *Body,
                                       const SwitchCase *Case = nullptr) {}

/// Evaluate a switch statement.
static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
                                     const SwitchStmt *SS) {}

static bool CheckLocalVariableDeclaration(EvalInfo &Info, const VarDecl *VD) {}

// Evaluate a statement.
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
                                   const Stmt *S, const SwitchCase *Case) {}

/// CheckTrivialDefaultConstructor - Check whether a constructor is a trivial
/// default constructor. If so, we'll fold it whether or not it's marked as
/// constexpr. If it is marked as constexpr, we will never implicitly define it,
/// so we need special handling.
static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
                                           const CXXConstructorDecl *CD,
                                           bool IsValueInitialization) {}

/// CheckConstexprFunction - Check that a function can be called in a constant
/// expression.
static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
                                   const FunctionDecl *Declaration,
                                   const FunctionDecl *Definition,
                                   const Stmt *Body) {}

namespace {
struct CheckDynamicTypeHandler {};
} // end anonymous namespace

/// Check that we can access the notional vptr of an object / determine its
/// dynamic type.
static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
                             AccessKinds AK, bool Polymorphic) {}

/// Check that the pointee of the 'this' pointer in a member function call is
/// either within its lifetime or in its period of construction or destruction.
static bool
checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E,
                                     const LValue &This,
                                     const CXXMethodDecl *NamedMember) {}

struct DynamicType {};

static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
                                             unsigned PathLength) {}

/// Determine the dynamic type of an object.
static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
                                                     const Expr *E,
                                                     LValue &This,
                                                     AccessKinds AK) {}

/// Perform virtual dispatch.
static const CXXMethodDecl *HandleVirtualDispatch(
    EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
    llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {}

/// Perform the adjustment from a value returned by a virtual function to
/// a value of the statically expected type, which may be a pointer or
/// reference to a base class of the returned type.
static bool HandleCovariantReturnAdjustment(EvalInfo &Info, const Expr *E,
                                            APValue &Result,
                                            ArrayRef<QualType> Path) {}

/// Determine whether \p Base, which is known to be a direct base class of
/// \p Derived, is a public base class.
static bool isBaseClassPublic(const CXXRecordDecl *Derived,
                              const CXXRecordDecl *Base) {}

/// Apply the given dynamic cast operation on the provided lvalue.
///
/// This implements the hard case of dynamic_cast, requiring a "runtime check"
/// to find a suitable target subobject.
static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
                              LValue &Ptr) {}

namespace {
struct StartLifetimeOfUnionMemberHandler {};
} // end anonymous namespace

const AccessKinds StartLifetimeOfUnionMemberHandler::AccessKind;

/// Handle a builtin simple-assignment or a call to a trivial assignment
/// operator whose left-hand side might involve a union member access. If it
/// does, implicitly start the lifetime of any accessed union elements per
/// C++20 [class.union]5.
static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
                                               const Expr *LHSExpr,
                                               const LValue &LHS) {}

static bool EvaluateCallArg(const ParmVarDecl *PVD, const Expr *Arg,
                            CallRef Call, EvalInfo &Info,
                            bool NonNull = false) {}

/// Evaluate the arguments to a function call.
static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
                         EvalInfo &Info, const FunctionDecl *Callee,
                         bool RightToLeft = false) {}

/// Perform a trivial copy from Param, which is the parameter of a copy or move
/// constructor or assignment operator.
static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param,
                              const Expr *E, APValue &Result,
                              bool CopyObjectRepresentation) {}

/// Evaluate a function call.
static bool HandleFunctionCall(SourceLocation CallLoc,
                               const FunctionDecl *Callee, const LValue *This,
                               const Expr *E, ArrayRef<const Expr *> Args,
                               CallRef Call, const Stmt *Body, EvalInfo &Info,
                               APValue &Result, const LValue *ResultSlot) {}

/// Evaluate a constructor call.
static bool HandleConstructorCall(const Expr *E, const LValue &This,
                                  CallRef Call,
                                  const CXXConstructorDecl *Definition,
                                  EvalInfo &Info, APValue &Result) {}

static bool HandleConstructorCall(const Expr *E, const LValue &This,
                                  ArrayRef<const Expr*> Args,
                                  const CXXConstructorDecl *Definition,
                                  EvalInfo &Info, APValue &Result) {}

static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
                                  const LValue &This, APValue &Value,
                                  QualType T) {}

namespace {
struct DestroyObjectHandler {};
}

/// Perform a destructor or pseudo-destructor call on the given object, which
/// might in general not be a complete object.
static bool HandleDestruction(EvalInfo &Info, const Expr *E,
                              const LValue &This, QualType ThisType) {}

/// Destroy and end the lifetime of the given complete object.
static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
                              APValue::LValueBase LVBase, APValue &Value,
                              QualType T) {}

/// Perform a call to 'operator new' or to `__builtin_operator_new'.
static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E,
                                  LValue &Result) {}

static bool hasVirtualDestructor(QualType T) {}

static const FunctionDecl *getVirtualOperatorDelete(QualType T) {}

/// Check that the given object is a suitable pointer to a heap allocation that
/// still exists and is of the right kind for the purpose of a deletion.
///
/// On success, returns the heap allocation to deallocate. On failure, produces
/// a diagnostic and returns std::nullopt.
static std::optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
                                                 const LValue &Pointer,
                                                 DynAlloc::Kind DeallocKind) {}

// Perform a call to 'operator delete' or '__builtin_operator_delete'.
bool HandleOperatorDeleteCall(EvalInfo &Info, const CallExpr *E) {}

//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
namespace {

class BitCastBuffer {};

/// Traverse an APValue to produce an BitCastBuffer, emulating how the current
/// target would represent the value at runtime.
class APValueToBufferConverter {};

/// Write an BitCastBuffer into an APValue.
class BufferToAPValueConverter {};

static bool checkBitCastConstexprEligibilityType(SourceLocation Loc,
                                                 QualType Ty, EvalInfo *Info,
                                                 const ASTContext &Ctx,
                                                 bool CheckingDest) {}

static bool checkBitCastConstexprEligibility(EvalInfo *Info,
                                             const ASTContext &Ctx,
                                             const CastExpr *BCE) {}

static bool handleRValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
                                        const APValue &SourceRValue,
                                        const CastExpr *BCE) {}

static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
                                        APValue &SourceValue,
                                        const CastExpr *BCE) {}

template <class Derived>
class ExprEvaluatorBase
  : public ConstStmtVisitor<Derived, bool> {};

} // namespace

//===----------------------------------------------------------------------===//
// Common base class for lvalue and temporary evaluation.
//===----------------------------------------------------------------------===//
namespace {
template<class Derived>
class LValueExprEvaluatorBase
  : public ExprEvaluatorBase<Derived> {};
}

//===----------------------------------------------------------------------===//
// LValue Evaluation
//
// This is used for evaluating lvalues (in C and C++), xvalues (in C++11),
// function designators (in C), decl references to void objects (in C), and
// temporaries (if building with -Wno-address-of-temporary).
//
// LValue evaluation produces values comprising a base expression of one of the
// following types:
// - Declarations
//  * VarDecl
//  * FunctionDecl
// - Literals
//  * CompoundLiteralExpr in C (and in global scope in C++)
//  * StringLiteral
//  * PredefinedExpr
//  * ObjCStringLiteralExpr
//  * ObjCEncodeExpr
//  * AddrLabelExpr
//  * BlockExpr
//  * CallExpr for a MakeStringConstant builtin
// - typeid(T) expressions, as TypeInfoLValues
// - Locals and temporaries
//  * MaterializeTemporaryExpr
//  * Any Expr, with a CallIndex indicating the function in which the temporary
//    was evaluated, for cases where the MaterializeTemporaryExpr is missing
//    from the AST (FIXME).
//  * A MaterializeTemporaryExpr that has static storage duration, with no
//    CallIndex, for a lifetime-extended temporary.
//  * The ConstantExpr that is currently being evaluated during evaluation of an
//    immediate invocation.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
  : public LValueExprEvaluatorBase<LValueExprEvaluator> {};
} // end anonymous namespace

/// Get an lvalue to a field of a lambda's closure type.
static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result,
                                const CXXMethodDecl *MD, const FieldDecl *FD,
                                bool LValueToRValueConversion) {}

/// Evaluate an expression as an lvalue. This can be legitimately called on
/// expressions which are not glvalues, in three cases:
///  * function designators in C, and
///  * "extern void" objects
///  * @selector() expressions in Objective-C
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
                           bool InvalidBaseOK) {}

bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {}


bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {}

bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {}

bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
    const MaterializeTemporaryExpr *E) {}

bool
LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {}

bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {}

bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {}

bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {}

bool LValueExprEvaluator::VisitExtVectorElementExpr(
    const ExtVectorElementExpr *E) {}

bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {}

bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {}

bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {}

bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {}

bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {}

bool LValueExprEvaluator::VisitCompoundAssignOperator(
    const CompoundAssignOperator *CAO) {}

bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {}

//===----------------------------------------------------------------------===//
// Pointer Evaluation
//===----------------------------------------------------------------------===//

/// Attempts to compute the number of bytes available at the pointer
/// returned by a function with the alloc_size attribute. Returns true if we
/// were successful. Places an unsigned number into `Result`.
///
/// This expects the given CallExpr to be a call to a function with an
/// alloc_size attribute.
static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
                                            const CallExpr *Call,
                                            llvm::APInt &Result) {}

/// Convenience function. LVal's base must be a call to an alloc_size
/// function.
static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
                                            const LValue &LVal,
                                            llvm::APInt &Result) {}

/// Attempts to evaluate the given LValueBase as the result of a call to
/// a function with the alloc_size attribute. If it was possible to do so, this
/// function will return true, make Result's Base point to said function call,
/// and mark Result's Base as invalid.
static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
                                      LValue &Result) {}

namespace {
class PointerExprEvaluator
  : public ExprEvaluatorBase<PointerExprEvaluator> {};
} // end anonymous namespace

static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
                            bool InvalidBaseOK) {}

bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {}

// Is the provided decl 'std::source_location::current'?
static bool IsDeclSourceLocationCurrent(const FunctionDecl *FD) {}

bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {}

static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
                                UnaryExprOrTypeTrait ExprKind) {}

static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
                                UnaryExprOrTypeTrait ExprKind) {}

static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {}

/// Evaluate the value of the alignment argument to __builtin_align_{up,down},
/// __builtin_is_aligned and __builtin_assume_aligned.
static bool getAlignmentArgument(const Expr *E, QualType ForType,
                                 EvalInfo &Info, APSInt &Alignment) {}

// To be clear: this happily visits unsupported builtins. Better name welcomed.
bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {}

bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {}

// Determine if T is a character type for which we guarantee that
// sizeof(T) == 1.
static bool isOneByteCharacterType(QualType T) {}

bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
                                                unsigned BuiltinOp) {}

static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
                                     APValue &Result, const InitListExpr *ILE,
                                     QualType AllocType);
static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
                                          APValue &Result,
                                          const CXXConstructExpr *CCE,
                                          QualType AllocType);

bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {}
//===----------------------------------------------------------------------===//
// Member Pointer Evaluation
//===----------------------------------------------------------------------===//

namespace {
class MemberPointerExprEvaluator
  : public ExprEvaluatorBase<MemberPointerExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
                                  EvalInfo &Info) {}

bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {}

bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {}

//===----------------------------------------------------------------------===//
// Record Evaluation
//===----------------------------------------------------------------------===//

namespace {
  class RecordExprEvaluator
  : public ExprEvaluatorBase<RecordExprEvaluator> {};
}

/// Perform zero-initialization on an object of non-union class type.
/// C++11 [dcl.init]p5:
///  To zero-initialize an object or reference of type T means:
///    [...]
///    -- if T is a (possibly cv-qualified) non-union class type,
///       each non-static data member and each base-class subobject is
///       zero-initialized
static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
                                          const RecordDecl *RD,
                                          const LValue &This, APValue &Result) {}

bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {}

bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {}

bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {}

bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
    const Expr *ExprToVisit, ArrayRef<Expr *> Args) {}

bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
                                                QualType T) {}

bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
    const CXXInheritedCtorInitExpr *E) {}

bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
    const CXXStdInitializerListExpr *E) {}

bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {}

static bool EvaluateRecord(const Expr *E, const LValue &This,
                           APValue &Result, EvalInfo &Info) {}

//===----------------------------------------------------------------------===//
// Temporary Evaluation
//
// Temporaries are represented in the AST as rvalues, but generally behave like
// lvalues. The full-object of which the temporary is a subobject is implicitly
// materialized so that a reference can bind to it.
//===----------------------------------------------------------------------===//
namespace {
class TemporaryExprEvaluator
  : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {};
} // end anonymous namespace

/// Evaluate an expression of record type as a temporary.
static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {}

//===----------------------------------------------------------------------===//
// Vector Evaluation
//===----------------------------------------------------------------------===//

namespace {
  class VectorExprEvaluator
  : public ExprEvaluatorBase<VectorExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {}

bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {}

bool
VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {}

bool
VectorExprEvaluator::ZeroInitialization(const Expr *E) {}

bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {}

bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
                                                        QualType ResultTy,
                                                        UnaryOperatorKind Op,
                                                        APValue Elt) {}

bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {}

static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
                                    const Expr *E, QualType SourceTy,
                                    QualType DestTy, APValue const &Original,
                                    APValue &Result) {}

bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {}

static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E,
                                QualType ElemType, APValue const &VecVal1,
                                APValue const &VecVal2, unsigned EltNum,
                                APValue &Result) {}

bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {}

//===----------------------------------------------------------------------===//
// Array Evaluation
//===----------------------------------------------------------------------===//

namespace {
  class ArrayExprEvaluator
  : public ExprEvaluatorBase<ArrayExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateArray(const Expr *E, const LValue &This,
                          APValue &Result, EvalInfo &Info) {}

static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
                                     APValue &Result, const InitListExpr *ILE,
                                     QualType AllocType) {}

static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
                                          APValue &Result,
                                          const CXXConstructExpr *CCE,
                                          QualType AllocType) {}

// Return true iff the given array filler may depend on the element index.
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {}

bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
                                           QualType AllocType) {}

bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
    const Expr *ExprToVisit, ArrayRef<Expr *> Args, const Expr *ArrayFiller,
    QualType AllocType) {}

bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {}

bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {}

bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
                                               const LValue &Subobject,
                                               APValue *Value,
                                               QualType Type) {}

bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
    const CXXParenListInitExpr *E) {}

//===----------------------------------------------------------------------===//
// Integer Evaluation
//
// As a GNU extension, we support casting pointers to sufficiently-wide integer
// types and back in constant folding. Integer values are thus represented
// either as an integer-valued APValue, or as an lvalue-valued APValue.
//===----------------------------------------------------------------------===//

namespace {
class IntExprEvaluator
        : public ExprEvaluatorBase<IntExprEvaluator> {};

class FixedPointExprEvaluator
    : public ExprEvaluatorBase<FixedPointExprEvaluator> {};
} // end anonymous namespace

/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and
/// produce either the integer value or a pointer.
///
/// GCC has a heinous extension which folds casts between pointer types and
/// pointer-sized integral types. We support this by allowing the evaluation of
/// an integer rvalue to produce a pointer (represented as an lvalue) instead.
/// Some simple arithmetic on such values is supported (they are treated much
/// like char*).
static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
                                    EvalInfo &Info) {}

static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) {}

bool IntExprEvaluator::VisitSourceLocExpr(const SourceLocExpr *E) {}

static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
                               EvalInfo &Info) {}

static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
                                        EvalInfo &Info) {}

/// Check whether the given declaration can be directly converted to an integral
/// rvalue. If not, no diagnostic is produced; there are other things we can
/// try.
bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {}

/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
                                         const LangOptions &LangOpts) {}

/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
static GCCTypeClass
EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) {}

/// EvaluateBuiltinConstantPForLValue - Determine the result of
/// __builtin_constant_p when applied to the given pointer.
///
/// A pointer is only "constant" if it is null (or a pointer cast to integer)
/// or it points to the first character of a string literal.
static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {}

/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to
/// GCC as we can manage.
static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {}

/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
static QualType getObjectType(APValue::LValueBase B) {}

/// A more selective version of E->IgnoreParenCasts for
/// tryEvaluateBuiltinObjectSize. This ignores some casts/parens that serve only
/// to change the type of E.
/// Ex. For E = `(short*)((char*)(&foo))`, returns `&foo`
///
/// Always returns an RValue with a pointer representation.
static const Expr *ignorePointerCastsAndParens(const Expr *E) {}

/// Checks to see if the given LValue's Designator is at the end of the LValue's
/// record layout. e.g.
///   struct { struct { int a, b; } fst, snd; } obj;
///   obj.fst   // no
///   obj.snd   // yes
///   obj.fst.a // no
///   obj.fst.b // no
///   obj.snd.a // no
///   obj.snd.b // yes
///
/// Please note: this function is specialized for how __builtin_object_size
/// views "objects".
///
/// If this encounters an invalid RecordDecl or otherwise cannot determine the
/// correct result, it will always return true.
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {}

/// Tests to see if the LValue has a user-specified designator (that isn't
/// necessarily valid). Note that this always returns 'true' if the LValue has
/// an unsized array as its first designator entry, because there's currently no
/// way to tell if the user typed *foo or foo[0].
static bool refersToCompleteObject(const LValue &LVal) {}

/// Attempts to detect a user writing into a piece of memory that's impossible
/// to figure out the size of by just using types.
static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {}

/// Converts the given APInt to CharUnits, assuming the APInt is unsigned.
/// Fails if the conversion would cause loss of precision.
static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int,
                                            CharUnits &Result) {}

/// If we're evaluating the object size of an instance of a struct that
/// contains a flexible array member, add the size of the initializer.
static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T,
                                           const LValue &LV, CharUnits &Size) {}

/// Helper for tryEvaluateBuiltinObjectSize -- Given an LValue, this will
/// determine how many bytes exist from the beginning of the object to either
/// the end of the current subobject, or the end of the object itself, depending
/// on what the LValue looks like + the value of Type.
///
/// If this returns false, the value of Result is undefined.
static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc,
                               unsigned Type, const LValue &LVal,
                               CharUnits &EndOffset) {}

/// Tries to evaluate the __builtin_object_size for @p E. If successful,
/// returns true and stores the result in @p Size.
///
/// If @p WasError is non-null, this will report whether the failure to evaluate
/// is to be treated as an Error in IntExprEvaluator.
static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
                                         EvalInfo &Info, uint64_t &Size) {}

bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {}

static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
                                     APValue &Val, APSInt &Alignment) {}

bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
                                            unsigned BuiltinOp) {}

/// Determine whether this is a pointer past the end of the complete
/// object referred to by the lvalue.
static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx,
                                            const LValue &LV) {}

namespace {

/// Data recursive integer evaluator of certain binary operators.
///
/// We use a data recursive algorithm for binary operators so that we are able
/// to handle extreme cases of chained binary operators without causing stack
/// overflow.
class DataRecursiveIntBinOpEvaluator {};

}

bool DataRecursiveIntBinOpEvaluator::
       VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
                         bool &SuppressRHSDiags) {}

static void addOrSubLValueAsInteger(APValue &LVal, const APSInt &Index,
                                    bool IsSub) {}

bool DataRecursiveIntBinOpEvaluator::
       VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
                  const BinaryOperator *E, APValue &Result) {}

void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {}

namespace {
enum class CmpResult {};
}

template <class SuccessCB, class AfterCB>
static bool
EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
                                 SuccessCB &&Success, AfterCB &&DoAfter) {}

bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {}

bool RecordExprEvaluator::VisitCXXParenListInitExpr(
    const CXXParenListInitExpr *E) {}

bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
                                    const UnaryExprOrTypeTraitExpr *E) {}

bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {}

bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {}

/// HandleCast - This is used to evaluate implicit or explicit casts where the
/// result type is integer.
bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {}

bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {}

bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {}

bool IntExprEvaluator::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {}

bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {}

bool IntExprEvaluator::VisitConceptSpecializationExpr(
       const ConceptSpecializationExpr *E) {}

bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {}

bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {}

bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {}

bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

//===----------------------------------------------------------------------===//
// Float Evaluation
//===----------------------------------------------------------------------===//

namespace {
class FloatExprEvaluator
  : public ExprEvaluatorBase<FloatExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {}

static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
                                  QualType ResultTy,
                                  const Expr *Arg,
                                  bool SNaN,
                                  llvm::APFloat &Result) {}

bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {}

bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {}

bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {}

bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {}

bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {}

bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {}

//===----------------------------------------------------------------------===//
// Complex Evaluation (for float and integer)
//===----------------------------------------------------------------------===//

namespace {
class ComplexExprEvaluator
  : public ExprEvaluatorBase<ComplexExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
                            EvalInfo &Info) {}

bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {}

bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {}

bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {}

void HandleComplexComplexMul(APFloat A, APFloat B, APFloat C, APFloat D,
                             APFloat &ResR, APFloat &ResI) {}

void HandleComplexComplexDiv(APFloat A, APFloat B, APFloat C, APFloat D,
                             APFloat &ResR, APFloat &ResI) {}

bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {}

bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {}

bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {}

bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {}

//===----------------------------------------------------------------------===//
// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic
// implicit conversion.
//===----------------------------------------------------------------------===//

namespace {
class AtomicExprEvaluator :
    public ExprEvaluatorBase<AtomicExprEvaluator> {};
} // end anonymous namespace

static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
                           EvalInfo &Info) {}

//===----------------------------------------------------------------------===//
// Void expression evaluation, primarily for a cast to void on the LHS of a
// comma operator
//===----------------------------------------------------------------------===//

namespace {
class VoidExprEvaluator
  : public ExprEvaluatorBase<VoidExprEvaluator> {};
} // end anonymous namespace

bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {}

static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {}

//===----------------------------------------------------------------------===//
// Top level Expr::EvaluateAsRValue method.
//===----------------------------------------------------------------------===//

static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {}

/// EvaluateInPlace - Evaluate an expression in-place in an APValue. In some
/// cases, the in-place evaluation is essential, since later initializers for
/// an object can indirectly refer to subobjects which were initialized earlier.
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
                            const Expr *E, bool AllowNonLiteralTypes) {}

/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {}

static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
                                 const ASTContext &Ctx, bool &IsConst) {}

static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result,
                                      Expr::SideEffectsKind SEK) {}

static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result,
                             const ASTContext &Ctx, EvalInfo &Info) {}

static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
                          const ASTContext &Ctx,
                          Expr::SideEffectsKind AllowSideEffects,
                          EvalInfo &Info) {}

static bool EvaluateAsFixedPoint(const Expr *E, Expr::EvalResult &ExprResult,
                                 const ASTContext &Ctx,
                                 Expr::SideEffectsKind AllowSideEffects,
                                 EvalInfo &Info) {}

/// EvaluateAsRValue - Return true if this is a constant which we can fold using
/// any crazy technique (that has nothing to do with language standards) that
/// we want to.  If this function returns true, it returns the folded constant
/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
/// will be applied to the result.
bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
                            bool InConstantContext) const {}

bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
                                      bool InConstantContext) const {}

bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
                         SideEffectsKind AllowSideEffects,
                         bool InConstantContext) const {}

bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
                                SideEffectsKind AllowSideEffects,
                                bool InConstantContext) const {}

bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
                           SideEffectsKind AllowSideEffects,
                           bool InConstantContext) const {}

bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
                            bool InConstantContext) const {}

static bool EvaluateDestruction(const ASTContext &Ctx, APValue::LValueBase Base,
                                APValue DestroyedValue, QualType Type,
                                SourceLocation Loc, Expr::EvalStatus &EStatus,
                                bool IsConstantDestruction) {}

bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
                                  ConstantExprKind Kind) const {}

bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
                                 const VarDecl *VD,
                                 SmallVectorImpl<PartialDiagnosticAt> &Notes,
                                 bool IsConstantInitialization) const {}

bool VarDecl::evaluateDestruction(
    SmallVectorImpl<PartialDiagnosticAt> &Notes) const {}

/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded, but discard the result.
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {}

APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
                    SmallVectorImpl<PartialDiagnosticAt> *Diag) const {}

APSInt Expr::EvaluateKnownConstIntCheckOverflow(
    const ASTContext &Ctx, SmallVectorImpl<PartialDiagnosticAt> *Diag) const {}

void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {}

bool Expr::EvalResult::isGlobalLValue() const {}

/// isIntegerConstantExpr - this recursive routine will test if an expression is
/// an integer constant expression.

/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc

// CheckICE - This function does the fundamental ICE checking: the returned
// ICEDiag contains an ICEKind indicating whether the expression is an ICE,
// and a (possibly null) SourceLocation indicating the location of the problem.
//
// Note that to reduce code duplication, this helper does no evaluation
// itself; the caller checks whether the expression is evaluatable, and
// in the rare cases where CheckICE actually cares about the evaluated
// value, it calls into Evaluate.

namespace {

enum ICEKind {};

struct ICEDiag {};

}

static ICEDiag NoDiag() {}

static ICEDiag Worst(ICEDiag A, ICEDiag B) {}

static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {}

static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {}

/// Evaluate an expression as a C++11 integral constant expression.
static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
                                                    const Expr *E,
                                                    llvm::APSInt *Value,
                                                    SourceLocation *Loc) {}

bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
                                 SourceLocation *Loc) const {}

std::optional<llvm::APSInt>
Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc) const {}

bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {}

bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
                               SourceLocation *Loc) const {}

bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
                                    const FunctionDecl *Callee,
                                    ArrayRef<const Expr*> Args,
                                    const Expr *This) const {}

bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
                                   SmallVectorImpl<
                                     PartialDiagnosticAt> &Diags) {}

bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
                                              const FunctionDecl *FD,
                                              SmallVectorImpl<
                                                PartialDiagnosticAt> &Diags) {}

bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx,
                                 unsigned Type) const {}static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result,
                                  EvalInfo &Info, std::string *StringResult) {}std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const {}bool Expr::EvaluateCharRangeAsString(std::string &Result,
                                     const Expr *SizeExpression,
                                     const Expr *PtrExpression, ASTContext &Ctx,
                                     EvalResult &Status) const {}bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const {}struct IsWithinLifetimeHandler {}std::optional<bool> EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &IEE,
                                                    const CallExpr *E) {}