Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp
35291 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 "Function.h"10#include "InterpFrame.h"11#include "InterpShared.h"12#include "InterpStack.h"13#include "Opcode.h"14#include "PrimType.h"15#include "Program.h"16#include "State.h"17#include "clang/AST/ASTContext.h"18#include "clang/AST/ASTDiagnostic.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 "llvm/ADT/APSInt.h"24#include "llvm/ADT/StringExtras.h"25#include <limits>26#include <vector>2728using namespace clang;2930using namespace clang;31using namespace clang::interp;3233static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {34llvm::report_fatal_error("Interpreter cannot return values");35}3637//===----------------------------------------------------------------------===//38// Jmp, Jt, Jf39//===----------------------------------------------------------------------===//4041static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {42PC += Offset;43return true;44}4546static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {47if (S.Stk.pop<bool>()) {48PC += Offset;49}50return true;51}5253static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {54if (!S.Stk.pop<bool>()) {55PC += Offset;56}57return true;58}5960static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,61const ValueDecl *VD) {62const SourceInfo &E = S.Current->getSource(OpPC);63S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;64S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();65}6667static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,68const ValueDecl *VD);69static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,70const ValueDecl *D) {71const SourceInfo &E = S.Current->getSource(OpPC);7273if (isa<ParmVarDecl>(D)) {74if (S.getLangOpts().CPlusPlus11) {75S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;76S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();77} else {78S.FFDiag(E);79}80return false;81}8283if (!D->getType().isConstQualified())84diagnoseNonConstVariable(S, OpPC, D);85else if (const auto *VD = dyn_cast<VarDecl>(D);86VD && !VD->getAnyInitializer())87diagnoseMissingInitializer(S, OpPC, VD);8889return false;90}9192static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,93const ValueDecl *VD) {94if (!S.getLangOpts().CPlusPlus)95return;9697const SourceInfo &Loc = S.Current->getSource(OpPC);98if (const auto *VarD = dyn_cast<VarDecl>(VD);99VarD && VarD->getType().isConstQualified() &&100!VarD->getAnyInitializer()) {101diagnoseMissingInitializer(S, OpPC, VD);102return;103}104105// Rather random, but this is to match the diagnostic output of the current106// interpreter.107if (isa<ObjCIvarDecl>(VD))108return;109110if (VD->getType()->isIntegralOrEnumerationType()) {111S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;112S.Note(VD->getLocation(), diag::note_declared_at);113return;114}115116S.FFDiag(Loc,117S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr118: diag::note_constexpr_ltor_non_integral,1191)120<< VD << VD->getType();121S.Note(VD->getLocation(), diag::note_declared_at);122}123124static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,125AccessKinds AK) {126if (Ptr.isActive())127return true;128129// Get the inactive field descriptor.130const FieldDecl *InactiveField = Ptr.getField();131132// Walk up the pointer chain to find the union which is not active.133Pointer U = Ptr.getBase();134while (!U.isActive()) {135U = U.getBase();136}137138// Find the active field of the union.139const Record *R = U.getRecord();140assert(R && R->isUnion() && "Not a union");141const FieldDecl *ActiveField = nullptr;142for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {143const Pointer &Field = U.atField(R->getField(I)->Offset);144if (Field.isActive()) {145ActiveField = Field.getField();146break;147}148}149150const SourceInfo &Loc = S.Current->getSource(OpPC);151S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)152<< AK << InactiveField << !ActiveField << ActiveField;153return false;154}155156static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,157AccessKinds AK) {158if (auto ID = Ptr.getDeclID()) {159if (!Ptr.isStaticTemporary())160return true;161162if (Ptr.getDeclDesc()->getType().isConstQualified())163return true;164165if (S.P.getCurrentDecl() == ID)166return true;167168const SourceInfo &E = S.Current->getSource(OpPC);169S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;170S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);171return false;172}173return true;174}175176static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {177if (auto ID = Ptr.getDeclID()) {178if (!Ptr.isStatic())179return true;180181if (S.P.getCurrentDecl() == ID)182return true;183184S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);185return false;186}187return true;188}189190namespace clang {191namespace interp {192static void popArg(InterpState &S, const Expr *Arg) {193PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);194TYPE_SWITCH(Ty, S.Stk.discard<T>());195}196197void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {198assert(S.Current);199const Function *CurFunc = S.Current->getFunction();200assert(CurFunc);201202if (CurFunc->isUnevaluatedBuiltin())203return;204205// Some builtin functions require us to only look at the call site, since206// the classified parameter types do not match.207if (CurFunc->isBuiltin()) {208const auto *CE =209cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));210for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {211const Expr *A = CE->getArg(I);212popArg(S, A);213}214return;215}216217if (S.Current->Caller && CurFunc->isVariadic()) {218// CallExpr we're look for is at the return PC of the current function, i.e.219// in the caller.220// This code path should be executed very rarely.221unsigned NumVarArgs;222const Expr *const *Args = nullptr;223unsigned NumArgs = 0;224const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());225if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {226Args = CE->getArgs();227NumArgs = CE->getNumArgs();228} else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {229Args = CE->getArgs();230NumArgs = CE->getNumArgs();231} else232assert(false && "Can't get arguments from that expression type");233234assert(NumArgs >= CurFunc->getNumWrittenParams());235NumVarArgs = NumArgs - CurFunc->getNumWrittenParams();236for (unsigned I = 0; I != NumVarArgs; ++I) {237const Expr *A = Args[NumArgs - 1 - I];238popArg(S, A);239}240}241242// And in any case, remove the fixed parameters (the non-variadic ones)243// at the end.244S.Current->popArgs();245}246247bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {248if (!Ptr.isExtern())249return true;250251if (Ptr.isInitialized() ||252(Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))253return true;254255if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {256const auto *VD = Ptr.getDeclDesc()->asValueDecl();257diagnoseNonConstVariable(S, OpPC, VD);258}259return false;260}261262bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {263if (!Ptr.isUnknownSizeArray())264return true;265const SourceInfo &E = S.Current->getSource(OpPC);266S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);267return false;268}269270bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,271AccessKinds AK) {272if (Ptr.isZero()) {273const auto &Src = S.Current->getSource(OpPC);274275if (Ptr.isField())276S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;277else278S.FFDiag(Src, diag::note_constexpr_access_null) << AK;279280return false;281}282283if (!Ptr.isLive()) {284const auto &Src = S.Current->getSource(OpPC);285bool IsTemp = Ptr.isTemporary();286287S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;288289if (IsTemp)290S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);291else292S.Note(Ptr.getDeclLoc(), diag::note_declared_at);293294return false;295}296297return true;298}299300bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {301assert(Desc);302303auto IsConstType = [&S](const VarDecl *VD) -> bool {304if (VD->isConstexpr())305return true;306307QualType T = VD->getType();308if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)309return (T->isSignedIntegerOrEnumerationType() ||310T->isUnsignedIntegerOrEnumerationType()) &&311T.isConstQualified();312313if (T.isConstQualified())314return true;315316if (const auto *RT = T->getAs<ReferenceType>())317return RT->getPointeeType().isConstQualified();318319if (const auto *PT = T->getAs<PointerType>())320return PT->getPointeeType().isConstQualified();321322return false;323};324325if (const auto *D = Desc->asVarDecl();326D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) {327diagnoseNonConstVariable(S, OpPC, D);328return S.inConstantContext();329}330331return true;332}333334static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {335if (Ptr.isIntegralPointer())336return true;337return CheckConstant(S, OpPC, Ptr.getDeclDesc());338}339340bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,341CheckSubobjectKind CSK) {342if (!Ptr.isZero())343return true;344const SourceInfo &Loc = S.Current->getSource(OpPC);345S.FFDiag(Loc, diag::note_constexpr_null_subobject)346<< CSK << S.Current->getRange(OpPC);347348return false;349}350351bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,352AccessKinds AK) {353if (!Ptr.isOnePastEnd())354return true;355const SourceInfo &Loc = S.Current->getSource(OpPC);356S.FFDiag(Loc, diag::note_constexpr_access_past_end)357<< AK << S.Current->getRange(OpPC);358return false;359}360361bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,362CheckSubobjectKind CSK) {363if (!Ptr.isElementPastEnd())364return true;365const SourceInfo &Loc = S.Current->getSource(OpPC);366S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)367<< CSK << S.Current->getRange(OpPC);368return false;369}370371bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,372CheckSubobjectKind CSK) {373if (!Ptr.isOnePastEnd())374return true;375376const SourceInfo &Loc = S.Current->getSource(OpPC);377S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)378<< CSK << S.Current->getRange(OpPC);379return false;380}381382bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,383uint32_t Offset) {384uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();385uint32_t PtrOffset = Ptr.getByteOffset();386387// We subtract Offset from PtrOffset. The result must be at least388// MinOffset.389if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)390return true;391392const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));393QualType TargetQT = E->getType()->getPointeeType();394QualType MostDerivedQT = Ptr.getDeclPtr().getType();395396S.CCEDiag(E, diag::note_constexpr_invalid_downcast)397<< MostDerivedQT << TargetQT;398399return false;400}401402bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {403assert(Ptr.isLive() && "Pointer is not live");404if (!Ptr.isConst() || Ptr.isMutable())405return true;406407// The This pointer is writable in constructors and destructors,408// even if isConst() returns true.409// TODO(perf): We could be hitting this code path quite a lot in complex410// constructors. Is there a better way to do this?411if (S.Current->getFunction()) {412for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {413if (const Function *Func = Frame->getFunction();414Func && (Func->isConstructor() || Func->isDestructor()) &&415Ptr.block() == Frame->getThis().block()) {416return true;417}418}419}420421if (!Ptr.isBlockPointer())422return false;423424const QualType Ty = Ptr.getType();425const SourceInfo &Loc = S.Current->getSource(OpPC);426S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;427return false;428}429430bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {431assert(Ptr.isLive() && "Pointer is not live");432if (!Ptr.isMutable())433return true;434435// In C++14 onwards, it is permitted to read a mutable member whose436// lifetime began within the evaluation.437if (S.getLangOpts().CPlusPlus14 &&438Ptr.block()->getEvalID() == S.Ctx.getEvalID())439return true;440441const SourceInfo &Loc = S.Current->getSource(OpPC);442const FieldDecl *Field = Ptr.getField();443S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;444S.Note(Field->getLocation(), diag::note_declared_at);445return false;446}447448bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,449AccessKinds AK) {450assert(Ptr.isLive());451452// FIXME: This check here might be kinda expensive. Maybe it would be better453// to have another field in InlineDescriptor for this?454if (!Ptr.isBlockPointer())455return true;456457QualType PtrType = Ptr.getType();458if (!PtrType.isVolatileQualified())459return true;460461const SourceInfo &Loc = S.Current->getSource(OpPC);462if (S.getLangOpts().CPlusPlus)463S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;464else465S.FFDiag(Loc);466return false;467}468469bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,470AccessKinds AK) {471assert(Ptr.isLive());472473if (Ptr.isInitialized())474return true;475476if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();477VD && VD->hasGlobalStorage()) {478const SourceInfo &Loc = S.Current->getSource(OpPC);479if (VD->getAnyInitializer()) {480S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;481S.Note(VD->getLocation(), diag::note_declared_at);482} else {483diagnoseMissingInitializer(S, OpPC, VD);484}485return false;486}487488if (!S.checkingPotentialConstantExpression()) {489S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)490<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);491}492return false;493}494495bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {496if (Ptr.isInitialized())497return true;498499assert(S.getLangOpts().CPlusPlus);500const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());501if ((!VD->hasConstantInitialization() &&502VD->mightBeUsableInConstantExpressions(S.getCtx())) ||503(S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&504!VD->hasICEInitializer(S.getCtx()))) {505const SourceInfo &Loc = S.Current->getSource(OpPC);506S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;507S.Note(VD->getLocation(), diag::note_declared_at);508}509return false;510}511512bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,513AccessKinds AK) {514if (!CheckLive(S, OpPC, Ptr, AK))515return false;516if (!CheckConstant(S, OpPC, Ptr))517return false;518519if (!CheckDummy(S, OpPC, Ptr, AK))520return false;521if (!CheckExtern(S, OpPC, Ptr))522return false;523if (!CheckRange(S, OpPC, Ptr, AK))524return false;525if (!CheckActive(S, OpPC, Ptr, AK))526return false;527if (!CheckInitialized(S, OpPC, Ptr, AK))528return false;529if (!CheckTemporary(S, OpPC, Ptr, AK))530return false;531if (!CheckMutable(S, OpPC, Ptr))532return false;533if (!CheckVolatile(S, OpPC, Ptr, AK))534return false;535return true;536}537538bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {539if (!CheckLive(S, OpPC, Ptr, AK_Assign))540return false;541if (!CheckDummy(S, OpPC, Ptr, AK_Assign))542return false;543if (!CheckExtern(S, OpPC, Ptr))544return false;545if (!CheckRange(S, OpPC, Ptr, AK_Assign))546return false;547if (!CheckGlobal(S, OpPC, Ptr))548return false;549if (!CheckConst(S, OpPC, Ptr))550return false;551return true;552}553554bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {555if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))556return false;557if (!Ptr.isDummy()) {558if (!CheckExtern(S, OpPC, Ptr))559return false;560if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))561return false;562}563return true;564}565566bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {567if (!CheckLive(S, OpPC, Ptr, AK_Assign))568return false;569if (!CheckRange(S, OpPC, Ptr, AK_Assign))570return false;571return true;572}573574bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {575576if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {577const SourceLocation &Loc = S.Current->getLocation(OpPC);578S.CCEDiag(Loc, diag::note_constexpr_virtual_call);579return false;580}581582if (F->isConstexpr() && F->hasBody() &&583(F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>()))584return true;585586// Implicitly constexpr.587if (F->isLambdaStaticInvoker())588return true;589590const SourceLocation &Loc = S.Current->getLocation(OpPC);591if (S.getLangOpts().CPlusPlus11) {592const FunctionDecl *DiagDecl = F->getDecl();593594// Invalid decls have been diagnosed before.595if (DiagDecl->isInvalidDecl())596return false;597598// If this function is not constexpr because it is an inherited599// non-constexpr constructor, diagnose that directly.600const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);601if (CD && CD->isInheritingConstructor()) {602const auto *Inherited = CD->getInheritedConstructor().getConstructor();603if (!Inherited->isConstexpr())604DiagDecl = CD = Inherited;605}606607// FIXME: If DiagDecl is an implicitly-declared special member function608// or an inheriting constructor, we should be much more explicit about why609// it's not constexpr.610if (CD && CD->isInheritingConstructor()) {611S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)612<< CD->getInheritedConstructor().getConstructor()->getParent();613S.Note(DiagDecl->getLocation(), diag::note_declared_at);614} else {615// Don't emit anything if the function isn't defined and we're checking616// for a constant expression. It might be defined at the point we're617// actually calling it.618bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;619if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&620S.checkingPotentialConstantExpression())621return false;622623// If the declaration is defined, declared 'constexpr' _and_ has a body,624// the below diagnostic doesn't add anything useful.625if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&626DiagDecl->hasBody())627return false;628629S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)630<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;631S.Note(DiagDecl->getLocation(), diag::note_declared_at);632}633} else {634S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);635}636637return false;638}639640bool CheckCallDepth(InterpState &S, CodePtr OpPC) {641if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {642S.FFDiag(S.Current->getSource(OpPC),643diag::note_constexpr_depth_limit_exceeded)644<< S.getLangOpts().ConstexprCallDepth;645return false;646}647648return true;649}650651bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {652if (!This.isZero())653return true;654655const SourceInfo &Loc = S.Current->getSource(OpPC);656657bool IsImplicit = false;658if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))659IsImplicit = E->isImplicit();660661if (S.getLangOpts().CPlusPlus11)662S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;663else664S.FFDiag(Loc);665666return false;667}668669bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {670if (!MD->isPureVirtual())671return true;672const SourceInfo &E = S.Current->getSource(OpPC);673S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;674S.Note(MD->getLocation(), diag::note_declared_at);675return false;676}677678bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,679APFloat::opStatus Status) {680const SourceInfo &E = S.Current->getSource(OpPC);681682// [expr.pre]p4:683// If during the evaluation of an expression, the result is not684// mathematically defined [...], the behavior is undefined.685// FIXME: C++ rules require us to not conform to IEEE 754 here.686if (Result.isNan()) {687S.CCEDiag(E, diag::note_constexpr_float_arithmetic)688<< /*NaN=*/true << S.Current->getRange(OpPC);689return S.noteUndefinedBehavior();690}691692// In a constant context, assume that any dynamic rounding mode or FP693// exception state matches the default floating-point environment.694if (S.inConstantContext())695return true;696697FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());698699if ((Status & APFloat::opInexact) &&700FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {701// Inexact result means that it depends on rounding mode. If the requested702// mode is dynamic, the evaluation cannot be made in compile time.703S.FFDiag(E, diag::note_constexpr_dynamic_rounding);704return false;705}706707if ((Status != APFloat::opOK) &&708(FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||709FPO.getExceptionMode() != LangOptions::FPE_Ignore ||710FPO.getAllowFEnvAccess())) {711S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);712return false;713}714715if ((Status & APFloat::opStatus::opInvalidOp) &&716FPO.getExceptionMode() != LangOptions::FPE_Ignore) {717// There is no usefully definable result.718S.FFDiag(E);719return false;720}721722return true;723}724725bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {726if (S.getLangOpts().CPlusPlus20)727return true;728729const SourceInfo &E = S.Current->getSource(OpPC);730S.CCEDiag(E, diag::note_constexpr_new);731return true;732}733734bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,735bool DeleteIsArray, const Descriptor *D,736const Expr *NewExpr) {737if (NewWasArray == DeleteIsArray)738return true;739740QualType TypeToDiagnose;741// We need to shuffle things around a bit here to get a better diagnostic,742// because the expression we allocated the block for was of type int*,743// but we want to get the array size right.744if (D->isArray()) {745QualType ElemQT = D->getType()->getPointeeType();746TypeToDiagnose = S.getCtx().getConstantArrayType(747ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),748nullptr, ArraySizeModifier::Normal, 0);749} else750TypeToDiagnose = D->getType()->getPointeeType();751752const SourceInfo &E = S.Current->getSource(OpPC);753S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)754<< DeleteIsArray << 0 << TypeToDiagnose;755S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)756<< NewExpr->getSourceRange();757return false;758}759760bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,761const Pointer &Ptr) {762if (Source && isa<CXXNewExpr>(Source))763return true;764765// Whatever this is, we didn't heap allocate it.766const SourceInfo &Loc = S.Current->getSource(OpPC);767S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)768<< Ptr.toDiagnosticString(S.getCtx());769770if (Ptr.isTemporary())771S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);772else773S.Note(Ptr.getDeclLoc(), diag::note_declared_at);774return false;775}776777/// We aleady know the given DeclRefExpr is invalid for some reason,778/// now figure out why and print appropriate diagnostics.779bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {780const ValueDecl *D = DR->getDecl();781return diagnoseUnknownDecl(S, OpPC, D);782}783784bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,785AccessKinds AK) {786if (!Ptr.isDummy())787return true;788789const Descriptor *Desc = Ptr.getDeclDesc();790const ValueDecl *D = Desc->asValueDecl();791if (!D)792return false;793794if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)795return diagnoseUnknownDecl(S, OpPC, D);796797assert(AK == AK_Assign);798if (S.getLangOpts().CPlusPlus11) {799const SourceInfo &E = S.Current->getSource(OpPC);800S.FFDiag(E, diag::note_constexpr_modify_global);801}802return false;803}804805bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,806const CallExpr *CE, unsigned ArgSize) {807auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());808auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);809unsigned Offset = 0;810unsigned Index = 0;811for (const Expr *Arg : Args) {812if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {813const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);814if (ArgPtr.isZero()) {815const SourceLocation &Loc = S.Current->getLocation(OpPC);816S.CCEDiag(Loc, diag::note_non_null_attribute_failed);817return false;818}819}820821Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));822++Index;823}824return true;825}826827// FIXME: This is similar to code we already have in Compiler.cpp.828// I think it makes sense to instead add the field and base destruction stuff829// to the destructor Function itself. Then destroying a record would really830// _just_ be calling its destructor. That would also help with the diagnostic831// difference when the destructor or a field/base fails.832static bool runRecordDestructor(InterpState &S, CodePtr OpPC,833const Pointer &BasePtr,834const Descriptor *Desc) {835assert(Desc->isRecord());836const Record *R = Desc->ElemRecord;837assert(R);838839// Fields.840for (const Record::Field &Field : llvm::reverse(R->fields())) {841const Descriptor *D = Field.Desc;842if (D->isRecord()) {843if (!runRecordDestructor(S, OpPC, BasePtr.atField(Field.Offset), D))844return false;845} else if (D->isCompositeArray()) {846const Descriptor *ElemDesc = Desc->ElemDesc;847assert(ElemDesc->isRecord());848for (unsigned I = 0; I != Desc->getNumElems(); ++I) {849if (!runRecordDestructor(S, OpPC, BasePtr.atIndex(I).narrow(),850ElemDesc))851return false;852}853}854}855856// Destructor of this record.857if (const CXXDestructorDecl *Dtor = R->getDestructor();858Dtor && !Dtor->isTrivial()) {859const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);860if (!DtorFunc)861return false;862863S.Stk.push<Pointer>(BasePtr);864if (!Call(S, OpPC, DtorFunc, 0))865return false;866}867868// Bases.869for (const Record::Base &Base : llvm::reverse(R->bases())) {870if (!runRecordDestructor(S, OpPC, BasePtr.atField(Base.Offset), Base.Desc))871return false;872}873874return true;875}876877bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {878assert(B);879const Descriptor *Desc = B->getDescriptor();880881if (Desc->isPrimitive() || Desc->isPrimitiveArray())882return true;883884assert(Desc->isRecord() || Desc->isCompositeArray());885886if (Desc->isCompositeArray()) {887const Descriptor *ElemDesc = Desc->ElemDesc;888assert(ElemDesc->isRecord());889890Pointer RP(const_cast<Block *>(B));891for (unsigned I = 0; I != Desc->getNumElems(); ++I) {892if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))893return false;894}895return true;896}897898assert(Desc->isRecord());899return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);900}901902void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,903const APSInt &Value) {904llvm::APInt Min;905llvm::APInt Max;906907if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())908return;909910ED->getValueRange(Max, Min);911--Max;912913if (ED->getNumNegativeBits() &&914(Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {915const SourceLocation &Loc = S.Current->getLocation(OpPC);916S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)917<< llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()918<< ED;919} else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {920const SourceLocation &Loc = S.Current->getLocation(OpPC);921S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)922<< llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()923<< ED;924}925}926927// https://github.com/llvm/llvm-project/issues/102513928#if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)929#pragma optimize("", off)930#endif931bool Interpret(InterpState &S, APValue &Result) {932// The current stack frame when we started Interpret().933// This is being used by the ops to determine wheter934// to return from this function and thus terminate935// interpretation.936const InterpFrame *StartFrame = S.Current;937assert(!S.Current->isRoot());938CodePtr PC = S.Current->getPC();939940// Empty program.941if (!PC)942return true;943944for (;;) {945auto Op = PC.read<Opcode>();946CodePtr OpPC = PC;947948switch (Op) {949#define GET_INTERP950#include "Opcodes.inc"951#undef GET_INTERP952}953}954}955// https://github.com/llvm/llvm-project/issues/102513956#if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)957#pragma optimize("", on)958#endif959960} // namespace interp961} // namespace clang962963964