2363 lines · cpp
1//===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Interp.h"10#include "Compiler.h"11#include "Function.h"12#include "InterpFrame.h"13#include "InterpShared.h"14#include "InterpStack.h"15#include "Opcode.h"16#include "PrimType.h"17#include "Program.h"18#include "State.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/CXXInheritance.h"21#include "clang/AST/DeclObjC.h"22#include "clang/AST/Expr.h"23#include "clang/AST/ExprCXX.h"24#include "clang/Basic/DiagnosticSema.h"25#include "clang/Basic/TargetInfo.h"26#include "llvm/ADT/StringExtras.h"27 28using namespace clang;29using namespace clang::interp;30 31static bool RetValue(InterpState &S, CodePtr &Pt) {32 llvm::report_fatal_error("Interpreter cannot return values");33}34 35//===----------------------------------------------------------------------===//36// Jmp, Jt, Jf37//===----------------------------------------------------------------------===//38 39static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {40 PC += Offset;41 return true;42}43 44static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {45 if (S.Stk.pop<bool>()) {46 PC += Offset;47 }48 return true;49}50 51static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {52 if (!S.Stk.pop<bool>()) {53 PC += Offset;54 }55 return true;56}57 58// https://github.com/llvm/llvm-project/issues/10251359#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)60#pragma optimize("", off)61#endif62// FIXME: We have the large switch over all opcodes here again, and in63// Interpret().64static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) {65 [[maybe_unused]] CodePtr PCBefore = RealPC;66 size_t StackSizeBefore = S.Stk.size();67 68 auto SpeculativeInterp = [&S, RealPC]() -> bool {69 const InterpFrame *StartFrame = S.Current;70 CodePtr PC = RealPC;71 72 for (;;) {73 auto Op = PC.read<Opcode>();74 if (Op == OP_EndSpeculation)75 return true;76 CodePtr OpPC = PC;77 78 switch (Op) {79#define GET_INTERP80#include "Opcodes.inc"81#undef GET_INTERP82 }83 }84 llvm_unreachable("We didn't see an EndSpeculation op?");85 };86 87 if (SpeculativeInterp()) {88 if (PT == PT_Ptr) {89 const auto &Ptr = S.Stk.pop<Pointer>();90 assert(S.Stk.size() == StackSizeBefore);91 S.Stk.push<Integral<32, true>>(92 Integral<32, true>::from(CheckBCPResult(S, Ptr)));93 } else {94 // Pop the result from the stack and return success.95 TYPE_SWITCH(PT, S.Stk.pop<T>(););96 assert(S.Stk.size() == StackSizeBefore);97 S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1));98 }99 } else {100 if (!S.inConstantContext())101 return Invalid(S, RealPC);102 103 S.Stk.clearTo(StackSizeBefore);104 S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));105 }106 107 // RealPC should not have been modified.108 assert(*RealPC == *PCBefore);109 110 // Jump to end label. This is a little tricker than just RealPC += Offset111 // because our usual jump instructions don't have any arguments, to the offset112 // we get is a little too much and we need to subtract the size of the113 // bool and PrimType arguments again.114 int32_t ParamSize = align(sizeof(PrimType));115 assert(Offset >= ParamSize);116 RealPC += Offset - ParamSize;117 118 [[maybe_unused]] CodePtr PCCopy = RealPC;119 assert(PCCopy.read<Opcode>() == OP_EndSpeculation);120 121 return true;122}123// https://github.com/llvm/llvm-project/issues/102513124#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)125#pragma optimize("", on)126#endif127 128static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,129 const ValueDecl *VD) {130 const SourceInfo &E = S.Current->getSource(OpPC);131 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;132 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();133}134 135static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,136 const ValueDecl *VD);137static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,138 const ValueDecl *D) {139 // This function tries pretty hard to produce a good diagnostic. Just skip140 // tha if nobody will see it anyway.141 if (!S.diagnosing())142 return false;143 144 if (isa<ParmVarDecl>(D)) {145 if (D->getType()->isReferenceType()) {146 if (S.inConstantContext() && S.getLangOpts().CPlusPlus &&147 !S.getLangOpts().CPlusPlus11)148 diagnoseNonConstVariable(S, OpPC, D);149 return false;150 }151 152 const SourceInfo &Loc = S.Current->getSource(OpPC);153 if (S.getLangOpts().CPlusPlus11) {154 S.FFDiag(Loc, diag::note_constexpr_function_param_value_unknown) << D;155 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();156 } else {157 S.FFDiag(Loc);158 }159 return false;160 }161 162 if (!D->getType().isConstQualified()) {163 diagnoseNonConstVariable(S, OpPC, D);164 } else if (const auto *VD = dyn_cast<VarDecl>(D)) {165 if (!VD->getAnyInitializer()) {166 diagnoseMissingInitializer(S, OpPC, VD);167 } else {168 const SourceInfo &Loc = S.Current->getSource(OpPC);169 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;170 S.Note(VD->getLocation(), diag::note_declared_at);171 }172 }173 174 return false;175}176 177static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,178 const ValueDecl *VD) {179 if (!S.diagnosing())180 return;181 182 const SourceInfo &Loc = S.Current->getSource(OpPC);183 if (!S.getLangOpts().CPlusPlus) {184 S.FFDiag(Loc);185 return;186 }187 188 if (const auto *VarD = dyn_cast<VarDecl>(VD);189 VarD && VarD->getType().isConstQualified() &&190 !VarD->getAnyInitializer()) {191 diagnoseMissingInitializer(S, OpPC, VD);192 return;193 }194 195 // Rather random, but this is to match the diagnostic output of the current196 // interpreter.197 if (isa<ObjCIvarDecl>(VD))198 return;199 200 if (VD->getType()->isIntegralOrEnumerationType()) {201 S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;202 S.Note(VD->getLocation(), diag::note_declared_at);203 return;204 }205 206 S.FFDiag(Loc,207 S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr208 : diag::note_constexpr_ltor_non_integral,209 1)210 << VD << VD->getType();211 S.Note(VD->getLocation(), diag::note_declared_at);212}213 214static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,215 AccessKinds AK) {216 if (B->getDeclID()) {217 if (!(B->isStatic() && B->isTemporary()))218 return true;219 220 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(221 B->getDescriptor()->asExpr());222 if (!MTE)223 return true;224 225 // FIXME(perf): Since we do this check on every Load from a static226 // temporary, it might make sense to cache the value of the227 // isUsableInConstantExpressions call.228 if (B->getEvalID() != S.Ctx.getEvalID() &&229 !MTE->isUsableInConstantExpressions(S.getASTContext())) {230 const SourceInfo &E = S.Current->getSource(OpPC);231 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;232 S.Note(B->getDescriptor()->getLocation(),233 diag::note_constexpr_temporary_here);234 return false;235 }236 }237 return true;238}239 240static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {241 if (auto ID = Ptr.getDeclID()) {242 if (!Ptr.isStatic())243 return true;244 245 if (S.P.getCurrentDecl() == ID)246 return true;247 248 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);249 return false;250 }251 return true;252}253 254namespace clang {255namespace interp {256static void popArg(InterpState &S, const Expr *Arg) {257 PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);258 TYPE_SWITCH(Ty, S.Stk.discard<T>());259}260 261void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,262 const Function *Func) {263 assert(S.Current);264 assert(Func);265 266 if (S.Current->Caller && Func->isVariadic()) {267 // CallExpr we're look for is at the return PC of the current function, i.e.268 // in the caller.269 // This code path should be executed very rarely.270 unsigned NumVarArgs;271 const Expr *const *Args = nullptr;272 unsigned NumArgs = 0;273 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());274 if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {275 Args = CE->getArgs();276 NumArgs = CE->getNumArgs();277 } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {278 Args = CE->getArgs();279 NumArgs = CE->getNumArgs();280 } else281 assert(false && "Can't get arguments from that expression type");282 283 assert(NumArgs >= Func->getNumWrittenParams());284 NumVarArgs = NumArgs - (Func->getNumWrittenParams() +285 isa<CXXOperatorCallExpr>(CallSite));286 for (unsigned I = 0; I != NumVarArgs; ++I) {287 const Expr *A = Args[NumArgs - 1 - I];288 popArg(S, A);289 }290 }291 292 // And in any case, remove the fixed parameters (the non-variadic ones)293 // at the end.294 for (PrimType Ty : Func->args_reverse())295 TYPE_SWITCH(Ty, S.Stk.discard<T>());296}297 298bool isConstexprUnknown(const Pointer &P) {299 if (!P.isBlockPointer())300 return false;301 302 if (P.isDummy())303 return isa_and_nonnull<ParmVarDecl>(P.getDeclDesc()->asValueDecl());304 305 return P.getDeclDesc()->IsConstexprUnknown;306}307 308bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {309 if (Ptr.isDummy())310 return false;311 if (Ptr.isZero())312 return true;313 if (Ptr.isFunctionPointer())314 return false;315 if (Ptr.isIntegralPointer())316 return true;317 if (Ptr.isTypeidPointer())318 return true;319 320 if (Ptr.getType()->isAnyComplexType())321 return true;322 323 if (const Expr *Base = Ptr.getDeclDesc()->asExpr())324 return isa<StringLiteral>(Base) && Ptr.getIndex() == 0;325 return false;326}327 328bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,329 AccessKinds AK) {330 if (Ptr.isActive())331 return true;332 333 assert(Ptr.inUnion());334 335 Pointer U = Ptr.getBase();336 Pointer C = Ptr;337 while (!U.isRoot() && !U.isActive()) {338 // A little arbitrary, but this is what the current interpreter does.339 // See the AnonymousUnion test in test/AST/ByteCode/unions.cpp.340 // GCC's output is more similar to what we would get without341 // this condition.342 if (U.getRecord() && U.getRecord()->isAnonymousUnion())343 break;344 345 C = U;346 U = U.getBase();347 }348 assert(C.isField());349 350 // Consider:351 // union U {352 // struct {353 // int x;354 // int y;355 // } a;356 // }357 //358 // When activating x, we will also activate a. If we now try to read359 // from y, we will get to CheckActive, because y is not active. In that360 // case, our U will be a (not a union). We return here and let later code361 // handle this.362 if (!U.getFieldDesc()->isUnion())363 return true;364 365 // Get the inactive field descriptor.366 assert(!C.isActive());367 const FieldDecl *InactiveField = C.getField();368 assert(InactiveField);369 370 // Find the active field of the union.371 const Record *R = U.getRecord();372 assert(R && R->isUnion() && "Not a union");373 374 const FieldDecl *ActiveField = nullptr;375 for (const Record::Field &F : R->fields()) {376 const Pointer &Field = U.atField(F.Offset);377 if (Field.isActive()) {378 ActiveField = Field.getField();379 break;380 }381 }382 383 const SourceInfo &Loc = S.Current->getSource(OpPC);384 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)385 << AK << InactiveField << !ActiveField << ActiveField;386 return false;387}388 389bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {390 if (!Ptr.isExtern())391 return true;392 393 if (Ptr.isInitialized() ||394 (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))395 return true;396 397 if (S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus &&398 Ptr.isConst())399 return false;400 401 const auto *VD = Ptr.getDeclDesc()->asValueDecl();402 diagnoseNonConstVariable(S, OpPC, VD);403 return false;404}405 406bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {407 if (!Ptr.isUnknownSizeArray())408 return true;409 const SourceInfo &E = S.Current->getSource(OpPC);410 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);411 return false;412}413 414bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,415 AccessKinds AK) {416 if (Ptr.isZero()) {417 const auto &Src = S.Current->getSource(OpPC);418 419 if (Ptr.isField())420 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;421 else422 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;423 424 return false;425 }426 427 if (!Ptr.isLive()) {428 const auto &Src = S.Current->getSource(OpPC);429 430 if (Ptr.isDynamic()) {431 S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;432 } else if (!S.checkingPotentialConstantExpression()) {433 bool IsTemp = Ptr.isTemporary();434 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;435 436 if (IsTemp)437 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);438 else439 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);440 }441 442 return false;443 }444 445 return true;446}447 448bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {449 assert(Desc);450 451 const auto *D = Desc->asVarDecl();452 if (!D || D == S.EvaluatingDecl || D->isConstexpr())453 return true;454 455 // If we're evaluating the initializer for a constexpr variable in C23, we may456 // only read other contexpr variables. Abort here since this one isn't457 // constexpr.458 if (const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);459 VD && VD->isConstexpr() && S.getLangOpts().C23)460 return Invalid(S, OpPC);461 462 QualType T = D->getType();463 bool IsConstant = T.isConstant(S.getASTContext());464 if (T->isIntegralOrEnumerationType()) {465 if (!IsConstant) {466 diagnoseNonConstVariable(S, OpPC, D);467 return false;468 }469 return true;470 }471 472 if (IsConstant) {473 if (S.getLangOpts().CPlusPlus) {474 S.CCEDiag(S.Current->getLocation(OpPC),475 S.getLangOpts().CPlusPlus11476 ? diag::note_constexpr_ltor_non_constexpr477 : diag::note_constexpr_ltor_non_integral,478 1)479 << D << T;480 S.Note(D->getLocation(), diag::note_declared_at);481 } else {482 S.CCEDiag(S.Current->getLocation(OpPC));483 }484 return true;485 }486 487 if (T->isPointerOrReferenceType()) {488 if (!T->getPointeeType().isConstant(S.getASTContext()) ||489 !S.getLangOpts().CPlusPlus11) {490 diagnoseNonConstVariable(S, OpPC, D);491 return false;492 }493 return true;494 }495 496 diagnoseNonConstVariable(S, OpPC, D);497 return false;498}499 500static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {501 if (!Ptr.isStatic() || !Ptr.isBlockPointer())502 return true;503 if (!Ptr.getDeclID())504 return true;505 return CheckConstant(S, OpPC, Ptr.getDeclDesc());506}507 508bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,509 CheckSubobjectKind CSK) {510 if (!Ptr.isZero())511 return true;512 const SourceInfo &Loc = S.Current->getSource(OpPC);513 S.FFDiag(Loc, diag::note_constexpr_null_subobject)514 << CSK << S.Current->getRange(OpPC);515 516 return false;517}518 519bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,520 AccessKinds AK) {521 if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray())522 return true;523 if (S.getLangOpts().CPlusPlus) {524 const SourceInfo &Loc = S.Current->getSource(OpPC);525 S.FFDiag(Loc, diag::note_constexpr_access_past_end)526 << AK << S.Current->getRange(OpPC);527 }528 return false;529}530 531bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,532 CheckSubobjectKind CSK) {533 if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray())534 return true;535 const SourceInfo &Loc = S.Current->getSource(OpPC);536 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)537 << CSK << S.Current->getRange(OpPC);538 return false;539}540 541bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,542 CheckSubobjectKind CSK) {543 if (!Ptr.isOnePastEnd())544 return true;545 546 const SourceInfo &Loc = S.Current->getSource(OpPC);547 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)548 << CSK << S.Current->getRange(OpPC);549 return false;550}551 552bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,553 uint32_t Offset) {554 uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();555 uint32_t PtrOffset = Ptr.getByteOffset();556 557 // We subtract Offset from PtrOffset. The result must be at least558 // MinOffset.559 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)560 return true;561 562 const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));563 QualType TargetQT = E->getType()->getPointeeType();564 QualType MostDerivedQT = Ptr.getDeclPtr().getType();565 566 S.CCEDiag(E, diag::note_constexpr_invalid_downcast)567 << MostDerivedQT << TargetQT;568 569 return false;570}571 572bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {573 assert(Ptr.isLive() && "Pointer is not live");574 if (!Ptr.isConst())575 return true;576 577 if (Ptr.isMutable() && !Ptr.isConstInMutable())578 return true;579 580 if (!Ptr.isBlockPointer())581 return false;582 583 // The This pointer is writable in constructors and destructors,584 // even if isConst() returns true.585 if (llvm::is_contained(S.InitializingBlocks, Ptr.block()))586 return true;587 588 const QualType Ty = Ptr.getType();589 const SourceInfo &Loc = S.Current->getSource(OpPC);590 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;591 return false;592}593 594bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {595 assert(Ptr.isLive() && "Pointer is not live");596 if (!Ptr.isMutable())597 return true;598 599 // In C++14 onwards, it is permitted to read a mutable member whose600 // lifetime began within the evaluation.601 if (S.getLangOpts().CPlusPlus14 &&602 Ptr.block()->getEvalID() == S.Ctx.getEvalID()) {603 // FIXME: This check is necessary because (of the way) we revisit604 // variables in Compiler.cpp:visitDeclRef. Revisiting a so far605 // unknown variable will get the same EvalID and we end up allowing606 // reads from mutable members of it.607 if (!S.inConstantContext() && isConstexprUnknown(Ptr))608 return false;609 return true;610 }611 612 const SourceInfo &Loc = S.Current->getSource(OpPC);613 const FieldDecl *Field = Ptr.getField();614 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;615 S.Note(Field->getLocation(), diag::note_declared_at);616 return false;617}618 619static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,620 AccessKinds AK) {621 assert(Ptr.isLive());622 623 if (!Ptr.isVolatile())624 return true;625 626 if (!S.getLangOpts().CPlusPlus)627 return Invalid(S, OpPC);628 629 // The reason why Ptr is volatile might be further up the hierarchy.630 // Find that pointer.631 Pointer P = Ptr;632 while (!P.isRoot()) {633 if (P.getType().isVolatileQualified())634 break;635 P = P.getBase();636 }637 638 const NamedDecl *ND = nullptr;639 int DiagKind;640 SourceLocation Loc;641 if (const auto *F = P.getField()) {642 DiagKind = 2;643 Loc = F->getLocation();644 ND = F;645 } else if (auto *VD = P.getFieldDesc()->asValueDecl()) {646 DiagKind = 1;647 Loc = VD->getLocation();648 ND = VD;649 } else {650 DiagKind = 0;651 if (const auto *E = P.getFieldDesc()->asExpr())652 Loc = E->getExprLoc();653 }654 655 S.FFDiag(S.Current->getLocation(OpPC),656 diag::note_constexpr_access_volatile_obj, 1)657 << AK << DiagKind << ND;658 S.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;659 return false;660}661 662bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,663 AccessKinds AK) {664 assert(Ptr.isLive());665 assert(!Ptr.isInitialized());666 return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.getDeclDesc(), AK);667}668 669bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,670 const Descriptor *Desc, AccessKinds AK) {671 if (Extern && S.checkingPotentialConstantExpression())672 return false;673 674 if (const auto *VD = Desc->asVarDecl();675 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {676 677 if (VD == S.EvaluatingDecl &&678 !(S.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {679 if (!S.getLangOpts().CPlusPlus14 &&680 !VD->getType().isConstant(S.getASTContext())) {681 // Diagnose as non-const read.682 diagnoseNonConstVariable(S, OpPC, VD);683 } else {684 const SourceInfo &Loc = S.Current->getSource(OpPC);685 // Diagnose as "read of object outside its lifetime".686 S.FFDiag(Loc, diag::note_constexpr_access_uninit)687 << AK << /*IsIndeterminate=*/false;688 }689 return false;690 }691 692 if (VD->getAnyInitializer()) {693 const SourceInfo &Loc = S.Current->getSource(OpPC);694 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;695 S.Note(VD->getLocation(), diag::note_declared_at);696 } else {697 diagnoseMissingInitializer(S, OpPC, VD);698 }699 return false;700 }701 702 if (!S.checkingPotentialConstantExpression()) {703 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)704 << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);705 }706 return false;707}708 709static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,710 AccessKinds AK) {711 if (LT == Lifetime::Started)712 return true;713 714 if (!S.checkingPotentialConstantExpression()) {715 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)716 << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);717 }718 return false;719}720 721static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {722 if (!B->isWeak())723 return true;724 725 const auto *VD = B->getDescriptor()->asVarDecl();726 assert(VD);727 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)728 << VD;729 S.Note(VD->getLocation(), diag::note_declared_at);730 731 return false;732}733 734// The list of checks here is just the one from CheckLoad, but with the735// ones removed that are impossible on primitive global values.736// For example, since those can't be members of structs, they also can't737// be mutable.738bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {739 const auto &Desc =740 *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());741 if (!B->isAccessible()) {742 if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))743 return false;744 if (!CheckDummy(S, OpPC, B, AK_Read))745 return false;746 return CheckWeak(S, OpPC, B);747 }748 749 if (!CheckConstant(S, OpPC, B->getDescriptor()))750 return false;751 if (Desc.InitState != GlobalInitState::Initialized)752 return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),753 AK_Read);754 if (!CheckTemporary(S, OpPC, B, AK_Read))755 return false;756 if (B->getDescriptor()->IsVolatile) {757 if (!S.getLangOpts().CPlusPlus)758 return Invalid(S, OpPC);759 760 const ValueDecl *D = B->getDescriptor()->asValueDecl();761 S.FFDiag(S.Current->getLocation(OpPC),762 diag::note_constexpr_access_volatile_obj, 1)763 << AK_Read << 1 << D;764 S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;765 return false;766 }767 return true;768}769 770// Similarly, for local loads.771bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {772 assert(!B->isExtern());773 const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());774 if (!CheckLifetime(S, OpPC, Desc.LifeState, AK_Read))775 return false;776 if (!Desc.IsInitialized)777 return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B->getDescriptor(),778 AK_Read);779 if (B->getDescriptor()->IsVolatile) {780 if (!S.getLangOpts().CPlusPlus)781 return Invalid(S, OpPC);782 783 const ValueDecl *D = B->getDescriptor()->asValueDecl();784 S.FFDiag(S.Current->getLocation(OpPC),785 diag::note_constexpr_access_volatile_obj, 1)786 << AK_Read << 1 << D;787 S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;788 return false;789 }790 return true;791}792 793bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,794 AccessKinds AK) {795 if (Ptr.isZero()) {796 const auto &Src = S.Current->getSource(OpPC);797 798 if (Ptr.isField())799 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;800 else801 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;802 return false;803 }804 // Block pointers are the only ones we can actually read from.805 if (!Ptr.isBlockPointer())806 return false;807 808 if (!Ptr.block()->isAccessible()) {809 if (!CheckLive(S, OpPC, Ptr, AK))810 return false;811 if (!CheckExtern(S, OpPC, Ptr))812 return false;813 if (!CheckDummy(S, OpPC, Ptr.block(), AK))814 return false;815 return CheckWeak(S, OpPC, Ptr.block());816 }817 818 if (!CheckConstant(S, OpPC, Ptr))819 return false;820 if (!CheckRange(S, OpPC, Ptr, AK))821 return false;822 if (!CheckActive(S, OpPC, Ptr, AK))823 return false;824 if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK))825 return false;826 if (!Ptr.isInitialized())827 return DiagnoseUninitialized(S, OpPC, Ptr, AK);828 if (!CheckTemporary(S, OpPC, Ptr.block(), AK))829 return false;830 831 if (!CheckMutable(S, OpPC, Ptr))832 return false;833 if (!CheckVolatile(S, OpPC, Ptr, AK))834 return false;835 if (!Ptr.isConst() && !S.inConstantContext() && isConstexprUnknown(Ptr))836 return false;837 return true;838}839 840/// This is not used by any of the opcodes directly. It's used by841/// EvalEmitter to do the final lvalue-to-rvalue conversion.842bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {843 assert(!Ptr.isZero());844 if (!Ptr.isBlockPointer())845 return false;846 847 if (!Ptr.block()->isAccessible()) {848 if (!CheckLive(S, OpPC, Ptr, AK_Read))849 return false;850 if (!CheckExtern(S, OpPC, Ptr))851 return false;852 if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))853 return false;854 return CheckWeak(S, OpPC, Ptr.block());855 }856 857 if (!CheckConstant(S, OpPC, Ptr))858 return false;859 860 if (!CheckActive(S, OpPC, Ptr, AK_Read))861 return false;862 if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read))863 return false;864 if (!Ptr.isInitialized())865 return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read);866 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read))867 return false;868 if (!CheckMutable(S, OpPC, Ptr))869 return false;870 return true;871}872 873bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,874 bool WillBeActivated) {875 if (!Ptr.isBlockPointer() || Ptr.isZero())876 return false;877 878 if (!Ptr.block()->isAccessible()) {879 if (!CheckLive(S, OpPC, Ptr, AK_Assign))880 return false;881 if (!CheckExtern(S, OpPC, Ptr))882 return false;883 return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);884 }885 if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign))886 return false;887 if (!CheckRange(S, OpPC, Ptr, AK_Assign))888 return false;889 if (!WillBeActivated && !CheckActive(S, OpPC, Ptr, AK_Assign))890 return false;891 if (!CheckGlobal(S, OpPC, Ptr))892 return false;893 if (!CheckConst(S, OpPC, Ptr))894 return false;895 if (!CheckVolatile(S, OpPC, Ptr, AK_Assign))896 return false;897 if (!S.inConstantContext() && isConstexprUnknown(Ptr))898 return false;899 return true;900}901 902static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {903 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))904 return false;905 if (!Ptr.isDummy()) {906 if (!CheckExtern(S, OpPC, Ptr))907 return false;908 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))909 return false;910 }911 return true;912}913 914bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {915 if (!CheckLive(S, OpPC, Ptr, AK_Assign))916 return false;917 if (!CheckRange(S, OpPC, Ptr, AK_Assign))918 return false;919 return true;920}921 922static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC,923 const FunctionDecl *DiagDecl) {924 // Bail out if the function declaration itself is invalid. We will925 // have produced a relevant diagnostic while parsing it, so just926 // note the problematic sub-expression.927 if (DiagDecl->isInvalidDecl())928 return Invalid(S, OpPC);929 930 // Diagnose failed assertions specially.931 if (S.Current->getLocation(OpPC).isMacroID() && DiagDecl->getIdentifier()) {932 // FIXME: Instead of checking for an implementation-defined function,933 // check and evaluate the assert() macro.934 StringRef Name = DiagDecl->getName();935 bool AssertFailed =936 Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";937 if (AssertFailed) {938 S.FFDiag(S.Current->getLocation(OpPC),939 diag::note_constexpr_assert_failed);940 return false;941 }942 }943 944 if (!S.getLangOpts().CPlusPlus11) {945 S.FFDiag(S.Current->getLocation(OpPC),946 diag::note_invalid_subexpr_in_const_expr);947 return false;948 }949 950 // Invalid decls have been diagnosed before.951 if (DiagDecl->isInvalidDecl())952 return false;953 954 // If this function is not constexpr because it is an inherited955 // non-constexpr constructor, diagnose that directly.956 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);957 if (CD && CD->isInheritingConstructor()) {958 const auto *Inherited = CD->getInheritedConstructor().getConstructor();959 if (!Inherited->isConstexpr())960 DiagDecl = CD = Inherited;961 }962 963 // Silently reject constructors of invalid classes. The invalid class964 // has been rejected elsewhere before.965 if (CD && CD->getParent()->isInvalidDecl())966 return false;967 968 // FIXME: If DiagDecl is an implicitly-declared special member function969 // or an inheriting constructor, we should be much more explicit about why970 // it's not constexpr.971 if (CD && CD->isInheritingConstructor()) {972 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_invalid_inhctor,973 1)974 << CD->getInheritedConstructor().getConstructor()->getParent();975 S.Note(DiagDecl->getLocation(), diag::note_declared_at);976 } else {977 // Don't emit anything if the function isn't defined and we're checking978 // for a constant expression. It might be defined at the point we're979 // actually calling it.980 bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;981 bool IsDefined = DiagDecl->isDefined();982 if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&983 S.checkingPotentialConstantExpression())984 return false;985 986 // If the declaration is defined, declared 'constexpr' _and_ has a body,987 // the below diagnostic doesn't add anything useful.988 if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && DiagDecl->hasBody())989 return false;990 991 S.FFDiag(S.Current->getLocation(OpPC),992 diag::note_constexpr_invalid_function, 1)993 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;994 995 if (DiagDecl->getDefinition())996 S.Note(DiagDecl->getDefinition()->getLocation(), diag::note_declared_at);997 else998 S.Note(DiagDecl->getLocation(), diag::note_declared_at);999 }1000 1001 return false;1002}1003 1004static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {1005 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {1006 const SourceLocation &Loc = S.Current->getLocation(OpPC);1007 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);1008 return false;1009 }1010 1011 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)1012 return false;1013 1014 if (F->isValid() && F->hasBody() && F->isConstexpr())1015 return true;1016 1017 const FunctionDecl *DiagDecl = F->getDecl();1018 const FunctionDecl *Definition = nullptr;1019 DiagDecl->getBody(Definition);1020 1021 if (!Definition && S.checkingPotentialConstantExpression() &&1022 DiagDecl->isConstexpr()) {1023 return false;1024 }1025 1026 // Implicitly constexpr.1027 if (F->isLambdaStaticInvoker())1028 return true;1029 1030 return diagnoseCallableDecl(S, OpPC, DiagDecl);1031}1032 1033static bool CheckCallDepth(InterpState &S, CodePtr OpPC) {1034 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {1035 S.FFDiag(S.Current->getSource(OpPC),1036 diag::note_constexpr_depth_limit_exceeded)1037 << S.getLangOpts().ConstexprCallDepth;1038 return false;1039 }1040 1041 return true;1042}1043 1044bool CheckThis(InterpState &S, CodePtr OpPC) {1045 if (S.Current->hasThisPointer())1046 return true;1047 1048 const Expr *E = S.Current->getExpr(OpPC);1049 if (S.getLangOpts().CPlusPlus11) {1050 bool IsImplicit = false;1051 if (const auto *TE = dyn_cast<CXXThisExpr>(E))1052 IsImplicit = TE->isImplicit();1053 S.FFDiag(E, diag::note_constexpr_this) << IsImplicit;1054 } else {1055 S.FFDiag(E);1056 }1057 1058 return false;1059}1060 1061bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,1062 APFloat::opStatus Status, FPOptions FPO) {1063 // [expr.pre]p4:1064 // If during the evaluation of an expression, the result is not1065 // mathematically defined [...], the behavior is undefined.1066 // FIXME: C++ rules require us to not conform to IEEE 754 here.1067 if (Result.isNan()) {1068 const SourceInfo &E = S.Current->getSource(OpPC);1069 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)1070 << /*NaN=*/true << S.Current->getRange(OpPC);1071 return S.noteUndefinedBehavior();1072 }1073 1074 // In a constant context, assume that any dynamic rounding mode or FP1075 // exception state matches the default floating-point environment.1076 if (S.inConstantContext())1077 return true;1078 1079 if ((Status & APFloat::opInexact) &&1080 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {1081 // Inexact result means that it depends on rounding mode. If the requested1082 // mode is dynamic, the evaluation cannot be made in compile time.1083 const SourceInfo &E = S.Current->getSource(OpPC);1084 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);1085 return false;1086 }1087 1088 if ((Status != APFloat::opOK) &&1089 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||1090 FPO.getExceptionMode() != LangOptions::FPE_Ignore ||1091 FPO.getAllowFEnvAccess())) {1092 const SourceInfo &E = S.Current->getSource(OpPC);1093 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);1094 return false;1095 }1096 1097 if ((Status & APFloat::opStatus::opInvalidOp) &&1098 FPO.getExceptionMode() != LangOptions::FPE_Ignore) {1099 const SourceInfo &E = S.Current->getSource(OpPC);1100 // There is no usefully definable result.1101 S.FFDiag(E);1102 return false;1103 }1104 1105 return true;1106}1107 1108bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {1109 if (S.getLangOpts().CPlusPlus20)1110 return true;1111 1112 const SourceInfo &E = S.Current->getSource(OpPC);1113 S.CCEDiag(E, diag::note_constexpr_new);1114 return true;1115}1116 1117bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,1118 DynamicAllocator::Form AllocForm,1119 DynamicAllocator::Form DeleteForm, const Descriptor *D,1120 const Expr *NewExpr) {1121 if (AllocForm == DeleteForm)1122 return true;1123 1124 QualType TypeToDiagnose = D->getDataType(S.getASTContext());1125 1126 const SourceInfo &E = S.Current->getSource(OpPC);1127 S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)1128 << static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)1129 << TypeToDiagnose;1130 S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)1131 << NewExpr->getSourceRange();1132 return false;1133}1134 1135bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,1136 const Pointer &Ptr) {1137 // Regular new type(...) call.1138 if (isa_and_nonnull<CXXNewExpr>(Source))1139 return true;1140 // operator new.1141 if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);1142 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)1143 return true;1144 // std::allocator.allocate() call1145 if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);1146 MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))1147 return true;1148 1149 // Whatever this is, we didn't heap allocate it.1150 const SourceInfo &Loc = S.Current->getSource(OpPC);1151 S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)1152 << Ptr.toDiagnosticString(S.getASTContext());1153 1154 if (Ptr.isTemporary())1155 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);1156 else1157 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);1158 return false;1159}1160 1161/// We aleady know the given DeclRefExpr is invalid for some reason,1162/// now figure out why and print appropriate diagnostics.1163bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {1164 const ValueDecl *D = DR->getDecl();1165 return diagnoseUnknownDecl(S, OpPC, D);1166}1167 1168bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {1169 if (!B->isDummy())1170 return true;1171 1172 const ValueDecl *D = B->getDescriptor()->asValueDecl();1173 if (!D)1174 return false;1175 1176 if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)1177 return diagnoseUnknownDecl(S, OpPC, D);1178 1179 if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14) {1180 const SourceInfo &E = S.Current->getSource(OpPC);1181 S.FFDiag(E, diag::note_constexpr_modify_global);1182 }1183 return false;1184}1185 1186static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,1187 const CallExpr *CE, unsigned ArgSize) {1188 auto Args = ArrayRef(CE->getArgs(), CE->getNumArgs());1189 auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);1190 unsigned Offset = 0;1191 unsigned Index = 0;1192 for (const Expr *Arg : Args) {1193 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {1194 const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);1195 if (ArgPtr.isZero()) {1196 const SourceLocation &Loc = S.Current->getLocation(OpPC);1197 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);1198 return false;1199 }1200 }1201 1202 Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));1203 ++Index;1204 }1205 return true;1206}1207 1208static bool runRecordDestructor(InterpState &S, CodePtr OpPC,1209 const Pointer &BasePtr,1210 const Descriptor *Desc) {1211 assert(Desc->isRecord());1212 const Record *R = Desc->ElemRecord;1213 assert(R);1214 1215 if (S.Current->hasThisPointer() && S.Current->getFunction()->isDestructor() &&1216 Pointer::pointToSameBlock(BasePtr, S.Current->getThis())) {1217 const SourceInfo &Loc = S.Current->getSource(OpPC);1218 S.FFDiag(Loc, diag::note_constexpr_double_destroy);1219 return false;1220 }1221 1222 // Destructor of this record.1223 const CXXDestructorDecl *Dtor = R->getDestructor();1224 assert(Dtor);1225 assert(!Dtor->isTrivial());1226 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);1227 if (!DtorFunc)1228 return false;1229 1230 S.Stk.push<Pointer>(BasePtr);1231 return Call(S, OpPC, DtorFunc, 0);1232}1233 1234static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {1235 assert(B);1236 const Descriptor *Desc = B->getDescriptor();1237 1238 if (Desc->isPrimitive() || Desc->isPrimitiveArray())1239 return true;1240 1241 assert(Desc->isRecord() || Desc->isCompositeArray());1242 1243 if (Desc->hasTrivialDtor())1244 return true;1245 1246 if (Desc->isCompositeArray()) {1247 unsigned N = Desc->getNumElems();1248 if (N == 0)1249 return true;1250 const Descriptor *ElemDesc = Desc->ElemDesc;1251 assert(ElemDesc->isRecord());1252 1253 Pointer RP(const_cast<Block *>(B));1254 for (int I = static_cast<int>(N) - 1; I >= 0; --I) {1255 if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))1256 return false;1257 }1258 return true;1259 }1260 1261 assert(Desc->isRecord());1262 return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);1263}1264 1265static bool hasVirtualDestructor(QualType T) {1266 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())1267 if (const CXXDestructorDecl *DD = RD->getDestructor())1268 return DD->isVirtual();1269 return false;1270}1271 1272bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,1273 bool IsGlobalDelete) {1274 if (!CheckDynamicMemoryAllocation(S, OpPC))1275 return false;1276 1277 DynamicAllocator &Allocator = S.getAllocator();1278 1279 const Expr *Source = nullptr;1280 const Block *BlockToDelete = nullptr;1281 {1282 // Extra scope for this so the block doesn't have this pointer1283 // pointing to it when we destroy it.1284 Pointer Ptr = S.Stk.pop<Pointer>();1285 1286 // Deleteing nullptr is always fine.1287 if (Ptr.isZero())1288 return true;1289 1290 // Remove base casts.1291 QualType InitialType = Ptr.getType();1292 while (Ptr.isBaseClass())1293 Ptr = Ptr.getBase();1294 1295 Source = Ptr.getDeclDesc()->asExpr();1296 BlockToDelete = Ptr.block();1297 1298 // Check that new[]/delete[] or new/delete were used, not a mixture.1299 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();1300 if (std::optional<DynamicAllocator::Form> AllocForm =1301 Allocator.getAllocationForm(Source)) {1302 DynamicAllocator::Form DeleteForm =1303 DeleteIsArrayForm ? DynamicAllocator::Form::Array1304 : DynamicAllocator::Form::NonArray;1305 if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,1306 Source))1307 return false;1308 }1309 1310 // For the non-array case, the types must match if the static type1311 // does not have a virtual destructor.1312 if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&1313 !hasVirtualDestructor(InitialType)) {1314 S.FFDiag(S.Current->getSource(OpPC),1315 diag::note_constexpr_delete_base_nonvirt_dtor)1316 << InitialType << Ptr.getType();1317 return false;1318 }1319 1320 if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) ||1321 (Ptr.isArrayElement() && Ptr.getIndex() != 0)) {1322 const SourceInfo &Loc = S.Current->getSource(OpPC);1323 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)1324 << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();1325 return false;1326 }1327 1328 if (!CheckDeleteSource(S, OpPC, Source, Ptr))1329 return false;1330 1331 // For a class type with a virtual destructor, the selected operator delete1332 // is the one looked up when building the destructor.1333 if (!DeleteIsArrayForm && !IsGlobalDelete) {1334 QualType AllocType = Ptr.getType();1335 auto getVirtualOperatorDelete = [](QualType T) -> const FunctionDecl * {1336 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())1337 if (const CXXDestructorDecl *DD = RD->getDestructor())1338 return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;1339 return nullptr;1340 };1341 1342 if (const FunctionDecl *VirtualDelete =1343 getVirtualOperatorDelete(AllocType);1344 VirtualDelete &&1345 !VirtualDelete1346 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {1347 S.FFDiag(S.Current->getSource(OpPC),1348 diag::note_constexpr_new_non_replaceable)1349 << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;1350 return false;1351 }1352 }1353 }1354 assert(Source);1355 assert(BlockToDelete);1356 1357 // Invoke destructors before deallocating the memory.1358 if (!RunDestructors(S, OpPC, BlockToDelete))1359 return false;1360 1361 if (!Allocator.deallocate(Source, BlockToDelete, S)) {1362 // Nothing has been deallocated, this must be a double-delete.1363 const SourceInfo &Loc = S.Current->getSource(OpPC);1364 S.FFDiag(Loc, diag::note_constexpr_double_delete);1365 return false;1366 }1367 1368 return true;1369}1370 1371void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,1372 const APSInt &Value) {1373 llvm::APInt Min;1374 llvm::APInt Max;1375 ED->getValueRange(Max, Min);1376 --Max;1377 1378 if (ED->getNumNegativeBits() &&1379 (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {1380 const SourceLocation &Loc = S.Current->getLocation(OpPC);1381 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)1382 << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()1383 << ED;1384 } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {1385 const SourceLocation &Loc = S.Current->getLocation(OpPC);1386 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)1387 << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()1388 << ED;1389 }1390}1391 1392bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {1393 assert(T);1394 assert(!S.getLangOpts().CPlusPlus23);1395 1396 // C++1y: A constant initializer for an object o [...] may also invoke1397 // constexpr constructors for o and its subobjects even if those objects1398 // are of non-literal class types.1399 //1400 // C++11 missed this detail for aggregates, so classes like this:1401 // struct foo_t { union { int i; volatile int j; } u; };1402 // are not (obviously) initializable like so:1403 // __attribute__((__require_constant_initialization__))1404 // static const foo_t x = {{0}};1405 // because "i" is a subobject with non-literal initialization (due to the1406 // volatile member of the union). See:1407 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#16771408 // Therefore, we use the C++1y behavior.1409 1410 if (!S.Current->isBottomFrame() &&1411 S.Current->getFunction()->isConstructor() &&1412 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {1413 return true;1414 }1415 1416 const Expr *E = S.Current->getExpr(OpPC);1417 if (S.getLangOpts().CPlusPlus11)1418 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();1419 else1420 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);1421 return false;1422}1423 1424static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,1425 uint32_t Off) {1426 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&1427 !CheckNull(S, OpPC, Ptr, CSK_Field))1428 return false;1429 1430 if (!CheckRange(S, OpPC, Ptr, CSK_Field))1431 return false;1432 if (!CheckArray(S, OpPC, Ptr))1433 return false;1434 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))1435 return false;1436 1437 if (Ptr.isIntegralPointer()) {1438 if (std::optional<IntPointer> IntPtr =1439 Ptr.asIntPointer().atOffset(S.getASTContext(), Off)) {1440 S.Stk.push<Pointer>(std::move(*IntPtr));1441 return true;1442 }1443 return false;1444 }1445 1446 if (!Ptr.isBlockPointer()) {1447 // FIXME: The only time we (seem to) get here is when trying to access a1448 // field of a typeid pointer. In that case, we're supposed to diagnose e.g.1449 // `typeid(int).name`, but we currently diagnose `&typeid(int)`.1450 S.FFDiag(S.Current->getSource(OpPC),1451 diag::note_constexpr_access_unreadable_object)1452 << AK_Read << Ptr.toDiagnosticString(S.getASTContext());1453 return false;1454 }1455 1456 // We can't get the field of something that's not a record.1457 if (!Ptr.getFieldDesc()->isRecord())1458 return false;1459 1460 if ((Ptr.getByteOffset() + Off) >= Ptr.block()->getSize())1461 return false;1462 1463 S.Stk.push<Pointer>(Ptr.atField(Off));1464 return true;1465}1466 1467bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {1468 const auto &Ptr = S.Stk.peek<Pointer>();1469 return getField(S, OpPC, Ptr, Off);1470}1471 1472bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {1473 const auto &Ptr = S.Stk.pop<Pointer>();1474 return getField(S, OpPC, Ptr, Off);1475}1476 1477static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,1478 const Pointer &ThisPtr) {1479 assert(Func->isConstructor());1480 1481 if (Func->getParentDecl()->isInvalidDecl())1482 return false;1483 1484 const Descriptor *D = ThisPtr.getFieldDesc();1485 // FIXME: I think this case is not 100% correct. E.g. a pointer into a1486 // subobject of a composite array.1487 if (!D->ElemRecord)1488 return true;1489 1490 if (D->ElemRecord->getNumVirtualBases() == 0)1491 return true;1492 1493 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)1494 << Func->getParentDecl();1495 return false;1496}1497 1498bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {1499 if (!CheckLive(S, OpPC, Ptr, AK_Destroy))1500 return false;1501 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))1502 return false;1503 if (!CheckRange(S, OpPC, Ptr, AK_Destroy))1504 return false;1505 1506 // Can't call a dtor on a global variable.1507 if (Ptr.block()->isStatic()) {1508 const SourceInfo &E = S.Current->getSource(OpPC);1509 S.FFDiag(E, diag::note_constexpr_modify_global);1510 return false;1511 }1512 return CheckActive(S, OpPC, Ptr, AK_Destroy);1513}1514 1515/// Opcode. Check if the function decl can be called at compile time.1516bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD) {1517 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)1518 return false;1519 1520 const FunctionDecl *Definition = nullptr;1521 const Stmt *Body = FD->getBody(Definition);1522 1523 if (Definition && Body &&1524 (Definition->isConstexpr() || Definition->hasAttr<MSConstexprAttr>()))1525 return true;1526 1527 return diagnoseCallableDecl(S, OpPC, FD);1528}1529 1530static void compileFunction(InterpState &S, const Function *Func) {1531 const FunctionDecl *Definition = Func->getDecl()->getDefinition();1532 if (!Definition)1533 return;1534 1535 Compiler<ByteCodeEmitter>(S.getContext(), S.P)1536 .compileFunc(Definition, const_cast<Function *>(Func));1537}1538 1539bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,1540 uint32_t VarArgSize) {1541 if (Func->hasThisPointer()) {1542 size_t ArgSize = Func->getArgSize() + VarArgSize;1543 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);1544 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);1545 1546 // If the current function is a lambda static invoker and1547 // the function we're about to call is a lambda call operator,1548 // skip the CheckInvoke, since the ThisPtr is a null pointer1549 // anyway.1550 if (!(S.Current->getFunction() &&1551 S.Current->getFunction()->isLambdaStaticInvoker() &&1552 Func->isLambdaCallOperator())) {1553 if (!CheckInvoke(S, OpPC, ThisPtr))1554 return false;1555 }1556 1557 if (S.checkingPotentialConstantExpression())1558 return false;1559 }1560 1561 if (!Func->isFullyCompiled())1562 compileFunction(S, Func);1563 1564 if (!CheckCallable(S, OpPC, Func))1565 return false;1566 1567 if (!CheckCallDepth(S, OpPC))1568 return false;1569 1570 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);1571 InterpFrame *FrameBefore = S.Current;1572 S.Current = NewFrame.get();1573 1574 // Note that we cannot assert(CallResult.hasValue()) here since1575 // Ret() above only sets the APValue if the curent frame doesn't1576 // have a caller set.1577 if (Interpret(S)) {1578 NewFrame.release(); // Frame was delete'd already.1579 assert(S.Current == FrameBefore);1580 return true;1581 }1582 1583 // Interpreting the function failed somehow. Reset to1584 // previous state.1585 S.Current = FrameBefore;1586 return false;1587}1588bool Call(InterpState &S, CodePtr OpPC, const Function *Func,1589 uint32_t VarArgSize) {1590 assert(Func);1591 auto cleanup = [&]() -> bool {1592 cleanupAfterFunctionCall(S, OpPC, Func);1593 return false;1594 };1595 1596 if (Func->hasThisPointer()) {1597 size_t ArgSize = Func->getArgSize() + VarArgSize;1598 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);1599 1600 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);1601 1602 // C++23 [expr.const]p5.61603 // an invocation of a virtual function ([class.virtual]) for an object whose1604 // dynamic type is constexpr-unknown;1605 if (ThisPtr.isDummy() && Func->isVirtual())1606 return false;1607 1608 // If the current function is a lambda static invoker and1609 // the function we're about to call is a lambda call operator,1610 // skip the CheckInvoke, since the ThisPtr is a null pointer1611 // anyway.1612 if (S.Current->getFunction() &&1613 S.Current->getFunction()->isLambdaStaticInvoker() &&1614 Func->isLambdaCallOperator()) {1615 assert(ThisPtr.isZero());1616 } else {1617 if (!CheckInvoke(S, OpPC, ThisPtr))1618 return cleanup();1619 if (!Func->isConstructor() && !Func->isDestructor() &&1620 !CheckActive(S, OpPC, ThisPtr, AK_MemberCall))1621 return false;1622 }1623 1624 if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))1625 return false;1626 if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))1627 return false;1628 1629 if (Func->isConstructor() || Func->isDestructor())1630 S.InitializingBlocks.push_back(ThisPtr.block());1631 }1632 1633 if (!Func->isFullyCompiled())1634 compileFunction(S, Func);1635 1636 if (!CheckCallable(S, OpPC, Func))1637 return cleanup();1638 1639 // FIXME: The isConstructor() check here is not always right. The current1640 // constant evaluator is somewhat inconsistent in when it allows a function1641 // call when checking for a constant expression.1642 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&1643 !Func->isConstructor())1644 return cleanup();1645 1646 if (!CheckCallDepth(S, OpPC))1647 return cleanup();1648 1649 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);1650 InterpFrame *FrameBefore = S.Current;1651 S.Current = NewFrame.get();1652 1653 InterpStateCCOverride CCOverride(S, Func->isImmediate());1654 // Note that we cannot assert(CallResult.hasValue()) here since1655 // Ret() above only sets the APValue if the curent frame doesn't1656 // have a caller set.1657 bool Success = Interpret(S);1658 // Remove initializing block again.1659 if (Func->isConstructor() || Func->isDestructor())1660 S.InitializingBlocks.pop_back();1661 1662 if (!Success) {1663 // Interpreting the function failed somehow. Reset to1664 // previous state.1665 S.Current = FrameBefore;1666 return false;1667 }1668 1669 NewFrame.release(); // Frame was delete'd already.1670 assert(S.Current == FrameBefore);1671 return true;1672}1673 1674static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr,1675 const CXXRecordDecl *&DynamicDecl) {1676 while (TypePtr.isBaseClass())1677 TypePtr = TypePtr.getBase();1678 1679 QualType DynamicType = TypePtr.getType();1680 if (TypePtr.isStatic() || TypePtr.isConst()) {1681 if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();1682 VD && !VD->isConstexpr()) {1683 const Expr *E = S.Current->getExpr(OpPC);1684 APValue V = TypePtr.toAPValue(S.getASTContext());1685 QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);1686 S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)1687 << AccessKinds::AK_MemberCall << V.getAsString(S.getASTContext(), TT);1688 return false;1689 }1690 }1691 1692 if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {1693 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();1694 } else if (DynamicType->isArrayType()) {1695 const Type *ElemType = DynamicType->getPointeeOrArrayElementType();1696 assert(ElemType);1697 DynamicDecl = ElemType->getAsCXXRecordDecl();1698 } else {1699 DynamicDecl = DynamicType->getAsCXXRecordDecl();1700 }1701 return true;1702}1703 1704bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,1705 uint32_t VarArgSize) {1706 assert(Func->hasThisPointer());1707 assert(Func->isVirtual());1708 size_t ArgSize = Func->getArgSize() + VarArgSize;1709 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);1710 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);1711 const FunctionDecl *Callee = Func->getDecl();1712 1713 const CXXRecordDecl *DynamicDecl = nullptr;1714 if (!GetDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))1715 return false;1716 assert(DynamicDecl);1717 1718 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());1719 const auto *InitialFunction = cast<CXXMethodDecl>(Callee);1720 const CXXMethodDecl *Overrider;1721 1722 if (StaticDecl != DynamicDecl &&1723 !llvm::is_contained(S.InitializingBlocks, ThisPtr.block())) {1724 if (!DynamicDecl->isDerivedFrom(StaticDecl))1725 return false;1726 Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,1727 InitialFunction);1728 1729 } else {1730 Overrider = InitialFunction;1731 }1732 1733 // C++2a [class.abstract]p6:1734 // the effect of making a virtual call to a pure virtual function [...] is1735 // undefined1736 if (Overrider->isPureVirtual()) {1737 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,1738 1)1739 << Callee;1740 S.Note(Callee->getLocation(), diag::note_declared_at);1741 return false;1742 }1743 1744 if (Overrider != InitialFunction) {1745 // DR1872: An instantiated virtual constexpr function can't be called in a1746 // constant expression (prior to C++20). We can still constant-fold such a1747 // call.1748 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {1749 const Expr *E = S.Current->getExpr(OpPC);1750 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();1751 }1752 1753 Func = S.getContext().getOrCreateFunction(Overrider);1754 1755 const CXXRecordDecl *ThisFieldDecl =1756 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();1757 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {1758 // If the function we call is further DOWN the hierarchy than the1759 // FieldDesc of our pointer, just go up the hierarchy of this field1760 // the furthest we can go.1761 while (ThisPtr.isBaseClass())1762 ThisPtr = ThisPtr.getBase();1763 }1764 }1765 1766 if (!Call(S, OpPC, Func, VarArgSize))1767 return false;1768 1769 // Covariant return types. The return type of Overrider is a pointer1770 // or reference to a class type.1771 if (Overrider != InitialFunction &&1772 Overrider->getReturnType()->isPointerOrReferenceType() &&1773 InitialFunction->getReturnType()->isPointerOrReferenceType()) {1774 QualType OverriderPointeeType =1775 Overrider->getReturnType()->getPointeeType();1776 QualType InitialPointeeType =1777 InitialFunction->getReturnType()->getPointeeType();1778 // We've called Overrider above, but calling code expects us to return what1779 // InitialFunction returned. According to the rules for covariant return1780 // types, what InitialFunction returns needs to be a base class of what1781 // Overrider returns. So, we need to do an upcast here.1782 unsigned Offset = S.getContext().collectBaseOffset(1783 InitialPointeeType->getAsRecordDecl(),1784 OverriderPointeeType->getAsRecordDecl());1785 return GetPtrBasePop(S, OpPC, Offset, /*IsNullOK=*/true);1786 }1787 1788 return true;1789}1790 1791bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,1792 uint32_t BuiltinID) {1793 // A little arbitrary, but the current interpreter allows evaluation1794 // of builtin functions in this mode, with some exceptions.1795 if (BuiltinID == Builtin::BI__builtin_operator_new &&1796 S.checkingPotentialConstantExpression())1797 return false;1798 1799 return InterpretBuiltin(S, OpPC, CE, BuiltinID);1800}1801 1802bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,1803 const CallExpr *CE) {1804 const Pointer &Ptr = S.Stk.pop<Pointer>();1805 1806 if (Ptr.isZero()) {1807 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_null_callee)1808 << const_cast<Expr *>(CE->getCallee()) << CE->getSourceRange();1809 return false;1810 }1811 1812 if (!Ptr.isFunctionPointer())1813 return Invalid(S, OpPC);1814 1815 const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();1816 const Function *F = FuncPtr.getFunction();1817 assert(F);1818 // Don't allow calling block pointers.1819 if (!F->getDecl())1820 return Invalid(S, OpPC);1821 1822 // This happens when the call expression has been cast to1823 // something else, but we don't support that.1824 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=1825 S.Ctx.classify(CE->getCallReturnType(S.getASTContext())))1826 return false;1827 1828 // Check argument nullability state.1829 if (F->hasNonNullAttr()) {1830 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))1831 return false;1832 }1833 1834 // Can happen when casting function pointers around.1835 QualType CalleeType = CE->getCallee()->getType();1836 if (CalleeType->isPointerType() &&1837 !S.getASTContext().hasSameFunctionTypeIgnoringExceptionSpec(1838 F->getDecl()->getType(), CalleeType->getPointeeType())) {1839 return false;1840 }1841 1842 assert(ArgSize >= F->getWrittenArgSize());1843 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();1844 1845 // We need to do this explicitly here since we don't have the necessary1846 // information to do it automatically.1847 if (F->isThisPointerExplicit())1848 VarArgSize -= align(primSize(PT_Ptr));1849 1850 if (F->isVirtual())1851 return CallVirt(S, OpPC, F, VarArgSize);1852 1853 return Call(S, OpPC, F, VarArgSize);1854}1855 1856static void startLifetimeRecurse(const Pointer &Ptr) {1857 if (const Record *R = Ptr.getRecord()) {1858 Ptr.startLifetime();1859 for (const Record::Field &Fi : R->fields())1860 startLifetimeRecurse(Ptr.atField(Fi.Offset));1861 return;1862 }1863 1864 if (const Descriptor *FieldDesc = Ptr.getFieldDesc();1865 FieldDesc->isCompositeArray()) {1866 assert(Ptr.getLifetime() == Lifetime::Started);1867 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)1868 startLifetimeRecurse(Ptr.atIndex(I).narrow());1869 return;1870 }1871 1872 Ptr.startLifetime();1873}1874 1875bool StartLifetime(InterpState &S, CodePtr OpPC) {1876 const auto &Ptr = S.Stk.peek<Pointer>();1877 if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))1878 return false;1879 startLifetimeRecurse(Ptr.narrow());1880 return true;1881}1882 1883// FIXME: It might be better to the recursing as part of the generated code for1884// a destructor?1885static void endLifetimeRecurse(const Pointer &Ptr) {1886 if (const Record *R = Ptr.getRecord()) {1887 Ptr.endLifetime();1888 for (const Record::Field &Fi : R->fields())1889 endLifetimeRecurse(Ptr.atField(Fi.Offset));1890 return;1891 }1892 1893 if (const Descriptor *FieldDesc = Ptr.getFieldDesc();1894 FieldDesc->isCompositeArray()) {1895 // No endLifetime() for array roots.1896 assert(Ptr.getLifetime() == Lifetime::Started);1897 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)1898 endLifetimeRecurse(Ptr.atIndex(I).narrow());1899 return;1900 }1901 1902 Ptr.endLifetime();1903}1904 1905/// Ends the lifetime of the peek'd pointer.1906bool EndLifetime(InterpState &S, CodePtr OpPC) {1907 const auto &Ptr = S.Stk.peek<Pointer>();1908 if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))1909 return false;1910 1911 // FIXME: We need per-element lifetime information for primitive arrays.1912 if (Ptr.isArrayElement())1913 return true;1914 1915 endLifetimeRecurse(Ptr.narrow());1916 return true;1917}1918 1919/// Ends the lifetime of the pop'd pointer.1920bool EndLifetimePop(InterpState &S, CodePtr OpPC) {1921 const auto &Ptr = S.Stk.pop<Pointer>();1922 if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))1923 return false;1924 1925 // FIXME: We need per-element lifetime information for primitive arrays.1926 if (Ptr.isArrayElement())1927 return true;1928 1929 endLifetimeRecurse(Ptr.narrow());1930 return true;1931}1932 1933bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,1934 std::optional<uint64_t> ArraySize) {1935 const Pointer &Ptr = S.Stk.peek<Pointer>();1936 1937 if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion())1938 Ptr.activate();1939 1940 if (Ptr.isZero()) {1941 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)1942 << AK_Construct;1943 return false;1944 }1945 1946 if (!Ptr.isBlockPointer())1947 return false;1948 1949 startLifetimeRecurse(Ptr);1950 1951 // Similar to CheckStore(), but with the additional CheckTemporary() call and1952 // the AccessKinds are different.1953 if (!Ptr.block()->isAccessible()) {1954 if (!CheckExtern(S, OpPC, Ptr))1955 return false;1956 if (!CheckLive(S, OpPC, Ptr, AK_Construct))1957 return false;1958 return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);1959 }1960 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))1961 return false;1962 1963 // CheckLifetime for this and all base pointers.1964 for (Pointer P = Ptr;;) {1965 if (!CheckLifetime(S, OpPC, P.getLifetime(), AK_Construct))1966 return false;1967 1968 if (P.isRoot())1969 break;1970 P = P.getBase();1971 }1972 1973 if (!CheckRange(S, OpPC, Ptr, AK_Construct))1974 return false;1975 if (!CheckGlobal(S, OpPC, Ptr))1976 return false;1977 if (!CheckConst(S, OpPC, Ptr))1978 return false;1979 if (!S.inConstantContext() && isConstexprUnknown(Ptr))1980 return false;1981 1982 if (!InvalidNewDeleteExpr(S, OpPC, E))1983 return false;1984 1985 const auto *NewExpr = cast<CXXNewExpr>(E);1986 QualType StorageType = Ptr.getFieldDesc()->getDataType(S.getASTContext());1987 const ASTContext &ASTCtx = S.getASTContext();1988 QualType AllocType;1989 if (ArraySize) {1990 AllocType = ASTCtx.getConstantArrayType(1991 NewExpr->getAllocatedType(),1992 APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,1993 ArraySizeModifier::Normal, 0);1994 } else {1995 AllocType = NewExpr->getAllocatedType();1996 }1997 1998 unsigned StorageSize = 1;1999 unsigned AllocSize = 1;2000 if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))2001 AllocSize = CAT->getZExtSize();2002 if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))2003 StorageSize = CAT->getZExtSize();2004 2005 if (AllocSize > StorageSize ||2006 !ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),2007 ASTCtx.getBaseElementType(StorageType))) {2008 S.FFDiag(S.Current->getLocation(OpPC),2009 diag::note_constexpr_placement_new_wrong_type)2010 << StorageType << AllocType;2011 return false;2012 }2013 2014 // Can't activate fields in a union, unless the direct base is the union.2015 if (Ptr.inUnion() && !Ptr.isActive() && !Ptr.getBase().getRecord()->isUnion())2016 return CheckActive(S, OpPC, Ptr, AK_Construct);2017 2018 return true;2019}2020 2021bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {2022 assert(E);2023 2024 if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {2025 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();2026 2027 if (NewExpr->getNumPlacementArgs() > 0) {2028 // This is allowed pre-C++26, but only an std function.2029 if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction())2030 return true;2031 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)2032 << /*C++26 feature*/ 1 << E->getSourceRange();2033 } else if (2034 !OperatorNew2035 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {2036 S.FFDiag(S.Current->getSource(OpPC),2037 diag::note_constexpr_new_non_replaceable)2038 << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;2039 return false;2040 } else if (!S.getLangOpts().CPlusPlus26 &&2041 NewExpr->getNumPlacementArgs() == 1 &&2042 !OperatorNew->isReservedGlobalPlacementOperator()) {2043 if (!S.getLangOpts().CPlusPlus26) {2044 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)2045 << /*Unsupported*/ 0 << E->getSourceRange();2046 return false;2047 }2048 return true;2049 }2050 } else {2051 const auto *DeleteExpr = cast<CXXDeleteExpr>(E);2052 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();2053 if (!OperatorDelete2054 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {2055 S.FFDiag(S.Current->getSource(OpPC),2056 diag::note_constexpr_new_non_replaceable)2057 << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;2058 return false;2059 }2060 }2061 2062 return false;2063}2064 2065bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,2066 const FixedPoint &FP) {2067 const Expr *E = S.Current->getExpr(OpPC);2068 if (S.checkingForUndefinedBehavior()) {2069 S.getASTContext().getDiagnostics().Report(2070 E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)2071 << FP.toDiagnosticString(S.getASTContext()) << E->getType();2072 }2073 S.CCEDiag(E, diag::note_constexpr_overflow)2074 << FP.toDiagnosticString(S.getASTContext()) << E->getType();2075 return S.noteUndefinedBehavior();2076}2077 2078bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index) {2079 const SourceInfo &Loc = S.Current->getSource(OpPC);2080 S.FFDiag(Loc,2081 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)2082 << Index;2083 return false;2084}2085 2086bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,2087 const Pointer &Ptr, unsigned BitWidth) {2088 const SourceInfo &E = S.Current->getSource(OpPC);2089 S.CCEDiag(E, diag::note_constexpr_invalid_cast)2090 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);2091 2092 if (Ptr.isDummy())2093 return false;2094 if (Ptr.isFunctionPointer())2095 return true;2096 2097 if (Ptr.isBlockPointer() && !Ptr.isZero()) {2098 // Only allow based lvalue casts if they are lossless.2099 if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) !=2100 BitWidth)2101 return Invalid(S, OpPC);2102 }2103 return true;2104}2105 2106bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2107 const Pointer &Ptr = S.Stk.pop<Pointer>();2108 2109 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))2110 return false;2111 2112 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);2113 Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));2114 2115 S.Stk.push<IntegralAP<false>>(Result);2116 return true;2117}2118 2119bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2120 const Pointer &Ptr = S.Stk.pop<Pointer>();2121 2122 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))2123 return false;2124 2125 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);2126 Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));2127 2128 S.Stk.push<IntegralAP<true>>(Result);2129 return true;2130}2131 2132bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,2133 bool TargetIsUCharOrByte) {2134 // This is always fine.2135 if (!HasIndeterminateBits)2136 return true;2137 2138 // Indeterminate bits can only be bitcast to unsigned char or std::byte.2139 if (TargetIsUCharOrByte)2140 return true;2141 2142 const Expr *E = S.Current->getExpr(OpPC);2143 QualType ExprType = E->getType();2144 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)2145 << ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();2146 return false;2147}2148 2149bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,2150 const Type *TypeInfoType) {2151 S.Stk.push<Pointer>(TypePtr, TypeInfoType);2152 return true;2153}2154 2155bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {2156 const auto &P = S.Stk.pop<Pointer>();2157 2158 if (!P.isBlockPointer())2159 return false;2160 2161 // Pick the most-derived type.2162 CanQualType T = P.getDeclPtr().getType()->getCanonicalTypeUnqualified();2163 // ... unless we're currently constructing this object.2164 // FIXME: We have a similar check to this in more places.2165 if (S.Current->getFunction()) {2166 for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {2167 if (const Function *Func = Frame->getFunction();2168 Func && (Func->isConstructor() || Func->isDestructor()) &&2169 P.block() == Frame->getThis().block()) {2170 T = S.getContext().getASTContext().getCanonicalTagType(2171 Func->getParentDecl());2172 break;2173 }2174 }2175 }2176 2177 S.Stk.push<Pointer>(T->getTypePtr(), TypeInfoType);2178 return true;2179}2180 2181bool DiagTypeid(InterpState &S, CodePtr OpPC) {2182 const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));2183 S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)2184 << E->getExprOperand()->getType()2185 << E->getExprOperand()->getSourceRange();2186 return false;2187}2188 2189bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,2190 const Pointer &RHS) {2191 unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();2192 unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();2193 unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();2194 unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();2195 2196 StringRef LHSStr((const char *)LHS.atIndex(0).getRawAddress(), LHSLength);2197 StringRef RHSStr((const char *)RHS.atIndex(0).getRawAddress(), RHSLength);2198 int32_t IndexDiff = RHSOffset - LHSOffset;2199 if (IndexDiff < 0) {2200 if (static_cast<int32_t>(LHSLength) < -IndexDiff)2201 return false;2202 LHSStr = LHSStr.drop_front(-IndexDiff);2203 } else {2204 if (static_cast<int32_t>(RHSLength) < IndexDiff)2205 return false;2206 RHSStr = RHSStr.drop_front(IndexDiff);2207 }2208 2209 unsigned ShorterCharWidth;2210 StringRef Shorter;2211 StringRef Longer;2212 if (LHSLength < RHSLength) {2213 ShorterCharWidth = LHS.elemSize();2214 Shorter = LHSStr;2215 Longer = RHSStr;2216 } else {2217 ShorterCharWidth = RHS.elemSize();2218 Shorter = RHSStr;2219 Longer = LHSStr;2220 }2221 2222 // The null terminator isn't included in the string data, so check for it2223 // manually. If the longer string doesn't have a null terminator where the2224 // shorter string ends, they aren't potentially overlapping.2225 for (unsigned NullByte : llvm::seq(ShorterCharWidth)) {2226 if (Shorter.size() + NullByte >= Longer.size())2227 break;2228 if (Longer[Shorter.size() + NullByte])2229 return false;2230 }2231 return Shorter == Longer.take_front(Shorter.size());2232}2233 2234static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr,2235 PrimType T) {2236 2237 if (T == PT_IntAPS) {2238 auto &Val = Ptr.deref<IntegralAP<true>>();2239 if (!Val.singleWord()) {2240 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2241 Val.take(NewMemory);2242 }2243 } else if (T == PT_IntAP) {2244 auto &Val = Ptr.deref<IntegralAP<false>>();2245 if (!Val.singleWord()) {2246 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2247 Val.take(NewMemory);2248 }2249 } else if (T == PT_Float) {2250 auto &Val = Ptr.deref<Floating>();2251 if (!Val.singleWord()) {2252 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2253 Val.take(NewMemory);2254 }2255 }2256}2257 2258template <typename T>2259static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr) {2260 assert(needsAlloc<T>());2261 auto &Val = Ptr.deref<T>();2262 if (!Val.singleWord()) {2263 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];2264 Val.take(NewMemory);2265 }2266}2267 2268static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) {2269 if (const Record *R = Ptr.getRecord()) {2270 for (const Record::Field &Fi : R->fields()) {2271 if (Fi.Desc->isPrimitive()) {2272 TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), {2273 copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));2274 });2275 copyPrimitiveMemory(S, Ptr.atField(Fi.Offset), Fi.Desc->getPrimType());2276 } else2277 finishGlobalRecurse(S, Ptr.atField(Fi.Offset));2278 }2279 return;2280 }2281 2282 if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {2283 unsigned NumElems = D->getNumElems();2284 if (NumElems == 0)2285 return;2286 2287 if (D->isPrimitiveArray()) {2288 PrimType PT = D->getPrimType();2289 if (!needsAlloc(PT))2290 return;2291 assert(NumElems >= 1);2292 const Pointer EP = Ptr.atIndex(0);2293 bool AllSingleWord = true;2294 TYPE_SWITCH_ALLOC(PT, {2295 if (!EP.deref<T>().singleWord()) {2296 copyPrimitiveMemory<T>(S, EP);2297 AllSingleWord = false;2298 }2299 });2300 if (AllSingleWord)2301 return;2302 for (unsigned I = 1; I != D->getNumElems(); ++I) {2303 const Pointer EP = Ptr.atIndex(I);2304 copyPrimitiveMemory(S, EP, PT);2305 }2306 } else {2307 assert(D->isCompositeArray());2308 for (unsigned I = 0; I != D->getNumElems(); ++I) {2309 const Pointer EP = Ptr.atIndex(I).narrow();2310 finishGlobalRecurse(S, EP);2311 }2312 }2313 }2314}2315 2316bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {2317 const Pointer &Ptr = S.Stk.pop<Pointer>();2318 2319 finishGlobalRecurse(S, Ptr);2320 if (Ptr.canBeInitialized()) {2321 Ptr.initialize();2322 Ptr.activate();2323 }2324 2325 return true;2326}2327 2328// https://github.com/llvm/llvm-project/issues/1025132329#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)2330#pragma optimize("", off)2331#endif2332bool Interpret(InterpState &S) {2333 // The current stack frame when we started Interpret().2334 // This is being used by the ops to determine wheter2335 // to return from this function and thus terminate2336 // interpretation.2337 const InterpFrame *StartFrame = S.Current;2338 assert(!S.Current->isRoot());2339 CodePtr PC = S.Current->getPC();2340 2341 // Empty program.2342 if (!PC)2343 return true;2344 2345 for (;;) {2346 auto Op = PC.read<Opcode>();2347 CodePtr OpPC = PC;2348 2349 switch (Op) {2350#define GET_INTERP2351#include "Opcodes.inc"2352#undef GET_INTERP2353 }2354 }2355}2356// https://github.com/llvm/llvm-project/issues/1025132357#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)2358#pragma optimize("", on)2359#endif2360 2361} // namespace interp2362} // namespace clang2363