Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.cpp
213799 views
//===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Interp.h"9#include "Compiler.h"10#include "Function.h"11#include "InterpFrame.h"12#include "InterpShared.h"13#include "InterpStack.h"14#include "Opcode.h"15#include "PrimType.h"16#include "Program.h"17#include "State.h"18#include "clang/AST/ASTContext.h"19#include "clang/AST/CXXInheritance.h"20#include "clang/AST/DeclObjC.h"21#include "clang/AST/Expr.h"22#include "clang/AST/ExprCXX.h"23#include "clang/Basic/DiagnosticSema.h"24#include "clang/Basic/TargetInfo.h"25#include "llvm/ADT/StringExtras.h"2627using namespace clang;28using namespace clang::interp;2930static bool RetValue(InterpState &S, CodePtr &Pt) {31llvm::report_fatal_error("Interpreter cannot return values");32}3334//===----------------------------------------------------------------------===//35// Jmp, Jt, Jf36//===----------------------------------------------------------------------===//3738static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {39PC += Offset;40return true;41}4243static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {44if (S.Stk.pop<bool>()) {45PC += Offset;46}47return true;48}4950static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {51if (!S.Stk.pop<bool>()) {52PC += Offset;53}54return true;55}5657// https://github.com/llvm/llvm-project/issues/10251358#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)59#pragma optimize("", off)60#endif61// FIXME: We have the large switch over all opcodes here again, and in62// Interpret().63static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) {64[[maybe_unused]] CodePtr PCBefore = RealPC;65size_t StackSizeBefore = S.Stk.size();6667auto SpeculativeInterp = [&S, RealPC]() -> bool {68const InterpFrame *StartFrame = S.Current;69CodePtr PC = RealPC;7071for (;;) {72auto Op = PC.read<Opcode>();73if (Op == OP_EndSpeculation)74return true;75CodePtr OpPC = PC;7677switch (Op) {78#define GET_INTERP79#include "Opcodes.inc"80#undef GET_INTERP81}82}83llvm_unreachable("We didn't see an EndSpeculation op?");84};8586if (SpeculativeInterp()) {87if (PT == PT_Ptr) {88const auto &Ptr = S.Stk.pop<Pointer>();89assert(S.Stk.size() == StackSizeBefore);90S.Stk.push<Integral<32, true>>(91Integral<32, true>::from(CheckBCPResult(S, Ptr)));92} else {93// Pop the result from the stack and return success.94TYPE_SWITCH(PT, S.Stk.pop<T>(););95assert(S.Stk.size() == StackSizeBefore);96S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1));97}98} else {99if (!S.inConstantContext())100return Invalid(S, RealPC);101102S.Stk.clearTo(StackSizeBefore);103S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));104}105106// RealPC should not have been modified.107assert(*RealPC == *PCBefore);108109// Jump to end label. This is a little tricker than just RealPC += Offset110// because our usual jump instructions don't have any arguments, to the offset111// we get is a little too much and we need to subtract the size of the112// bool and PrimType arguments again.113int32_t ParamSize = align(sizeof(PrimType));114assert(Offset >= ParamSize);115RealPC += Offset - ParamSize;116117[[maybe_unused]] CodePtr PCCopy = RealPC;118assert(PCCopy.read<Opcode>() == OP_EndSpeculation);119120return true;121}122// https://github.com/llvm/llvm-project/issues/102513123#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)124#pragma optimize("", on)125#endif126127static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,128const ValueDecl *VD) {129const SourceInfo &E = S.Current->getSource(OpPC);130S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;131S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();132}133134static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,135const ValueDecl *VD);136static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,137const ValueDecl *D) {138// This function tries pretty hard to produce a good diagnostic. Just skip139// tha if nobody will see it anyway.140if (!S.diagnosing())141return false;142143if (isa<ParmVarDecl>(D)) {144if (D->getType()->isReferenceType())145return false;146147const SourceInfo &Loc = S.Current->getSource(OpPC);148if (S.getLangOpts().CPlusPlus11) {149S.FFDiag(Loc, diag::note_constexpr_function_param_value_unknown) << D;150S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();151} else {152S.FFDiag(Loc);153}154return false;155}156157if (!D->getType().isConstQualified()) {158diagnoseNonConstVariable(S, OpPC, D);159} else if (const auto *VD = dyn_cast<VarDecl>(D)) {160if (!VD->getAnyInitializer()) {161diagnoseMissingInitializer(S, OpPC, VD);162} else {163const SourceInfo &Loc = S.Current->getSource(OpPC);164S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;165S.Note(VD->getLocation(), diag::note_declared_at);166}167}168169return false;170}171172static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,173const ValueDecl *VD) {174if (!S.diagnosing())175return;176177const SourceInfo &Loc = S.Current->getSource(OpPC);178if (!S.getLangOpts().CPlusPlus) {179S.FFDiag(Loc);180return;181}182183if (const auto *VarD = dyn_cast<VarDecl>(VD);184VarD && VarD->getType().isConstQualified() &&185!VarD->getAnyInitializer()) {186diagnoseMissingInitializer(S, OpPC, VD);187return;188}189190// Rather random, but this is to match the diagnostic output of the current191// interpreter.192if (isa<ObjCIvarDecl>(VD))193return;194195if (VD->getType()->isIntegralOrEnumerationType()) {196S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;197S.Note(VD->getLocation(), diag::note_declared_at);198return;199}200201S.FFDiag(Loc,202S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr203: diag::note_constexpr_ltor_non_integral,2041)205<< VD << VD->getType();206S.Note(VD->getLocation(), diag::note_declared_at);207}208209static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,210AccessKinds AK) {211if (auto ID = Ptr.getDeclID()) {212if (!Ptr.isStaticTemporary())213return true;214215const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(216Ptr.getDeclDesc()->asExpr());217if (!MTE)218return true;219220// FIXME(perf): Since we do this check on every Load from a static221// temporary, it might make sense to cache the value of the222// isUsableInConstantExpressions call.223if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&224Ptr.block()->getEvalID() != S.Ctx.getEvalID()) {225const SourceInfo &E = S.Current->getSource(OpPC);226S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;227S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);228return false;229}230}231return true;232}233234static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {235if (auto ID = Ptr.getDeclID()) {236if (!Ptr.isStatic())237return true;238239if (S.P.getCurrentDecl() == ID)240return true;241242S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);243return false;244}245return true;246}247248namespace clang {249namespace interp {250static void popArg(InterpState &S, const Expr *Arg) {251PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);252TYPE_SWITCH(Ty, S.Stk.discard<T>());253}254255void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,256const Function *Func) {257assert(S.Current);258assert(Func);259260if (S.Current->Caller && Func->isVariadic()) {261// CallExpr we're look for is at the return PC of the current function, i.e.262// in the caller.263// This code path should be executed very rarely.264unsigned NumVarArgs;265const Expr *const *Args = nullptr;266unsigned NumArgs = 0;267const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());268if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {269Args = CE->getArgs();270NumArgs = CE->getNumArgs();271} else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {272Args = CE->getArgs();273NumArgs = CE->getNumArgs();274} else275assert(false && "Can't get arguments from that expression type");276277assert(NumArgs >= Func->getNumWrittenParams());278NumVarArgs = NumArgs - (Func->getNumWrittenParams() +279isa<CXXOperatorCallExpr>(CallSite));280for (unsigned I = 0; I != NumVarArgs; ++I) {281const Expr *A = Args[NumArgs - 1 - I];282popArg(S, A);283}284}285286// And in any case, remove the fixed parameters (the non-variadic ones)287// at the end.288for (PrimType Ty : Func->args_reverse())289TYPE_SWITCH(Ty, S.Stk.discard<T>());290}291292bool isConstexprUnknown(const Pointer &P) {293if (!P.isBlockPointer())294return false;295296if (P.isDummy())297return isa_and_nonnull<ParmVarDecl>(P.getDeclDesc()->asValueDecl());298299return P.getDeclDesc()->IsConstexprUnknown;300}301302bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {303if (Ptr.isDummy())304return false;305if (Ptr.isZero())306return true;307if (Ptr.isFunctionPointer())308return false;309if (Ptr.isIntegralPointer())310return true;311if (Ptr.isTypeidPointer())312return true;313314if (Ptr.getType()->isAnyComplexType())315return true;316317if (const Expr *Base = Ptr.getDeclDesc()->asExpr())318return isa<StringLiteral>(Base) && Ptr.getIndex() == 0;319return false;320}321322bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,323AccessKinds AK) {324if (Ptr.isActive())325return true;326327assert(Ptr.inUnion());328assert(Ptr.isField() && Ptr.getField());329330Pointer U = Ptr.getBase();331Pointer C = Ptr;332while (!U.isRoot() && !U.isActive()) {333// A little arbitrary, but this is what the current interpreter does.334// See the AnonymousUnion test in test/AST/ByteCode/unions.cpp.335// GCC's output is more similar to what we would get without336// this condition.337if (U.getRecord() && U.getRecord()->isAnonymousUnion())338break;339340C = U;341U = U.getBase();342}343assert(C.isField());344345// Consider:346// union U {347// struct {348// int x;349// int y;350// } a;351// }352//353// When activating x, we will also activate a. If we now try to read354// from y, we will get to CheckActive, because y is not active. In that355// case, our U will be a (not a union). We return here and let later code356// handle this.357if (!U.getFieldDesc()->isUnion())358return true;359360// Get the inactive field descriptor.361assert(!C.isActive());362const FieldDecl *InactiveField = C.getField();363assert(InactiveField);364365// Find the active field of the union.366const Record *R = U.getRecord();367assert(R && R->isUnion() && "Not a union");368369const FieldDecl *ActiveField = nullptr;370for (const Record::Field &F : R->fields()) {371const Pointer &Field = U.atField(F.Offset);372if (Field.isActive()) {373ActiveField = Field.getField();374break;375}376}377378const SourceInfo &Loc = S.Current->getSource(OpPC);379S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)380<< AK << InactiveField << !ActiveField << ActiveField;381return false;382}383384bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {385if (!Ptr.isExtern())386return true;387388if (Ptr.isInitialized() ||389(Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))390return true;391392if (S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus &&393Ptr.isConst())394return false;395396const auto *VD = Ptr.getDeclDesc()->asValueDecl();397diagnoseNonConstVariable(S, OpPC, VD);398return false;399}400401bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {402if (!Ptr.isUnknownSizeArray())403return true;404const SourceInfo &E = S.Current->getSource(OpPC);405S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);406return false;407}408409bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,410AccessKinds AK) {411if (Ptr.isZero()) {412const auto &Src = S.Current->getSource(OpPC);413414if (Ptr.isField())415S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;416else417S.FFDiag(Src, diag::note_constexpr_access_null) << AK;418419return false;420}421422if (!Ptr.isLive()) {423const auto &Src = S.Current->getSource(OpPC);424425if (Ptr.isDynamic()) {426S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;427} else if (!S.checkingPotentialConstantExpression()) {428bool IsTemp = Ptr.isTemporary();429S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;430431if (IsTemp)432S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);433else434S.Note(Ptr.getDeclLoc(), diag::note_declared_at);435}436437return false;438}439440return true;441}442443bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {444assert(Desc);445446const auto *D = Desc->asVarDecl();447if (!D || D == S.EvaluatingDecl || D->isConstexpr())448return true;449450// If we're evaluating the initializer for a constexpr variable in C23, we may451// only read other contexpr variables. Abort here since this one isn't452// constexpr.453if (const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);454VD && VD->isConstexpr() && S.getLangOpts().C23)455return Invalid(S, OpPC);456457QualType T = D->getType();458bool IsConstant = T.isConstant(S.getASTContext());459if (T->isIntegralOrEnumerationType()) {460if (!IsConstant) {461diagnoseNonConstVariable(S, OpPC, D);462return false;463}464return true;465}466467if (IsConstant) {468if (S.getLangOpts().CPlusPlus) {469S.CCEDiag(S.Current->getLocation(OpPC),470S.getLangOpts().CPlusPlus11471? diag::note_constexpr_ltor_non_constexpr472: diag::note_constexpr_ltor_non_integral,4731)474<< D << T;475S.Note(D->getLocation(), diag::note_declared_at);476} else {477S.CCEDiag(S.Current->getLocation(OpPC));478}479return true;480}481482if (T->isPointerOrReferenceType()) {483if (!T->getPointeeType().isConstant(S.getASTContext()) ||484!S.getLangOpts().CPlusPlus11) {485diagnoseNonConstVariable(S, OpPC, D);486return false;487}488return true;489}490491diagnoseNonConstVariable(S, OpPC, D);492return false;493}494495static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {496if (!Ptr.isStatic() || !Ptr.isBlockPointer())497return true;498if (!Ptr.getDeclID())499return true;500return CheckConstant(S, OpPC, Ptr.getDeclDesc());501}502503bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,504CheckSubobjectKind CSK) {505if (!Ptr.isZero())506return true;507const SourceInfo &Loc = S.Current->getSource(OpPC);508S.FFDiag(Loc, diag::note_constexpr_null_subobject)509<< CSK << S.Current->getRange(OpPC);510511return false;512}513514bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,515AccessKinds AK) {516if (!Ptr.isOnePastEnd())517return true;518if (S.getLangOpts().CPlusPlus) {519const SourceInfo &Loc = S.Current->getSource(OpPC);520S.FFDiag(Loc, diag::note_constexpr_access_past_end)521<< AK << S.Current->getRange(OpPC);522}523return false;524}525526bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,527CheckSubobjectKind CSK) {528if (!Ptr.isElementPastEnd())529return true;530const SourceInfo &Loc = S.Current->getSource(OpPC);531S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)532<< CSK << S.Current->getRange(OpPC);533return false;534}535536bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,537CheckSubobjectKind CSK) {538if (!Ptr.isOnePastEnd())539return true;540541const SourceInfo &Loc = S.Current->getSource(OpPC);542S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)543<< CSK << S.Current->getRange(OpPC);544return false;545}546547bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,548uint32_t Offset) {549uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();550uint32_t PtrOffset = Ptr.getByteOffset();551552// We subtract Offset from PtrOffset. The result must be at least553// MinOffset.554if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)555return true;556557const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));558QualType TargetQT = E->getType()->getPointeeType();559QualType MostDerivedQT = Ptr.getDeclPtr().getType();560561S.CCEDiag(E, diag::note_constexpr_invalid_downcast)562<< MostDerivedQT << TargetQT;563564return false;565}566567bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {568assert(Ptr.isLive() && "Pointer is not live");569if (!Ptr.isConst() || Ptr.isMutable())570return true;571572if (!Ptr.isBlockPointer())573return false;574575// The This pointer is writable in constructors and destructors,576// even if isConst() returns true.577if (llvm::find(S.InitializingBlocks, Ptr.block()))578return true;579580const QualType Ty = Ptr.getType();581const SourceInfo &Loc = S.Current->getSource(OpPC);582S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;583return false;584}585586bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {587assert(Ptr.isLive() && "Pointer is not live");588if (!Ptr.isMutable())589return true;590591// In C++14 onwards, it is permitted to read a mutable member whose592// lifetime began within the evaluation.593if (S.getLangOpts().CPlusPlus14 &&594Ptr.block()->getEvalID() == S.Ctx.getEvalID()) {595// FIXME: This check is necessary because (of the way) we revisit596// variables in Compiler.cpp:visitDeclRef. Revisiting a so far597// unknown variable will get the same EvalID and we end up allowing598// reads from mutable members of it.599if (!S.inConstantContext() && isConstexprUnknown(Ptr))600return false;601return true;602}603604const SourceInfo &Loc = S.Current->getSource(OpPC);605const FieldDecl *Field = Ptr.getField();606S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;607S.Note(Field->getLocation(), diag::note_declared_at);608return false;609}610611static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,612AccessKinds AK) {613assert(Ptr.isLive());614615if (!Ptr.isVolatile())616return true;617618if (!S.getLangOpts().CPlusPlus)619return Invalid(S, OpPC);620621// The reason why Ptr is volatile might be further up the hierarchy.622// Find that pointer.623Pointer P = Ptr;624while (!P.isRoot()) {625if (P.getType().isVolatileQualified())626break;627P = P.getBase();628}629630const NamedDecl *ND = nullptr;631int DiagKind;632SourceLocation Loc;633if (const auto *F = P.getField()) {634DiagKind = 2;635Loc = F->getLocation();636ND = F;637} else if (auto *VD = P.getFieldDesc()->asValueDecl()) {638DiagKind = 1;639Loc = VD->getLocation();640ND = VD;641} else {642DiagKind = 0;643if (const auto *E = P.getFieldDesc()->asExpr())644Loc = E->getExprLoc();645}646647S.FFDiag(S.Current->getLocation(OpPC),648diag::note_constexpr_access_volatile_obj, 1)649<< AK << DiagKind << ND;650S.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;651return false;652}653654bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,655AccessKinds AK) {656assert(Ptr.isLive());657658if (Ptr.isInitialized())659return true;660661if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();662VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {663664if (VD == S.EvaluatingDecl &&665!(S.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {666if (!S.getLangOpts().CPlusPlus14 &&667!VD->getType().isConstant(S.getASTContext())) {668// Diagnose as non-const read.669diagnoseNonConstVariable(S, OpPC, VD);670} else {671const SourceInfo &Loc = S.Current->getSource(OpPC);672// Diagnose as "read of object outside its lifetime".673S.FFDiag(Loc, diag::note_constexpr_access_uninit)674<< AK << /*IsIndeterminate=*/false;675}676return false;677}678679if (VD->getAnyInitializer()) {680const SourceInfo &Loc = S.Current->getSource(OpPC);681S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;682S.Note(VD->getLocation(), diag::note_declared_at);683} else {684diagnoseMissingInitializer(S, OpPC, VD);685}686return false;687}688689if (!S.checkingPotentialConstantExpression()) {690S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)691<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);692}693return false;694}695696static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,697AccessKinds AK) {698if (Ptr.getLifetime() == Lifetime::Started)699return true;700701if (!S.checkingPotentialConstantExpression()) {702S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)703<< AK << /*uninitialized=*/false << S.Current->getRange(OpPC);704}705return false;706}707708bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {709if (Ptr.isInitialized())710return true;711712assert(S.getLangOpts().CPlusPlus);713const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());714if ((!VD->hasConstantInitialization() &&715VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||716(S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&717!VD->hasICEInitializer(S.getASTContext()))) {718const SourceInfo &Loc = S.Current->getSource(OpPC);719S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;720S.Note(VD->getLocation(), diag::note_declared_at);721}722return false;723}724725static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {726if (!Ptr.isWeak())727return true;728729const auto *VD = Ptr.getDeclDesc()->asVarDecl();730assert(VD);731S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)732<< VD;733S.Note(VD->getLocation(), diag::note_declared_at);734735return false;736}737738bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,739AccessKinds AK) {740if (!CheckLive(S, OpPC, Ptr, AK))741return false;742if (!CheckExtern(S, OpPC, Ptr))743return false;744if (!CheckConstant(S, OpPC, Ptr))745return false;746if (!CheckDummy(S, OpPC, Ptr, AK))747return false;748if (!CheckRange(S, OpPC, Ptr, AK))749return false;750if (!CheckActive(S, OpPC, Ptr, AK))751return false;752if (!CheckLifetime(S, OpPC, Ptr, AK))753return false;754if (!CheckInitialized(S, OpPC, Ptr, AK))755return false;756if (!CheckTemporary(S, OpPC, Ptr, AK))757return false;758if (!CheckWeak(S, OpPC, Ptr))759return false;760if (!CheckMutable(S, OpPC, Ptr))761return false;762if (!CheckVolatile(S, OpPC, Ptr, AK))763return false;764return true;765}766767/// This is not used by any of the opcodes directly. It's used by768/// EvalEmitter to do the final lvalue-to-rvalue conversion.769bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {770if (!CheckLive(S, OpPC, Ptr, AK_Read))771return false;772if (!CheckConstant(S, OpPC, Ptr))773return false;774775if (!CheckDummy(S, OpPC, Ptr, AK_Read))776return false;777if (!CheckExtern(S, OpPC, Ptr))778return false;779if (!CheckRange(S, OpPC, Ptr, AK_Read))780return false;781if (!CheckActive(S, OpPC, Ptr, AK_Read))782return false;783if (!CheckLifetime(S, OpPC, Ptr, AK_Read))784return false;785if (!CheckInitialized(S, OpPC, Ptr, AK_Read))786return false;787if (!CheckTemporary(S, OpPC, Ptr, AK_Read))788return false;789if (!CheckWeak(S, OpPC, Ptr))790return false;791if (!CheckMutable(S, OpPC, Ptr))792return false;793return true;794}795796bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {797if (!CheckLive(S, OpPC, Ptr, AK_Assign))798return false;799if (!CheckDummy(S, OpPC, Ptr, AK_Assign))800return false;801if (!CheckLifetime(S, OpPC, Ptr, AK_Assign))802return false;803if (!CheckExtern(S, OpPC, Ptr))804return false;805if (!CheckRange(S, OpPC, Ptr, AK_Assign))806return false;807if (!CheckGlobal(S, OpPC, Ptr))808return false;809if (!CheckConst(S, OpPC, Ptr))810return false;811if (!S.inConstantContext() && isConstexprUnknown(Ptr))812return false;813return true;814}815816bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {817if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))818return false;819if (!Ptr.isDummy()) {820if (!CheckExtern(S, OpPC, Ptr))821return false;822if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))823return false;824}825return true;826}827828bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {829if (!CheckLive(S, OpPC, Ptr, AK_Assign))830return false;831if (!CheckRange(S, OpPC, Ptr, AK_Assign))832return false;833return true;834}835836bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {837838if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {839const SourceLocation &Loc = S.Current->getLocation(OpPC);840S.CCEDiag(Loc, diag::note_constexpr_virtual_call);841return false;842}843844if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)845return false;846847if (F->isValid() && F->hasBody() && F->isConstexpr())848return true;849850// Implicitly constexpr.851if (F->isLambdaStaticInvoker())852return true;853854// Bail out if the function declaration itself is invalid. We will855// have produced a relevant diagnostic while parsing it, so just856// note the problematic sub-expression.857if (F->getDecl()->isInvalidDecl())858return Invalid(S, OpPC);859860// Diagnose failed assertions specially.861if (S.Current->getLocation(OpPC).isMacroID() &&862F->getDecl()->getIdentifier()) {863// FIXME: Instead of checking for an implementation-defined function,864// check and evaluate the assert() macro.865StringRef Name = F->getDecl()->getName();866bool AssertFailed =867Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";868if (AssertFailed) {869S.FFDiag(S.Current->getLocation(OpPC),870diag::note_constexpr_assert_failed);871return false;872}873}874875if (S.getLangOpts().CPlusPlus11) {876const FunctionDecl *DiagDecl = F->getDecl();877878// Invalid decls have been diagnosed before.879if (DiagDecl->isInvalidDecl())880return false;881882// If this function is not constexpr because it is an inherited883// non-constexpr constructor, diagnose that directly.884const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);885if (CD && CD->isInheritingConstructor()) {886const auto *Inherited = CD->getInheritedConstructor().getConstructor();887if (!Inherited->isConstexpr())888DiagDecl = CD = Inherited;889}890891// Silently reject constructors of invalid classes. The invalid class892// has been rejected elsewhere before.893if (CD && CD->getParent()->isInvalidDecl())894return false;895896// FIXME: If DiagDecl is an implicitly-declared special member function897// or an inheriting constructor, we should be much more explicit about why898// it's not constexpr.899if (CD && CD->isInheritingConstructor()) {900S.FFDiag(S.Current->getLocation(OpPC),901diag::note_constexpr_invalid_inhctor, 1)902<< CD->getInheritedConstructor().getConstructor()->getParent();903S.Note(DiagDecl->getLocation(), diag::note_declared_at);904} else {905// Don't emit anything if the function isn't defined and we're checking906// for a constant expression. It might be defined at the point we're907// actually calling it.908bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;909bool IsDefined = F->isDefined();910if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&911S.checkingPotentialConstantExpression())912return false;913914// If the declaration is defined, declared 'constexpr' _and_ has a body,915// the below diagnostic doesn't add anything useful.916if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&917DiagDecl->hasBody())918return false;919920S.FFDiag(S.Current->getLocation(OpPC),921diag::note_constexpr_invalid_function, 1)922<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;923924if (DiagDecl->getDefinition())925S.Note(DiagDecl->getDefinition()->getLocation(),926diag::note_declared_at);927else928S.Note(DiagDecl->getLocation(), diag::note_declared_at);929}930} else {931S.FFDiag(S.Current->getLocation(OpPC),932diag::note_invalid_subexpr_in_const_expr);933}934935return false;936}937938bool CheckCallDepth(InterpState &S, CodePtr OpPC) {939if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {940S.FFDiag(S.Current->getSource(OpPC),941diag::note_constexpr_depth_limit_exceeded)942<< S.getLangOpts().ConstexprCallDepth;943return false;944}945946return true;947}948949bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {950if (!This.isZero())951return true;952953const Expr *E = S.Current->getExpr(OpPC);954if (S.getLangOpts().CPlusPlus11) {955bool IsImplicit = false;956if (const auto *TE = dyn_cast<CXXThisExpr>(E))957IsImplicit = TE->isImplicit();958S.FFDiag(E, diag::note_constexpr_this) << IsImplicit;959} else {960S.FFDiag(E);961}962963return false;964}965966bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,967APFloat::opStatus Status, FPOptions FPO) {968// [expr.pre]p4:969// If during the evaluation of an expression, the result is not970// mathematically defined [...], the behavior is undefined.971// FIXME: C++ rules require us to not conform to IEEE 754 here.972if (Result.isNan()) {973const SourceInfo &E = S.Current->getSource(OpPC);974S.CCEDiag(E, diag::note_constexpr_float_arithmetic)975<< /*NaN=*/true << S.Current->getRange(OpPC);976return S.noteUndefinedBehavior();977}978979// In a constant context, assume that any dynamic rounding mode or FP980// exception state matches the default floating-point environment.981if (S.inConstantContext())982return true;983984if ((Status & APFloat::opInexact) &&985FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {986// Inexact result means that it depends on rounding mode. If the requested987// mode is dynamic, the evaluation cannot be made in compile time.988const SourceInfo &E = S.Current->getSource(OpPC);989S.FFDiag(E, diag::note_constexpr_dynamic_rounding);990return false;991}992993if ((Status != APFloat::opOK) &&994(FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||995FPO.getExceptionMode() != LangOptions::FPE_Ignore ||996FPO.getAllowFEnvAccess())) {997const SourceInfo &E = S.Current->getSource(OpPC);998S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);999return false;1000}10011002if ((Status & APFloat::opStatus::opInvalidOp) &&1003FPO.getExceptionMode() != LangOptions::FPE_Ignore) {1004const SourceInfo &E = S.Current->getSource(OpPC);1005// There is no usefully definable result.1006S.FFDiag(E);1007return false;1008}10091010return true;1011}10121013bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {1014if (S.getLangOpts().CPlusPlus20)1015return true;10161017const SourceInfo &E = S.Current->getSource(OpPC);1018S.CCEDiag(E, diag::note_constexpr_new);1019return true;1020}10211022bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,1023DynamicAllocator::Form AllocForm,1024DynamicAllocator::Form DeleteForm, const Descriptor *D,1025const Expr *NewExpr) {1026if (AllocForm == DeleteForm)1027return true;10281029QualType TypeToDiagnose = D->getDataType(S.getASTContext());10301031const SourceInfo &E = S.Current->getSource(OpPC);1032S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)1033<< static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)1034<< TypeToDiagnose;1035S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)1036<< NewExpr->getSourceRange();1037return false;1038}10391040bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,1041const Pointer &Ptr) {1042// Regular new type(...) call.1043if (isa_and_nonnull<CXXNewExpr>(Source))1044return true;1045// operator new.1046if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);1047CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)1048return true;1049// std::allocator.allocate() call1050if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);1051MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))1052return true;10531054// Whatever this is, we didn't heap allocate it.1055const SourceInfo &Loc = S.Current->getSource(OpPC);1056S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)1057<< Ptr.toDiagnosticString(S.getASTContext());10581059if (Ptr.isTemporary())1060S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);1061else1062S.Note(Ptr.getDeclLoc(), diag::note_declared_at);1063return false;1064}10651066/// We aleady know the given DeclRefExpr is invalid for some reason,1067/// now figure out why and print appropriate diagnostics.1068bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {1069const ValueDecl *D = DR->getDecl();1070return diagnoseUnknownDecl(S, OpPC, D);1071}10721073bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,1074AccessKinds AK) {1075if (!Ptr.isDummy())1076return true;10771078const Descriptor *Desc = Ptr.getDeclDesc();1079const ValueDecl *D = Desc->asValueDecl();1080if (!D)1081return false;10821083if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)1084return diagnoseUnknownDecl(S, OpPC, D);10851086if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14) {1087const SourceInfo &E = S.Current->getSource(OpPC);1088S.FFDiag(E, diag::note_constexpr_modify_global);1089}1090return false;1091}10921093bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,1094const CallExpr *CE, unsigned ArgSize) {1095auto Args = ArrayRef(CE->getArgs(), CE->getNumArgs());1096auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);1097unsigned Offset = 0;1098unsigned Index = 0;1099for (const Expr *Arg : Args) {1100if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {1101const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);1102if (ArgPtr.isZero()) {1103const SourceLocation &Loc = S.Current->getLocation(OpPC);1104S.CCEDiag(Loc, diag::note_non_null_attribute_failed);1105return false;1106}1107}11081109Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));1110++Index;1111}1112return true;1113}11141115static bool runRecordDestructor(InterpState &S, CodePtr OpPC,1116const Pointer &BasePtr,1117const Descriptor *Desc) {1118assert(Desc->isRecord());1119const Record *R = Desc->ElemRecord;1120assert(R);11211122if (Pointer::pointToSameBlock(BasePtr, S.Current->getThis()) &&1123S.Current->getFunction()->isDestructor()) {1124const SourceInfo &Loc = S.Current->getSource(OpPC);1125S.FFDiag(Loc, diag::note_constexpr_double_destroy);1126return false;1127}11281129// Destructor of this record.1130if (const CXXDestructorDecl *Dtor = R->getDestructor();1131Dtor && !Dtor->isTrivial()) {1132const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);1133if (!DtorFunc)1134return false;11351136S.Stk.push<Pointer>(BasePtr);1137if (!Call(S, OpPC, DtorFunc, 0))1138return false;1139}1140return true;1141}11421143static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {1144assert(B);1145const Descriptor *Desc = B->getDescriptor();11461147if (Desc->isPrimitive() || Desc->isPrimitiveArray())1148return true;11491150assert(Desc->isRecord() || Desc->isCompositeArray());11511152if (Desc->isCompositeArray()) {1153unsigned N = Desc->getNumElems();1154if (N == 0)1155return true;1156const Descriptor *ElemDesc = Desc->ElemDesc;1157assert(ElemDesc->isRecord());11581159Pointer RP(const_cast<Block *>(B));1160for (int I = static_cast<int>(N) - 1; I >= 0; --I) {1161if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))1162return false;1163}1164return true;1165}11661167assert(Desc->isRecord());1168return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);1169}11701171static bool hasVirtualDestructor(QualType T) {1172if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())1173if (const CXXDestructorDecl *DD = RD->getDestructor())1174return DD->isVirtual();1175return false;1176}11771178bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,1179bool IsGlobalDelete) {1180if (!CheckDynamicMemoryAllocation(S, OpPC))1181return false;11821183DynamicAllocator &Allocator = S.getAllocator();11841185const Expr *Source = nullptr;1186const Block *BlockToDelete = nullptr;1187{1188// Extra scope for this so the block doesn't have this pointer1189// pointing to it when we destroy it.1190Pointer Ptr = S.Stk.pop<Pointer>();11911192// Deleteing nullptr is always fine.1193if (Ptr.isZero())1194return true;11951196// Remove base casts.1197QualType InitialType = Ptr.getType();1198while (Ptr.isBaseClass())1199Ptr = Ptr.getBase();12001201Source = Ptr.getDeclDesc()->asExpr();1202BlockToDelete = Ptr.block();12031204// Check that new[]/delete[] or new/delete were used, not a mixture.1205const Descriptor *BlockDesc = BlockToDelete->getDescriptor();1206if (std::optional<DynamicAllocator::Form> AllocForm =1207Allocator.getAllocationForm(Source)) {1208DynamicAllocator::Form DeleteForm =1209DeleteIsArrayForm ? DynamicAllocator::Form::Array1210: DynamicAllocator::Form::NonArray;1211if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,1212Source))1213return false;1214}12151216// For the non-array case, the types must match if the static type1217// does not have a virtual destructor.1218if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&1219!hasVirtualDestructor(InitialType)) {1220S.FFDiag(S.Current->getSource(OpPC),1221diag::note_constexpr_delete_base_nonvirt_dtor)1222<< InitialType << Ptr.getType();1223return false;1224}12251226if (!Ptr.isRoot() || Ptr.isOnePastEnd() ||1227(Ptr.isArrayElement() && Ptr.getIndex() != 0)) {1228const SourceInfo &Loc = S.Current->getSource(OpPC);1229S.FFDiag(Loc, diag::note_constexpr_delete_subobject)1230<< Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();1231return false;1232}12331234if (!CheckDeleteSource(S, OpPC, Source, Ptr))1235return false;12361237// For a class type with a virtual destructor, the selected operator delete1238// is the one looked up when building the destructor.1239if (!DeleteIsArrayForm && !IsGlobalDelete) {1240QualType AllocType = Ptr.getType();1241auto getVirtualOperatorDelete = [](QualType T) -> const FunctionDecl * {1242if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())1243if (const CXXDestructorDecl *DD = RD->getDestructor())1244return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;1245return nullptr;1246};12471248if (const FunctionDecl *VirtualDelete =1249getVirtualOperatorDelete(AllocType);1250VirtualDelete &&1251!VirtualDelete1252->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {1253S.FFDiag(S.Current->getSource(OpPC),1254diag::note_constexpr_new_non_replaceable)1255<< isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;1256return false;1257}1258}1259}1260assert(Source);1261assert(BlockToDelete);12621263// Invoke destructors before deallocating the memory.1264if (!RunDestructors(S, OpPC, BlockToDelete))1265return false;12661267if (!Allocator.deallocate(Source, BlockToDelete, S)) {1268// Nothing has been deallocated, this must be a double-delete.1269const SourceInfo &Loc = S.Current->getSource(OpPC);1270S.FFDiag(Loc, diag::note_constexpr_double_delete);1271return false;1272}12731274return true;1275}12761277void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,1278const APSInt &Value) {1279if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())1280return;12811282llvm::APInt Min;1283llvm::APInt Max;1284ED->getValueRange(Max, Min);1285--Max;12861287if (ED->getNumNegativeBits() &&1288(Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {1289const SourceLocation &Loc = S.Current->getLocation(OpPC);1290S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)1291<< llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()1292<< ED;1293} else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {1294const SourceLocation &Loc = S.Current->getLocation(OpPC);1295S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)1296<< llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()1297<< ED;1298}1299}13001301bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {1302assert(T);1303assert(!S.getLangOpts().CPlusPlus23);13041305// C++1y: A constant initializer for an object o [...] may also invoke1306// constexpr constructors for o and its subobjects even if those objects1307// are of non-literal class types.1308//1309// C++11 missed this detail for aggregates, so classes like this:1310// struct foo_t { union { int i; volatile int j; } u; };1311// are not (obviously) initializable like so:1312// __attribute__((__require_constant_initialization__))1313// static const foo_t x = {{0}};1314// because "i" is a subobject with non-literal initialization (due to the1315// volatile member of the union). See:1316// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#16771317// Therefore, we use the C++1y behavior.13181319if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&1320S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {1321return true;1322}13231324const Expr *E = S.Current->getExpr(OpPC);1325if (S.getLangOpts().CPlusPlus11)1326S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();1327else1328S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);1329return false;1330}13311332static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,1333uint32_t Off) {1334if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&1335!CheckNull(S, OpPC, Ptr, CSK_Field))1336return false;13371338if (!CheckRange(S, OpPC, Ptr, CSK_Field))1339return false;1340if (!CheckArray(S, OpPC, Ptr))1341return false;1342if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))1343return false;13441345if (Ptr.isIntegralPointer()) {1346S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));1347return true;1348}13491350if (!Ptr.isBlockPointer()) {1351// FIXME: The only time we (seem to) get here is when trying to access a1352// field of a typeid pointer. In that case, we're supposed to diagnose e.g.1353// `typeid(int).name`, but we currently diagnose `&typeid(int)`.1354S.FFDiag(S.Current->getSource(OpPC),1355diag::note_constexpr_access_unreadable_object)1356<< AK_Read << Ptr.toDiagnosticString(S.getASTContext());1357return false;1358}13591360if ((Ptr.getByteOffset() + Off) >= Ptr.block()->getSize())1361return false;13621363S.Stk.push<Pointer>(Ptr.atField(Off));1364return true;1365}13661367bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {1368const auto &Ptr = S.Stk.peek<Pointer>();1369return getField(S, OpPC, Ptr, Off);1370}13711372bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {1373const auto &Ptr = S.Stk.pop<Pointer>();1374return getField(S, OpPC, Ptr, Off);1375}13761377static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,1378const Pointer &ThisPtr) {1379assert(Func->isConstructor());13801381if (Func->getParentDecl()->isInvalidDecl())1382return false;13831384const Descriptor *D = ThisPtr.getFieldDesc();1385// FIXME: I think this case is not 100% correct. E.g. a pointer into a1386// subobject of a composite array.1387if (!D->ElemRecord)1388return true;13891390if (D->ElemRecord->getNumVirtualBases() == 0)1391return true;13921393S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)1394<< Func->getParentDecl();1395return false;1396}13971398bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {1399if (!CheckLive(S, OpPC, Ptr, AK_Destroy))1400return false;1401if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))1402return false;1403if (!CheckRange(S, OpPC, Ptr, AK_Destroy))1404return false;14051406// Can't call a dtor on a global variable.1407if (Ptr.block()->isStatic()) {1408const SourceInfo &E = S.Current->getSource(OpPC);1409S.FFDiag(E, diag::note_constexpr_modify_global);1410return false;1411}1412return CheckActive(S, OpPC, Ptr, AK_Destroy);1413}14141415static void compileFunction(InterpState &S, const Function *Func) {1416Compiler<ByteCodeEmitter>(S.getContext(), S.P)1417.compileFunc(Func->getDecl()->getMostRecentDecl(),1418const_cast<Function *>(Func));1419}14201421bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,1422uint32_t VarArgSize) {1423if (Func->hasThisPointer()) {1424size_t ArgSize = Func->getArgSize() + VarArgSize;1425size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);1426const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);14271428// If the current function is a lambda static invoker and1429// the function we're about to call is a lambda call operator,1430// skip the CheckInvoke, since the ThisPtr is a null pointer1431// anyway.1432if (!(S.Current->getFunction() &&1433S.Current->getFunction()->isLambdaStaticInvoker() &&1434Func->isLambdaCallOperator())) {1435if (!CheckInvoke(S, OpPC, ThisPtr))1436return false;1437}14381439if (S.checkingPotentialConstantExpression())1440return false;1441}14421443if (!Func->isFullyCompiled())1444compileFunction(S, Func);14451446if (!CheckCallable(S, OpPC, Func))1447return false;14481449if (!CheckCallDepth(S, OpPC))1450return false;14511452auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);1453InterpFrame *FrameBefore = S.Current;1454S.Current = NewFrame.get();14551456// Note that we cannot assert(CallResult.hasValue()) here since1457// Ret() above only sets the APValue if the curent frame doesn't1458// have a caller set.1459if (Interpret(S)) {1460NewFrame.release(); // Frame was delete'd already.1461assert(S.Current == FrameBefore);1462return true;1463}14641465// Interpreting the function failed somehow. Reset to1466// previous state.1467S.Current = FrameBefore;1468return false;1469}1470bool Call(InterpState &S, CodePtr OpPC, const Function *Func,1471uint32_t VarArgSize) {1472assert(Func);1473auto cleanup = [&]() -> bool {1474cleanupAfterFunctionCall(S, OpPC, Func);1475return false;1476};14771478if (Func->hasThisPointer()) {1479size_t ArgSize = Func->getArgSize() + VarArgSize;1480size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);14811482const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);14831484// C++23 [expr.const]p5.61485// an invocation of a virtual function ([class.virtual]) for an object whose1486// dynamic type is constexpr-unknown;1487if (ThisPtr.isDummy() && Func->isVirtual())1488return false;14891490// If the current function is a lambda static invoker and1491// the function we're about to call is a lambda call operator,1492// skip the CheckInvoke, since the ThisPtr is a null pointer1493// anyway.1494if (S.Current->getFunction() &&1495S.Current->getFunction()->isLambdaStaticInvoker() &&1496Func->isLambdaCallOperator()) {1497assert(ThisPtr.isZero());1498} else {1499if (!CheckInvoke(S, OpPC, ThisPtr))1500return cleanup();1501if (!Func->isConstructor() && !Func->isDestructor() &&1502!Func->isCopyOrMoveOperator() &&1503!CheckActive(S, OpPC, ThisPtr, AK_MemberCall))1504return false;1505}15061507if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))1508return false;1509if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))1510return false;15111512if (Func->isConstructor() || Func->isDestructor())1513S.InitializingBlocks.push_back(ThisPtr.block());1514}15151516if (!Func->isFullyCompiled())1517compileFunction(S, Func);15181519if (!CheckCallable(S, OpPC, Func))1520return cleanup();15211522// FIXME: The isConstructor() check here is not always right. The current1523// constant evaluator is somewhat inconsistent in when it allows a function1524// call when checking for a constant expression.1525if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&1526!Func->isConstructor())1527return cleanup();15281529if (!CheckCallDepth(S, OpPC))1530return cleanup();15311532auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);1533InterpFrame *FrameBefore = S.Current;1534S.Current = NewFrame.get();15351536InterpStateCCOverride CCOverride(S, Func->isImmediate());1537// Note that we cannot assert(CallResult.hasValue()) here since1538// Ret() above only sets the APValue if the curent frame doesn't1539// have a caller set.1540bool Success = Interpret(S);1541// Remove initializing block again.1542if (Func->isConstructor() || Func->isDestructor())1543S.InitializingBlocks.pop_back();15441545if (!Success) {1546// Interpreting the function failed somehow. Reset to1547// previous state.1548S.Current = FrameBefore;1549return false;1550}15511552NewFrame.release(); // Frame was delete'd already.1553assert(S.Current == FrameBefore);1554return true;1555}15561557bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,1558uint32_t VarArgSize) {1559assert(Func->hasThisPointer());1560assert(Func->isVirtual());1561size_t ArgSize = Func->getArgSize() + VarArgSize;1562size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);1563Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);1564const FunctionDecl *Callee = Func->getDecl();15651566if (!Func->isFullyCompiled())1567compileFunction(S, Func);15681569// C++2a [class.abstract]p6:1570// the effect of making a virtual call to a pure virtual function [...] is1571// undefined1572if (Callee->isPureVirtual()) {1573S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,15741)1575<< Callee;1576S.Note(Callee->getLocation(), diag::note_declared_at);1577return false;1578}15791580const CXXRecordDecl *DynamicDecl = nullptr;1581{1582Pointer TypePtr = ThisPtr;1583while (TypePtr.isBaseClass())1584TypePtr = TypePtr.getBase();15851586QualType DynamicType = TypePtr.getType();1587if (DynamicType->isPointerType() || DynamicType->isReferenceType())1588DynamicDecl = DynamicType->getPointeeCXXRecordDecl();1589else1590DynamicDecl = DynamicType->getAsCXXRecordDecl();1591}1592assert(DynamicDecl);15931594const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());1595const auto *InitialFunction = cast<CXXMethodDecl>(Callee);1596const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(1597DynamicDecl, StaticDecl, InitialFunction);15981599if (Overrider != InitialFunction) {1600// DR1872: An instantiated virtual constexpr function can't be called in a1601// constant expression (prior to C++20). We can still constant-fold such a1602// call.1603if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {1604const Expr *E = S.Current->getExpr(OpPC);1605S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();1606}16071608Func = S.getContext().getOrCreateFunction(Overrider);16091610const CXXRecordDecl *ThisFieldDecl =1611ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();1612if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {1613// If the function we call is further DOWN the hierarchy than the1614// FieldDesc of our pointer, just go up the hierarchy of this field1615// the furthest we can go.1616while (ThisPtr.isBaseClass())1617ThisPtr = ThisPtr.getBase();1618}1619}16201621if (!Call(S, OpPC, Func, VarArgSize))1622return false;16231624// Covariant return types. The return type of Overrider is a pointer1625// or reference to a class type.1626if (Overrider != InitialFunction &&1627Overrider->getReturnType()->isPointerOrReferenceType() &&1628InitialFunction->getReturnType()->isPointerOrReferenceType()) {1629QualType OverriderPointeeType =1630Overrider->getReturnType()->getPointeeType();1631QualType InitialPointeeType =1632InitialFunction->getReturnType()->getPointeeType();1633// We've called Overrider above, but calling code expects us to return what1634// InitialFunction returned. According to the rules for covariant return1635// types, what InitialFunction returns needs to be a base class of what1636// Overrider returns. So, we need to do an upcast here.1637unsigned Offset = S.getContext().collectBaseOffset(1638InitialPointeeType->getAsRecordDecl(),1639OverriderPointeeType->getAsRecordDecl());1640return GetPtrBasePop(S, OpPC, Offset, /*IsNullOK=*/true);1641}16421643return true;1644}16451646bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,1647uint32_t BuiltinID) {1648// A little arbitrary, but the current interpreter allows evaluation1649// of builtin functions in this mode, with some exceptions.1650if (BuiltinID == Builtin::BI__builtin_operator_new &&1651S.checkingPotentialConstantExpression())1652return false;16531654return InterpretBuiltin(S, OpPC, CE, BuiltinID);1655}16561657bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,1658const CallExpr *CE) {1659const Pointer &Ptr = S.Stk.pop<Pointer>();16601661if (Ptr.isZero()) {1662const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));1663S.FFDiag(E, diag::note_constexpr_null_callee)1664<< const_cast<Expr *>(E->getCallee()) << E->getSourceRange();1665return false;1666}16671668if (!Ptr.isFunctionPointer())1669return Invalid(S, OpPC);16701671const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();1672const Function *F = FuncPtr.getFunction();1673assert(F);1674// Don't allow calling block pointers.1675if (!F->getDecl())1676return Invalid(S, OpPC);16771678// This happens when the call expression has been cast to1679// something else, but we don't support that.1680if (S.Ctx.classify(F->getDecl()->getReturnType()) !=1681S.Ctx.classify(CE->getCallReturnType(S.getASTContext())))1682return false;16831684// Check argument nullability state.1685if (F->hasNonNullAttr()) {1686if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))1687return false;1688}16891690assert(ArgSize >= F->getWrittenArgSize());1691uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();16921693// We need to do this explicitly here since we don't have the necessary1694// information to do it automatically.1695if (F->isThisPointerExplicit())1696VarArgSize -= align(primSize(PT_Ptr));16971698if (F->isVirtual())1699return CallVirt(S, OpPC, F, VarArgSize);17001701return Call(S, OpPC, F, VarArgSize);1702}17031704static void startLifetimeRecurse(const Pointer &Ptr) {1705if (const Record *R = Ptr.getRecord()) {1706Ptr.startLifetime();1707for (const Record::Field &Fi : R->fields())1708startLifetimeRecurse(Ptr.atField(Fi.Offset));1709return;1710}17111712if (const Descriptor *FieldDesc = Ptr.getFieldDesc();1713FieldDesc->isCompositeArray()) {1714assert(Ptr.getLifetime() == Lifetime::Started);1715for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)1716startLifetimeRecurse(Ptr.atIndex(I).narrow());1717return;1718}17191720Ptr.startLifetime();1721}17221723bool StartLifetime(InterpState &S, CodePtr OpPC) {1724const auto &Ptr = S.Stk.peek<Pointer>();1725if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))1726return false;1727startLifetimeRecurse(Ptr.narrow());1728return true;1729}17301731// FIXME: It might be better to the recursing as part of the generated code for1732// a destructor?1733static void endLifetimeRecurse(const Pointer &Ptr) {1734if (const Record *R = Ptr.getRecord()) {1735Ptr.endLifetime();1736for (const Record::Field &Fi : R->fields())1737endLifetimeRecurse(Ptr.atField(Fi.Offset));1738return;1739}17401741if (const Descriptor *FieldDesc = Ptr.getFieldDesc();1742FieldDesc->isCompositeArray()) {1743// No endLifetime() for array roots.1744assert(Ptr.getLifetime() == Lifetime::Started);1745for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)1746endLifetimeRecurse(Ptr.atIndex(I).narrow());1747return;1748}17491750Ptr.endLifetime();1751}17521753/// Ends the lifetime of the peek'd pointer.1754bool EndLifetime(InterpState &S, CodePtr OpPC) {1755const auto &Ptr = S.Stk.peek<Pointer>();1756if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))1757return false;1758endLifetimeRecurse(Ptr.narrow());1759return true;1760}17611762/// Ends the lifetime of the pop'd pointer.1763bool EndLifetimePop(InterpState &S, CodePtr OpPC) {1764const auto &Ptr = S.Stk.pop<Pointer>();1765if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))1766return false;1767endLifetimeRecurse(Ptr.narrow());1768return true;1769}17701771bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,1772std::optional<uint64_t> ArraySize) {1773const Pointer &Ptr = S.Stk.peek<Pointer>();17741775// Similar to CheckStore(), but with the additional CheckTemporary() call and1776// the AccessKinds are different.1777if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))1778return false;1779if (!CheckLive(S, OpPC, Ptr, AK_Construct))1780return false;1781if (!CheckDummy(S, OpPC, Ptr, AK_Construct))1782return false;17831784// CheckLifetime for this and all base pointers.1785for (Pointer P = Ptr;;) {1786if (!CheckLifetime(S, OpPC, P, AK_Construct))1787return false;17881789if (P.isRoot())1790break;1791P = P.getBase();1792}1793if (!CheckExtern(S, OpPC, Ptr))1794return false;1795if (!CheckRange(S, OpPC, Ptr, AK_Construct))1796return false;1797if (!CheckGlobal(S, OpPC, Ptr))1798return false;1799if (!CheckConst(S, OpPC, Ptr))1800return false;1801if (!S.inConstantContext() && isConstexprUnknown(Ptr))1802return false;18031804if (!InvalidNewDeleteExpr(S, OpPC, E))1805return false;18061807const auto *NewExpr = cast<CXXNewExpr>(E);1808QualType StorageType = Ptr.getFieldDesc()->getDataType(S.getASTContext());1809const ASTContext &ASTCtx = S.getASTContext();1810QualType AllocType;1811if (ArraySize) {1812AllocType = ASTCtx.getConstantArrayType(1813NewExpr->getAllocatedType(),1814APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,1815ArraySizeModifier::Normal, 0);1816} else {1817AllocType = NewExpr->getAllocatedType();1818}18191820unsigned StorageSize = 1;1821unsigned AllocSize = 1;1822if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))1823AllocSize = CAT->getZExtSize();1824if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))1825StorageSize = CAT->getZExtSize();18261827if (AllocSize > StorageSize ||1828!ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),1829ASTCtx.getBaseElementType(StorageType))) {1830S.FFDiag(S.Current->getLocation(OpPC),1831diag::note_constexpr_placement_new_wrong_type)1832<< StorageType << AllocType;1833return false;1834}18351836// Can't activate fields in a union, unless the direct base is the union.1837if (Ptr.inUnion() && !Ptr.isActive() && !Ptr.getBase().getRecord()->isUnion())1838return CheckActive(S, OpPC, Ptr, AK_Construct);18391840return true;1841}18421843bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {1844assert(E);18451846if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {1847const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();18481849if (NewExpr->getNumPlacementArgs() > 0) {1850// This is allowed pre-C++26, but only an std function.1851if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction())1852return true;1853S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)1854<< /*C++26 feature*/ 1 << E->getSourceRange();1855} else if (1856!OperatorNew1857->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {1858S.FFDiag(S.Current->getSource(OpPC),1859diag::note_constexpr_new_non_replaceable)1860<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;1861return false;1862} else if (!S.getLangOpts().CPlusPlus26 &&1863NewExpr->getNumPlacementArgs() == 1 &&1864!OperatorNew->isReservedGlobalPlacementOperator()) {1865if (!S.getLangOpts().CPlusPlus26) {1866S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)1867<< /*Unsupported*/ 0 << E->getSourceRange();1868return false;1869}1870return true;1871}1872} else {1873const auto *DeleteExpr = cast<CXXDeleteExpr>(E);1874const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();1875if (!OperatorDelete1876->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {1877S.FFDiag(S.Current->getSource(OpPC),1878diag::note_constexpr_new_non_replaceable)1879<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;1880return false;1881}1882}18831884return false;1885}18861887bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,1888const FixedPoint &FP) {1889const Expr *E = S.Current->getExpr(OpPC);1890if (S.checkingForUndefinedBehavior()) {1891S.getASTContext().getDiagnostics().Report(1892E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)1893<< FP.toDiagnosticString(S.getASTContext()) << E->getType();1894}1895S.CCEDiag(E, diag::note_constexpr_overflow)1896<< FP.toDiagnosticString(S.getASTContext()) << E->getType();1897return S.noteUndefinedBehavior();1898}18991900bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index) {1901const SourceInfo &Loc = S.Current->getSource(OpPC);1902S.FFDiag(Loc,1903diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)1904<< Index;1905return false;1906}19071908bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,1909const Pointer &Ptr, unsigned BitWidth) {1910if (Ptr.isDummy())1911return false;1912if (Ptr.isFunctionPointer())1913return true;19141915const SourceInfo &E = S.Current->getSource(OpPC);1916S.CCEDiag(E, diag::note_constexpr_invalid_cast)1917<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);19181919if (Ptr.isBlockPointer() && !Ptr.isZero()) {1920// Only allow based lvalue casts if they are lossless.1921if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) !=1922BitWidth)1923return Invalid(S, OpPC);1924}1925return true;1926}19271928bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {1929const Pointer &Ptr = S.Stk.pop<Pointer>();19301931if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))1932return false;19331934auto Result = S.allocAP<IntegralAP<false>>(BitWidth);1935Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));19361937S.Stk.push<IntegralAP<false>>(Result);1938return true;1939}19401941bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {1942const Pointer &Ptr = S.Stk.pop<Pointer>();19431944if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))1945return false;19461947auto Result = S.allocAP<IntegralAP<true>>(BitWidth);1948Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));19491950S.Stk.push<IntegralAP<true>>(Result);1951return true;1952}19531954bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,1955bool TargetIsUCharOrByte) {1956// This is always fine.1957if (!HasIndeterminateBits)1958return true;19591960// Indeterminate bits can only be bitcast to unsigned char or std::byte.1961if (TargetIsUCharOrByte)1962return true;19631964const Expr *E = S.Current->getExpr(OpPC);1965QualType ExprType = E->getType();1966S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)1967<< ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();1968return false;1969}19701971bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,1972const Type *TypeInfoType) {1973S.Stk.push<Pointer>(TypePtr, TypeInfoType);1974return true;1975}19761977bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {1978const auto &P = S.Stk.pop<Pointer>();19791980if (!P.isBlockPointer())1981return false;19821983// Pick the most-derived type.1984const Type *T = P.getDeclPtr().getType().getTypePtr();1985// ... unless we're currently constructing this object.1986// FIXME: We have a similar check to this in more places.1987if (S.Current->getFunction()) {1988for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {1989if (const Function *Func = Frame->getFunction();1990Func && (Func->isConstructor() || Func->isDestructor()) &&1991P.block() == Frame->getThis().block()) {1992T = Func->getParentDecl()->getTypeForDecl();1993break;1994}1995}1996}19971998S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(),1999TypeInfoType);2000return true;2001}20022003bool DiagTypeid(InterpState &S, CodePtr OpPC) {2004const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));2005S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)2006<< E->getExprOperand()->getType()2007<< E->getExprOperand()->getSourceRange();2008return false;2009}20102011bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,2012const Pointer &RHS) {2013unsigned LHSOffset = LHS.getIndex();2014unsigned RHSOffset = RHS.getIndex();2015unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();2016unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();20172018StringRef LHSStr((const char *)LHS.atIndex(0).getRawAddress(), LHSLength);2019StringRef RHSStr((const char *)RHS.atIndex(0).getRawAddress(), RHSLength);2020int32_t IndexDiff = RHSOffset - LHSOffset;2021if (IndexDiff < 0) {2022if (static_cast<int32_t>(LHSLength) < -IndexDiff)2023return false;2024LHSStr = LHSStr.drop_front(-IndexDiff);2025} else {2026if (static_cast<int32_t>(RHSLength) < IndexDiff)2027return false;2028RHSStr = RHSStr.drop_front(IndexDiff);2029}20302031unsigned ShorterCharWidth;2032StringRef Shorter;2033StringRef Longer;2034if (LHSLength < RHSLength) {2035ShorterCharWidth = LHS.elemSize();2036Shorter = LHSStr;2037Longer = RHSStr;2038} else {2039ShorterCharWidth = RHS.elemSize();2040Shorter = RHSStr;2041Longer = LHSStr;2042}20432044// The null terminator isn't included in the string data, so check for it2045// manually. If the longer string doesn't have a null terminator where the2046// shorter string ends, they aren't potentially overlapping.2047for (unsigned NullByte : llvm::seq(ShorterCharWidth)) {2048if (Shorter.size() + NullByte >= Longer.size())2049break;2050if (Longer[Shorter.size() + NullByte])2051return false;2052}2053return Shorter == Longer.take_front(Shorter.size());2054}20552056static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr,2057PrimType T) {20582059if (T == PT_IntAPS) {2060auto &Val = Ptr.deref<IntegralAP<true>>();2061if (!Val.singleWord()) {2062uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2063Val.take(NewMemory);2064}2065} else if (T == PT_IntAP) {2066auto &Val = Ptr.deref<IntegralAP<false>>();2067if (!Val.singleWord()) {2068uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2069Val.take(NewMemory);2070}2071} else if (T == PT_Float) {2072auto &Val = Ptr.deref<Floating>();2073if (!Val.singleWord()) {2074uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2075Val.take(NewMemory);2076}2077}2078}20792080template <typename T>2081static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr) {2082assert(needsAlloc<T>());2083auto &Val = Ptr.deref<T>();2084if (!Val.singleWord()) {2085uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2086Val.take(NewMemory);2087}2088}20892090static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) {2091if (const Record *R = Ptr.getRecord()) {2092for (const Record::Field &Fi : R->fields()) {2093if (Fi.Desc->isPrimitive()) {2094TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), {2095copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));2096});2097copyPrimitiveMemory(S, Ptr.atField(Fi.Offset), Fi.Desc->getPrimType());2098} else2099finishGlobalRecurse(S, Ptr.atField(Fi.Offset));2100}2101return;2102}21032104if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {2105unsigned NumElems = D->getNumElems();2106if (NumElems == 0)2107return;21082109if (D->isPrimitiveArray()) {2110PrimType PT = D->getPrimType();2111if (!needsAlloc(PT))2112return;2113assert(NumElems >= 1);2114const Pointer EP = Ptr.atIndex(0);2115bool AllSingleWord = true;2116TYPE_SWITCH_ALLOC(PT, {2117if (!EP.deref<T>().singleWord()) {2118copyPrimitiveMemory<T>(S, EP);2119AllSingleWord = false;2120}2121});2122if (AllSingleWord)2123return;2124for (unsigned I = 1; I != D->getNumElems(); ++I) {2125const Pointer EP = Ptr.atIndex(I);2126copyPrimitiveMemory(S, EP, PT);2127}2128} else {2129assert(D->isCompositeArray());2130for (unsigned I = 0; I != D->getNumElems(); ++I) {2131const Pointer EP = Ptr.atIndex(I).narrow();2132finishGlobalRecurse(S, EP);2133}2134}2135}2136}21372138bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {2139const Pointer &Ptr = S.Stk.pop<Pointer>();21402141finishGlobalRecurse(S, Ptr);2142if (Ptr.canBeInitialized()) {2143Ptr.initialize();2144Ptr.activate();2145}21462147return true;2148}21492150// https://github.com/llvm/llvm-project/issues/1025132151#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)2152#pragma optimize("", off)2153#endif2154bool Interpret(InterpState &S) {2155// The current stack frame when we started Interpret().2156// This is being used by the ops to determine wheter2157// to return from this function and thus terminate2158// interpretation.2159const InterpFrame *StartFrame = S.Current;2160assert(!S.Current->isRoot());2161CodePtr PC = S.Current->getPC();21622163// Empty program.2164if (!PC)2165return true;21662167for (;;) {2168auto Op = PC.read<Opcode>();2169CodePtr OpPC = PC;21702171switch (Op) {2172#define GET_INTERP2173#include "Opcodes.inc"2174#undef GET_INTERP2175}2176}2177}2178// https://github.com/llvm/llvm-project/issues/1025132179#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)2180#pragma optimize("", on)2181#endif21822183} // namespace interp2184} // namespace clang218521862187