1bdd1243dSDimitry Andric //===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "Interp.h" 10a7dea167SDimitry Andric #include "Function.h" 11a7dea167SDimitry Andric #include "InterpFrame.h" 120fca6ea1SDimitry Andric #include "InterpShared.h" 13a7dea167SDimitry Andric #include "InterpStack.h" 14a7dea167SDimitry Andric #include "Opcode.h" 15a7dea167SDimitry Andric #include "PrimType.h" 16a7dea167SDimitry Andric #include "Program.h" 17a7dea167SDimitry Andric #include "State.h" 18a7dea167SDimitry Andric #include "clang/AST/ASTContext.h" 19a7dea167SDimitry Andric #include "clang/AST/ASTDiagnostic.h" 20a7dea167SDimitry Andric #include "clang/AST/CXXInheritance.h" 210fca6ea1SDimitry Andric #include "clang/AST/DeclObjC.h" 22a7dea167SDimitry Andric #include "clang/AST/Expr.h" 23a7dea167SDimitry Andric #include "clang/AST/ExprCXX.h" 24a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h" 250fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h" 260fca6ea1SDimitry Andric #include <limits> 270fca6ea1SDimitry Andric #include <vector> 280fca6ea1SDimitry Andric 290fca6ea1SDimitry Andric using namespace clang; 30a7dea167SDimitry Andric 31a7dea167SDimitry Andric using namespace clang; 32a7dea167SDimitry Andric using namespace clang::interp; 33a7dea167SDimitry Andric 34a7dea167SDimitry Andric static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) { 35a7dea167SDimitry Andric llvm::report_fatal_error("Interpreter cannot return values"); 36a7dea167SDimitry Andric } 37a7dea167SDimitry Andric 38a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 39a7dea167SDimitry Andric // Jmp, Jt, Jf 40a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 41a7dea167SDimitry Andric 42a7dea167SDimitry Andric static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) { 43a7dea167SDimitry Andric PC += Offset; 44a7dea167SDimitry Andric return true; 45a7dea167SDimitry Andric } 46a7dea167SDimitry Andric 47a7dea167SDimitry Andric static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) { 48a7dea167SDimitry Andric if (S.Stk.pop<bool>()) { 49a7dea167SDimitry Andric PC += Offset; 50a7dea167SDimitry Andric } 51a7dea167SDimitry Andric return true; 52a7dea167SDimitry Andric } 53a7dea167SDimitry Andric 54a7dea167SDimitry Andric static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { 55a7dea167SDimitry Andric if (!S.Stk.pop<bool>()) { 56a7dea167SDimitry Andric PC += Offset; 57a7dea167SDimitry Andric } 58a7dea167SDimitry Andric return true; 59a7dea167SDimitry Andric } 60a7dea167SDimitry Andric 610fca6ea1SDimitry Andric static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, 620fca6ea1SDimitry Andric const ValueDecl *VD) { 630fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 640fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; 650fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); 660fca6ea1SDimitry Andric } 670fca6ea1SDimitry Andric 680fca6ea1SDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, 690fca6ea1SDimitry Andric const ValueDecl *VD); 700fca6ea1SDimitry Andric static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, 710fca6ea1SDimitry Andric const ValueDecl *D) { 720fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 730fca6ea1SDimitry Andric 740fca6ea1SDimitry Andric if (isa<ParmVarDecl>(D)) { 750fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus11) { 760fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; 770fca6ea1SDimitry Andric S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); 780fca6ea1SDimitry Andric } else { 790fca6ea1SDimitry Andric S.FFDiag(E); 800fca6ea1SDimitry Andric } 810fca6ea1SDimitry Andric return false; 820fca6ea1SDimitry Andric } 830fca6ea1SDimitry Andric 840fca6ea1SDimitry Andric if (!D->getType().isConstQualified()) 850fca6ea1SDimitry Andric diagnoseNonConstVariable(S, OpPC, D); 860fca6ea1SDimitry Andric else if (const auto *VD = dyn_cast<VarDecl>(D); 870fca6ea1SDimitry Andric VD && !VD->getAnyInitializer()) 880fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD); 890fca6ea1SDimitry Andric 900fca6ea1SDimitry Andric return false; 910fca6ea1SDimitry Andric } 920fca6ea1SDimitry Andric 937a6dacacSDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, 947a6dacacSDimitry Andric const ValueDecl *VD) { 957a6dacacSDimitry Andric if (!S.getLangOpts().CPlusPlus) 967a6dacacSDimitry Andric return; 977a6dacacSDimitry Andric 987a6dacacSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 990fca6ea1SDimitry Andric if (const auto *VarD = dyn_cast<VarDecl>(VD); 1000fca6ea1SDimitry Andric VarD && VarD->getType().isConstQualified() && 1010fca6ea1SDimitry Andric !VarD->getAnyInitializer()) { 1020fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD); 1030fca6ea1SDimitry Andric return; 1040fca6ea1SDimitry Andric } 1057a6dacacSDimitry Andric 1060fca6ea1SDimitry Andric // Rather random, but this is to match the diagnostic output of the current 1070fca6ea1SDimitry Andric // interpreter. 1080fca6ea1SDimitry Andric if (isa<ObjCIvarDecl>(VD)) 1090fca6ea1SDimitry Andric return; 1100fca6ea1SDimitry Andric 1110fca6ea1SDimitry Andric if (VD->getType()->isIntegralOrEnumerationType()) { 1127a6dacacSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD; 1130fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at); 1140fca6ea1SDimitry Andric return; 1150fca6ea1SDimitry Andric } 1160fca6ea1SDimitry Andric 1177a6dacacSDimitry Andric S.FFDiag(Loc, 1180fca6ea1SDimitry Andric S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr 1197a6dacacSDimitry Andric : diag::note_constexpr_ltor_non_integral, 1207a6dacacSDimitry Andric 1) 1217a6dacacSDimitry Andric << VD << VD->getType(); 1227a6dacacSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at); 1237a6dacacSDimitry Andric } 1247a6dacacSDimitry Andric 125a7dea167SDimitry Andric static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 126a7dea167SDimitry Andric AccessKinds AK) { 127a7dea167SDimitry Andric if (Ptr.isActive()) 128a7dea167SDimitry Andric return true; 129a7dea167SDimitry Andric 130a7dea167SDimitry Andric // Get the inactive field descriptor. 131a7dea167SDimitry Andric const FieldDecl *InactiveField = Ptr.getField(); 132a7dea167SDimitry Andric 133a7dea167SDimitry Andric // Walk up the pointer chain to find the union which is not active. 134a7dea167SDimitry Andric Pointer U = Ptr.getBase(); 135a7dea167SDimitry Andric while (!U.isActive()) { 136a7dea167SDimitry Andric U = U.getBase(); 137a7dea167SDimitry Andric } 138a7dea167SDimitry Andric 139a7dea167SDimitry Andric // Find the active field of the union. 14006c3fb27SDimitry Andric const Record *R = U.getRecord(); 141a7dea167SDimitry Andric assert(R && R->isUnion() && "Not a union"); 142a7dea167SDimitry Andric const FieldDecl *ActiveField = nullptr; 143a7dea167SDimitry Andric for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) { 144a7dea167SDimitry Andric const Pointer &Field = U.atField(R->getField(I)->Offset); 145a7dea167SDimitry Andric if (Field.isActive()) { 146a7dea167SDimitry Andric ActiveField = Field.getField(); 147a7dea167SDimitry Andric break; 148a7dea167SDimitry Andric } 149a7dea167SDimitry Andric } 150a7dea167SDimitry Andric 151a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 152a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member) 153a7dea167SDimitry Andric << AK << InactiveField << !ActiveField << ActiveField; 154a7dea167SDimitry Andric return false; 155a7dea167SDimitry Andric } 156a7dea167SDimitry Andric 157a7dea167SDimitry Andric static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 158a7dea167SDimitry Andric AccessKinds AK) { 159a7dea167SDimitry Andric if (auto ID = Ptr.getDeclID()) { 160a7dea167SDimitry Andric if (!Ptr.isStaticTemporary()) 161a7dea167SDimitry Andric return true; 162a7dea167SDimitry Andric 163a7dea167SDimitry Andric if (Ptr.getDeclDesc()->getType().isConstQualified()) 164a7dea167SDimitry Andric return true; 165a7dea167SDimitry Andric 166a7dea167SDimitry Andric if (S.P.getCurrentDecl() == ID) 167a7dea167SDimitry Andric return true; 168a7dea167SDimitry Andric 169a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 170a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; 171a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 172a7dea167SDimitry Andric return false; 173a7dea167SDimitry Andric } 174a7dea167SDimitry Andric return true; 175a7dea167SDimitry Andric } 176a7dea167SDimitry Andric 177a7dea167SDimitry Andric static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 178a7dea167SDimitry Andric if (auto ID = Ptr.getDeclID()) { 179a7dea167SDimitry Andric if (!Ptr.isStatic()) 180a7dea167SDimitry Andric return true; 181a7dea167SDimitry Andric 182a7dea167SDimitry Andric if (S.P.getCurrentDecl() == ID) 183a7dea167SDimitry Andric return true; 184a7dea167SDimitry Andric 185a7dea167SDimitry Andric S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global); 186a7dea167SDimitry Andric return false; 187a7dea167SDimitry Andric } 188a7dea167SDimitry Andric return true; 189a7dea167SDimitry Andric } 190a7dea167SDimitry Andric 191a7dea167SDimitry Andric namespace clang { 192a7dea167SDimitry Andric namespace interp { 1935f757f3fSDimitry Andric static void popArg(InterpState &S, const Expr *Arg) { 1940fca6ea1SDimitry Andric PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr); 1955f757f3fSDimitry Andric TYPE_SWITCH(Ty, S.Stk.discard<T>()); 1965f757f3fSDimitry Andric } 1975f757f3fSDimitry Andric 1985f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { 1995f757f3fSDimitry Andric assert(S.Current); 2005f757f3fSDimitry Andric const Function *CurFunc = S.Current->getFunction(); 2015f757f3fSDimitry Andric assert(CurFunc); 2025f757f3fSDimitry Andric 2035f757f3fSDimitry Andric if (CurFunc->isUnevaluatedBuiltin()) 2045f757f3fSDimitry Andric return; 2055f757f3fSDimitry Andric 206297eecfbSDimitry Andric // Some builtin functions require us to only look at the call site, since 207297eecfbSDimitry Andric // the classified parameter types do not match. 208297eecfbSDimitry Andric if (CurFunc->isBuiltin()) { 209297eecfbSDimitry Andric const auto *CE = 210297eecfbSDimitry Andric cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC())); 211297eecfbSDimitry Andric for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) { 212297eecfbSDimitry Andric const Expr *A = CE->getArg(I); 213297eecfbSDimitry Andric popArg(S, A); 214297eecfbSDimitry Andric } 215297eecfbSDimitry Andric return; 216297eecfbSDimitry Andric } 217297eecfbSDimitry Andric 2185f757f3fSDimitry Andric if (S.Current->Caller && CurFunc->isVariadic()) { 2195f757f3fSDimitry Andric // CallExpr we're look for is at the return PC of the current function, i.e. 2205f757f3fSDimitry Andric // in the caller. 2215f757f3fSDimitry Andric // This code path should be executed very rarely. 2220fca6ea1SDimitry Andric unsigned NumVarArgs; 2230fca6ea1SDimitry Andric const Expr *const *Args = nullptr; 2240fca6ea1SDimitry Andric unsigned NumArgs = 0; 2250fca6ea1SDimitry Andric const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC()); 2260fca6ea1SDimitry Andric if (const auto *CE = dyn_cast<CallExpr>(CallSite)) { 2270fca6ea1SDimitry Andric Args = CE->getArgs(); 2280fca6ea1SDimitry Andric NumArgs = CE->getNumArgs(); 2290fca6ea1SDimitry Andric } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) { 2300fca6ea1SDimitry Andric Args = CE->getArgs(); 2310fca6ea1SDimitry Andric NumArgs = CE->getNumArgs(); 2320fca6ea1SDimitry Andric } else 2330fca6ea1SDimitry Andric assert(false && "Can't get arguments from that expression type"); 2340fca6ea1SDimitry Andric 2350fca6ea1SDimitry Andric assert(NumArgs >= CurFunc->getNumWrittenParams()); 2360fca6ea1SDimitry Andric NumVarArgs = NumArgs - CurFunc->getNumWrittenParams(); 2370fca6ea1SDimitry Andric for (unsigned I = 0; I != NumVarArgs; ++I) { 2380fca6ea1SDimitry Andric const Expr *A = Args[NumArgs - 1 - I]; 2395f757f3fSDimitry Andric popArg(S, A); 2405f757f3fSDimitry Andric } 2415f757f3fSDimitry Andric } 2420fca6ea1SDimitry Andric 2435f757f3fSDimitry Andric // And in any case, remove the fixed parameters (the non-variadic ones) 2445f757f3fSDimitry Andric // at the end. 2455f757f3fSDimitry Andric S.Current->popArgs(); 2465f757f3fSDimitry Andric } 247a7dea167SDimitry Andric 248a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 249a7dea167SDimitry Andric if (!Ptr.isExtern()) 250a7dea167SDimitry Andric return true; 251a7dea167SDimitry Andric 2520fca6ea1SDimitry Andric if (Ptr.isInitialized() || 2530fca6ea1SDimitry Andric (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)) 2540fca6ea1SDimitry Andric return true; 2550fca6ea1SDimitry Andric 2565f757f3fSDimitry Andric if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { 25706c3fb27SDimitry Andric const auto *VD = Ptr.getDeclDesc()->asValueDecl(); 2587a6dacacSDimitry Andric diagnoseNonConstVariable(S, OpPC, VD); 259a7dea167SDimitry Andric } 260a7dea167SDimitry Andric return false; 261a7dea167SDimitry Andric } 262a7dea167SDimitry Andric 263a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 264a7dea167SDimitry Andric if (!Ptr.isUnknownSizeArray()) 265a7dea167SDimitry Andric return true; 266a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 267a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_unsized_array_indexed); 268a7dea167SDimitry Andric return false; 269a7dea167SDimitry Andric } 270a7dea167SDimitry Andric 271a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 272a7dea167SDimitry Andric AccessKinds AK) { 273a7dea167SDimitry Andric if (Ptr.isZero()) { 274bdd1243dSDimitry Andric const auto &Src = S.Current->getSource(OpPC); 275a7dea167SDimitry Andric 276a7dea167SDimitry Andric if (Ptr.isField()) 277a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; 278a7dea167SDimitry Andric else 279a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_access_null) << AK; 280a7dea167SDimitry Andric 281a7dea167SDimitry Andric return false; 282a7dea167SDimitry Andric } 283a7dea167SDimitry Andric 284a7dea167SDimitry Andric if (!Ptr.isLive()) { 285bdd1243dSDimitry Andric const auto &Src = S.Current->getSource(OpPC); 286a7dea167SDimitry Andric bool IsTemp = Ptr.isTemporary(); 287a7dea167SDimitry Andric 288a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp; 289a7dea167SDimitry Andric 290a7dea167SDimitry Andric if (IsTemp) 291a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 292a7dea167SDimitry Andric else 293a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at); 294a7dea167SDimitry Andric 295a7dea167SDimitry Andric return false; 296a7dea167SDimitry Andric } 297a7dea167SDimitry Andric 298a7dea167SDimitry Andric return true; 299a7dea167SDimitry Andric } 300a7dea167SDimitry Andric 3017a6dacacSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 3027a6dacacSDimitry Andric assert(Desc); 3037a6dacacSDimitry Andric 3047a6dacacSDimitry Andric auto IsConstType = [&S](const VarDecl *VD) -> bool { 3057a6dacacSDimitry Andric if (VD->isConstexpr()) 3067a6dacacSDimitry Andric return true; 3077a6dacacSDimitry Andric 3087a6dacacSDimitry Andric QualType T = VD->getType(); 3090fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11) 3100fca6ea1SDimitry Andric return (T->isSignedIntegerOrEnumerationType() || 3110fca6ea1SDimitry Andric T->isUnsignedIntegerOrEnumerationType()) && 3120fca6ea1SDimitry Andric T.isConstQualified(); 3130fca6ea1SDimitry Andric 3147a6dacacSDimitry Andric if (T.isConstQualified()) 3157a6dacacSDimitry Andric return true; 3167a6dacacSDimitry Andric 3177a6dacacSDimitry Andric if (const auto *RT = T->getAs<ReferenceType>()) 3187a6dacacSDimitry Andric return RT->getPointeeType().isConstQualified(); 3197a6dacacSDimitry Andric 3207a6dacacSDimitry Andric if (const auto *PT = T->getAs<PointerType>()) 3217a6dacacSDimitry Andric return PT->getPointeeType().isConstQualified(); 3227a6dacacSDimitry Andric 3237a6dacacSDimitry Andric return false; 3247a6dacacSDimitry Andric }; 3257a6dacacSDimitry Andric 3260fca6ea1SDimitry Andric if (const auto *D = Desc->asVarDecl(); 3270fca6ea1SDimitry Andric D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) { 3280fca6ea1SDimitry Andric diagnoseNonConstVariable(S, OpPC, D); 3297a6dacacSDimitry Andric return S.inConstantContext(); 3307a6dacacSDimitry Andric } 3317a6dacacSDimitry Andric 3327a6dacacSDimitry Andric return true; 3337a6dacacSDimitry Andric } 3347a6dacacSDimitry Andric 3357a6dacacSDimitry Andric static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 3360fca6ea1SDimitry Andric if (Ptr.isIntegralPointer()) 3370fca6ea1SDimitry Andric return true; 3387a6dacacSDimitry Andric return CheckConstant(S, OpPC, Ptr.getDeclDesc()); 3397a6dacacSDimitry Andric } 3407a6dacacSDimitry Andric 341a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 342a7dea167SDimitry Andric CheckSubobjectKind CSK) { 343a7dea167SDimitry Andric if (!Ptr.isZero()) 344a7dea167SDimitry Andric return true; 345a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 3460fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_null_subobject) 3470fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC); 3480fca6ea1SDimitry Andric 349a7dea167SDimitry Andric return false; 350a7dea167SDimitry Andric } 351a7dea167SDimitry Andric 352a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 353a7dea167SDimitry Andric AccessKinds AK) { 354a7dea167SDimitry Andric if (!Ptr.isOnePastEnd()) 355a7dea167SDimitry Andric return true; 356a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 3570fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_past_end) 3580fca6ea1SDimitry Andric << AK << S.Current->getRange(OpPC); 359a7dea167SDimitry Andric return false; 360a7dea167SDimitry Andric } 361a7dea167SDimitry Andric 362a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 363a7dea167SDimitry Andric CheckSubobjectKind CSK) { 364a7dea167SDimitry Andric if (!Ptr.isElementPastEnd()) 365a7dea167SDimitry Andric return true; 366a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 3670fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) 3680fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC); 369a7dea167SDimitry Andric return false; 370a7dea167SDimitry Andric } 371a7dea167SDimitry Andric 3725f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 3735f757f3fSDimitry Andric CheckSubobjectKind CSK) { 3745f757f3fSDimitry Andric if (!Ptr.isOnePastEnd()) 3755f757f3fSDimitry Andric return true; 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 3780fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) 3790fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC); 3800fca6ea1SDimitry Andric return false; 3810fca6ea1SDimitry Andric } 3820fca6ea1SDimitry Andric 3830fca6ea1SDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 3840fca6ea1SDimitry Andric uint32_t Offset) { 3850fca6ea1SDimitry Andric uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize(); 3860fca6ea1SDimitry Andric uint32_t PtrOffset = Ptr.getByteOffset(); 3870fca6ea1SDimitry Andric 3880fca6ea1SDimitry Andric // We subtract Offset from PtrOffset. The result must be at least 3890fca6ea1SDimitry Andric // MinOffset. 3900fca6ea1SDimitry Andric if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset) 3910fca6ea1SDimitry Andric return true; 3920fca6ea1SDimitry Andric 3930fca6ea1SDimitry Andric const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC)); 3940fca6ea1SDimitry Andric QualType TargetQT = E->getType()->getPointeeType(); 3950fca6ea1SDimitry Andric QualType MostDerivedQT = Ptr.getDeclPtr().getType(); 3960fca6ea1SDimitry Andric 3970fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_downcast) 3980fca6ea1SDimitry Andric << MostDerivedQT << TargetQT; 3990fca6ea1SDimitry Andric 4005f757f3fSDimitry Andric return false; 4015f757f3fSDimitry Andric } 4025f757f3fSDimitry Andric 403a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 404a7dea167SDimitry Andric assert(Ptr.isLive() && "Pointer is not live"); 4050fca6ea1SDimitry Andric if (!Ptr.isConst() || Ptr.isMutable()) 40606c3fb27SDimitry Andric return true; 40706c3fb27SDimitry Andric 40806c3fb27SDimitry Andric // The This pointer is writable in constructors and destructors, 40906c3fb27SDimitry Andric // even if isConst() returns true. 4100fca6ea1SDimitry Andric // TODO(perf): We could be hitting this code path quite a lot in complex 4110fca6ea1SDimitry Andric // constructors. Is there a better way to do this? 4120fca6ea1SDimitry Andric if (S.Current->getFunction()) { 4130fca6ea1SDimitry Andric for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) { 4140fca6ea1SDimitry Andric if (const Function *Func = Frame->getFunction(); 41506c3fb27SDimitry Andric Func && (Func->isConstructor() || Func->isDestructor()) && 4160fca6ea1SDimitry Andric Ptr.block() == Frame->getThis().block()) { 417a7dea167SDimitry Andric return true; 418a7dea167SDimitry Andric } 4190fca6ea1SDimitry Andric } 4200fca6ea1SDimitry Andric } 4210fca6ea1SDimitry Andric 4220fca6ea1SDimitry Andric if (!Ptr.isBlockPointer()) 4230fca6ea1SDimitry Andric return false; 424a7dea167SDimitry Andric 425a7dea167SDimitry Andric const QualType Ty = Ptr.getType(); 426a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 427a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; 428a7dea167SDimitry Andric return false; 429a7dea167SDimitry Andric } 430a7dea167SDimitry Andric 431a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 432a7dea167SDimitry Andric assert(Ptr.isLive() && "Pointer is not live"); 4330fca6ea1SDimitry Andric if (!Ptr.isMutable()) 434a7dea167SDimitry Andric return true; 4350fca6ea1SDimitry Andric 4360fca6ea1SDimitry Andric // In C++14 onwards, it is permitted to read a mutable member whose 4370fca6ea1SDimitry Andric // lifetime began within the evaluation. 4380fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus14 && 4390fca6ea1SDimitry Andric Ptr.block()->getEvalID() == S.Ctx.getEvalID()) 4400fca6ea1SDimitry Andric return true; 441a7dea167SDimitry Andric 442a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 443a7dea167SDimitry Andric const FieldDecl *Field = Ptr.getField(); 444a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field; 445a7dea167SDimitry Andric S.Note(Field->getLocation(), diag::note_declared_at); 446a7dea167SDimitry Andric return false; 447a7dea167SDimitry Andric } 448a7dea167SDimitry Andric 4490fca6ea1SDimitry Andric bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 4500fca6ea1SDimitry Andric AccessKinds AK) { 4510fca6ea1SDimitry Andric assert(Ptr.isLive()); 4520fca6ea1SDimitry Andric 4530fca6ea1SDimitry Andric // FIXME: This check here might be kinda expensive. Maybe it would be better 4540fca6ea1SDimitry Andric // to have another field in InlineDescriptor for this? 4550fca6ea1SDimitry Andric if (!Ptr.isBlockPointer()) 4560fca6ea1SDimitry Andric return true; 4570fca6ea1SDimitry Andric 4580fca6ea1SDimitry Andric QualType PtrType = Ptr.getType(); 4590fca6ea1SDimitry Andric if (!PtrType.isVolatileQualified()) 4600fca6ea1SDimitry Andric return true; 4610fca6ea1SDimitry Andric 4620fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 4630fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus) 4640fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType; 4650fca6ea1SDimitry Andric else 4660fca6ea1SDimitry Andric S.FFDiag(Loc); 4670fca6ea1SDimitry Andric return false; 4680fca6ea1SDimitry Andric } 4690fca6ea1SDimitry Andric 47006c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 47106c3fb27SDimitry Andric AccessKinds AK) { 4720fca6ea1SDimitry Andric assert(Ptr.isLive()); 4730fca6ea1SDimitry Andric 47406c3fb27SDimitry Andric if (Ptr.isInitialized()) 47506c3fb27SDimitry Andric return true; 47606c3fb27SDimitry Andric 4770fca6ea1SDimitry Andric if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); 4780fca6ea1SDimitry Andric VD && VD->hasGlobalStorage()) { 4790fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 4800fca6ea1SDimitry Andric if (VD->getAnyInitializer()) { 4810fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; 4820fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at); 4830fca6ea1SDimitry Andric } else { 4840fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD); 4850fca6ea1SDimitry Andric } 4860fca6ea1SDimitry Andric return false; 4870fca6ea1SDimitry Andric } 4880fca6ea1SDimitry Andric 48906c3fb27SDimitry Andric if (!S.checkingPotentialConstantExpression()) { 4905f757f3fSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) 4915f757f3fSDimitry Andric << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); 49206c3fb27SDimitry Andric } 49306c3fb27SDimitry Andric return false; 49406c3fb27SDimitry Andric } 49506c3fb27SDimitry Andric 4960fca6ea1SDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 4970fca6ea1SDimitry Andric if (Ptr.isInitialized()) 4980fca6ea1SDimitry Andric return true; 4990fca6ea1SDimitry Andric 5000fca6ea1SDimitry Andric assert(S.getLangOpts().CPlusPlus); 5010fca6ea1SDimitry Andric const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl()); 5020fca6ea1SDimitry Andric if ((!VD->hasConstantInitialization() && 5030fca6ea1SDimitry Andric VD->mightBeUsableInConstantExpressions(S.getCtx())) || 5040fca6ea1SDimitry Andric (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 && 5050fca6ea1SDimitry Andric !VD->hasICEInitializer(S.getCtx()))) { 5060fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 5070fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; 5080fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at); 5090fca6ea1SDimitry Andric } 5100fca6ea1SDimitry Andric return false; 5110fca6ea1SDimitry Andric } 5120fca6ea1SDimitry Andric 5130fca6ea1SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 5140fca6ea1SDimitry Andric AccessKinds AK) { 5150fca6ea1SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK)) 516a7dea167SDimitry Andric return false; 5177a6dacacSDimitry Andric if (!CheckConstant(S, OpPC, Ptr)) 5187a6dacacSDimitry Andric return false; 5197a6dacacSDimitry Andric 5200fca6ea1SDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK)) 5211db9f3b2SDimitry Andric return false; 522a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr)) 523a7dea167SDimitry Andric return false; 5240fca6ea1SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK)) 525a7dea167SDimitry Andric return false; 5260fca6ea1SDimitry Andric if (!CheckActive(S, OpPC, Ptr, AK)) 527a7dea167SDimitry Andric return false; 5280fca6ea1SDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK)) 529a7dea167SDimitry Andric return false; 5300fca6ea1SDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK)) 531a7dea167SDimitry Andric return false; 532a7dea167SDimitry Andric if (!CheckMutable(S, OpPC, Ptr)) 533a7dea167SDimitry Andric return false; 5340fca6ea1SDimitry Andric if (!CheckVolatile(S, OpPC, Ptr, AK)) 5350fca6ea1SDimitry Andric return false; 536a7dea167SDimitry Andric return true; 537a7dea167SDimitry Andric } 538a7dea167SDimitry Andric 539a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 540a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 541a7dea167SDimitry Andric return false; 5420fca6ea1SDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Assign)) 5430fca6ea1SDimitry Andric return false; 544a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr)) 545a7dea167SDimitry Andric return false; 546a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 547a7dea167SDimitry Andric return false; 548a7dea167SDimitry Andric if (!CheckGlobal(S, OpPC, Ptr)) 549a7dea167SDimitry Andric return false; 550a7dea167SDimitry Andric if (!CheckConst(S, OpPC, Ptr)) 551a7dea167SDimitry Andric return false; 552a7dea167SDimitry Andric return true; 553a7dea167SDimitry Andric } 554a7dea167SDimitry Andric 555a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 556a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) 557a7dea167SDimitry Andric return false; 5580fca6ea1SDimitry Andric if (!Ptr.isDummy()) { 559a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr)) 560a7dea167SDimitry Andric return false; 561a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) 562a7dea167SDimitry Andric return false; 5630fca6ea1SDimitry Andric } 564a7dea167SDimitry Andric return true; 565a7dea167SDimitry Andric } 566a7dea167SDimitry Andric 567a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 568a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 569a7dea167SDimitry Andric return false; 570a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 571a7dea167SDimitry Andric return false; 572a7dea167SDimitry Andric return true; 573a7dea167SDimitry Andric } 574a7dea167SDimitry Andric 575bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { 576a7dea167SDimitry Andric 57706c3fb27SDimitry Andric if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { 578bdd1243dSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 579a7dea167SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_virtual_call); 580a7dea167SDimitry Andric return false; 581a7dea167SDimitry Andric } 582a7dea167SDimitry Andric 5830fca6ea1SDimitry Andric if (F->isConstexpr() && F->hasBody() && 5840fca6ea1SDimitry Andric (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>())) 5850fca6ea1SDimitry Andric return true; 5860fca6ea1SDimitry Andric 5870fca6ea1SDimitry Andric // Implicitly constexpr. 5880fca6ea1SDimitry Andric if (F->isLambdaStaticInvoker()) 5890fca6ea1SDimitry Andric return true; 5900fca6ea1SDimitry Andric 591bdd1243dSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 592a7dea167SDimitry Andric if (S.getLangOpts().CPlusPlus11) { 593a7dea167SDimitry Andric const FunctionDecl *DiagDecl = F->getDecl(); 594a7dea167SDimitry Andric 5950fca6ea1SDimitry Andric // Invalid decls have been diagnosed before. 5960fca6ea1SDimitry Andric if (DiagDecl->isInvalidDecl()) 5970fca6ea1SDimitry Andric return false; 5980fca6ea1SDimitry Andric 599a7dea167SDimitry Andric // If this function is not constexpr because it is an inherited 600a7dea167SDimitry Andric // non-constexpr constructor, diagnose that directly. 60106c3fb27SDimitry Andric const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); 602a7dea167SDimitry Andric if (CD && CD->isInheritingConstructor()) { 60306c3fb27SDimitry Andric const auto *Inherited = CD->getInheritedConstructor().getConstructor(); 604a7dea167SDimitry Andric if (!Inherited->isConstexpr()) 605a7dea167SDimitry Andric DiagDecl = CD = Inherited; 606a7dea167SDimitry Andric } 607a7dea167SDimitry Andric 608a7dea167SDimitry Andric // FIXME: If DiagDecl is an implicitly-declared special member function 609a7dea167SDimitry Andric // or an inheriting constructor, we should be much more explicit about why 610a7dea167SDimitry Andric // it's not constexpr. 6115f757f3fSDimitry Andric if (CD && CD->isInheritingConstructor()) { 612a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) 613a7dea167SDimitry Andric << CD->getInheritedConstructor().getConstructor()->getParent(); 6145f757f3fSDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at); 6155f757f3fSDimitry Andric } else { 6165f757f3fSDimitry Andric // Don't emit anything if the function isn't defined and we're checking 6175f757f3fSDimitry Andric // for a constant expression. It might be defined at the point we're 6185f757f3fSDimitry Andric // actually calling it. 6190fca6ea1SDimitry Andric bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; 6200fca6ea1SDimitry Andric if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() && 6210fca6ea1SDimitry Andric S.checkingPotentialConstantExpression()) 6220fca6ea1SDimitry Andric return false; 6230fca6ea1SDimitry Andric 6240fca6ea1SDimitry Andric // If the declaration is defined, declared 'constexpr' _and_ has a body, 6250fca6ea1SDimitry Andric // the below diagnostic doesn't add anything useful. 6260fca6ea1SDimitry Andric if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && 6270fca6ea1SDimitry Andric DiagDecl->hasBody()) 6285f757f3fSDimitry Andric return false; 6295f757f3fSDimitry Andric 630a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) 631a7dea167SDimitry Andric << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; 632a7dea167SDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at); 6335f757f3fSDimitry Andric } 634a7dea167SDimitry Andric } else { 635a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 636a7dea167SDimitry Andric } 637a7dea167SDimitry Andric 6380fca6ea1SDimitry Andric return false; 639a7dea167SDimitry Andric } 640a7dea167SDimitry Andric 64106c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC) { 64206c3fb27SDimitry Andric if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) { 64306c3fb27SDimitry Andric S.FFDiag(S.Current->getSource(OpPC), 64406c3fb27SDimitry Andric diag::note_constexpr_depth_limit_exceeded) 64506c3fb27SDimitry Andric << S.getLangOpts().ConstexprCallDepth; 64606c3fb27SDimitry Andric return false; 64706c3fb27SDimitry Andric } 64806c3fb27SDimitry Andric 64906c3fb27SDimitry Andric return true; 65006c3fb27SDimitry Andric } 65106c3fb27SDimitry Andric 652a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) { 653a7dea167SDimitry Andric if (!This.isZero()) 654a7dea167SDimitry Andric return true; 655a7dea167SDimitry Andric 656a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 657a7dea167SDimitry Andric 658a7dea167SDimitry Andric bool IsImplicit = false; 65906c3fb27SDimitry Andric if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr())) 660a7dea167SDimitry Andric IsImplicit = E->isImplicit(); 661a7dea167SDimitry Andric 662a7dea167SDimitry Andric if (S.getLangOpts().CPlusPlus11) 663a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit; 664a7dea167SDimitry Andric else 665a7dea167SDimitry Andric S.FFDiag(Loc); 666a7dea167SDimitry Andric 667a7dea167SDimitry Andric return false; 668a7dea167SDimitry Andric } 669a7dea167SDimitry Andric 670a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) { 6717a6dacacSDimitry Andric if (!MD->isPureVirtual()) 672a7dea167SDimitry Andric return true; 673a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 674a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD; 675a7dea167SDimitry Andric S.Note(MD->getLocation(), diag::note_declared_at); 676a7dea167SDimitry Andric return false; 677a7dea167SDimitry Andric } 678bdd1243dSDimitry Andric 6795f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, 6805f757f3fSDimitry Andric APFloat::opStatus Status) { 6815f757f3fSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 6825f757f3fSDimitry Andric 6835f757f3fSDimitry Andric // [expr.pre]p4: 6845f757f3fSDimitry Andric // If during the evaluation of an expression, the result is not 6855f757f3fSDimitry Andric // mathematically defined [...], the behavior is undefined. 6865f757f3fSDimitry Andric // FIXME: C++ rules require us to not conform to IEEE 754 here. 6875f757f3fSDimitry Andric if (Result.isNan()) { 6885f757f3fSDimitry Andric S.CCEDiag(E, diag::note_constexpr_float_arithmetic) 6895f757f3fSDimitry Andric << /*NaN=*/true << S.Current->getRange(OpPC); 6905f757f3fSDimitry Andric return S.noteUndefinedBehavior(); 6915f757f3fSDimitry Andric } 6925f757f3fSDimitry Andric 69306c3fb27SDimitry Andric // In a constant context, assume that any dynamic rounding mode or FP 69406c3fb27SDimitry Andric // exception state matches the default floating-point environment. 69506c3fb27SDimitry Andric if (S.inConstantContext()) 69606c3fb27SDimitry Andric return true; 69706c3fb27SDimitry Andric 69806c3fb27SDimitry Andric FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts()); 69906c3fb27SDimitry Andric 70006c3fb27SDimitry Andric if ((Status & APFloat::opInexact) && 70106c3fb27SDimitry Andric FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) { 70206c3fb27SDimitry Andric // Inexact result means that it depends on rounding mode. If the requested 70306c3fb27SDimitry Andric // mode is dynamic, the evaluation cannot be made in compile time. 70406c3fb27SDimitry Andric S.FFDiag(E, diag::note_constexpr_dynamic_rounding); 70506c3fb27SDimitry Andric return false; 70606c3fb27SDimitry Andric } 70706c3fb27SDimitry Andric 70806c3fb27SDimitry Andric if ((Status != APFloat::opOK) && 70906c3fb27SDimitry Andric (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic || 71006c3fb27SDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore || 71106c3fb27SDimitry Andric FPO.getAllowFEnvAccess())) { 71206c3fb27SDimitry Andric S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); 71306c3fb27SDimitry Andric return false; 71406c3fb27SDimitry Andric } 71506c3fb27SDimitry Andric 71606c3fb27SDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp) && 71706c3fb27SDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore) { 71806c3fb27SDimitry Andric // There is no usefully definable result. 71906c3fb27SDimitry Andric S.FFDiag(E); 72006c3fb27SDimitry Andric return false; 72106c3fb27SDimitry Andric } 72206c3fb27SDimitry Andric 72306c3fb27SDimitry Andric return true; 724bdd1243dSDimitry Andric } 725bdd1243dSDimitry Andric 7260fca6ea1SDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) { 7270fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus20) 7280fca6ea1SDimitry Andric return true; 7290fca6ea1SDimitry Andric 7300fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 7310fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_new); 7320fca6ea1SDimitry Andric return true; 7330fca6ea1SDimitry Andric } 7340fca6ea1SDimitry Andric 7350fca6ea1SDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, 7360fca6ea1SDimitry Andric bool DeleteIsArray, const Descriptor *D, 7370fca6ea1SDimitry Andric const Expr *NewExpr) { 7380fca6ea1SDimitry Andric if (NewWasArray == DeleteIsArray) 7390fca6ea1SDimitry Andric return true; 7400fca6ea1SDimitry Andric 7410fca6ea1SDimitry Andric QualType TypeToDiagnose; 7420fca6ea1SDimitry Andric // We need to shuffle things around a bit here to get a better diagnostic, 7430fca6ea1SDimitry Andric // because the expression we allocated the block for was of type int*, 7440fca6ea1SDimitry Andric // but we want to get the array size right. 7450fca6ea1SDimitry Andric if (D->isArray()) { 7460fca6ea1SDimitry Andric QualType ElemQT = D->getType()->getPointeeType(); 7470fca6ea1SDimitry Andric TypeToDiagnose = S.getCtx().getConstantArrayType( 7480fca6ea1SDimitry Andric ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false), 7490fca6ea1SDimitry Andric nullptr, ArraySizeModifier::Normal, 0); 7500fca6ea1SDimitry Andric } else 7510fca6ea1SDimitry Andric TypeToDiagnose = D->getType()->getPointeeType(); 7520fca6ea1SDimitry Andric 7530fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 7540fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_new_delete_mismatch) 7550fca6ea1SDimitry Andric << DeleteIsArray << 0 << TypeToDiagnose; 7560fca6ea1SDimitry Andric S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here) 7570fca6ea1SDimitry Andric << NewExpr->getSourceRange(); 7580fca6ea1SDimitry Andric return false; 7590fca6ea1SDimitry Andric } 7600fca6ea1SDimitry Andric 7610fca6ea1SDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, 7620fca6ea1SDimitry Andric const Pointer &Ptr) { 7630fca6ea1SDimitry Andric if (Source && isa<CXXNewExpr>(Source)) 7640fca6ea1SDimitry Andric return true; 7650fca6ea1SDimitry Andric 7660fca6ea1SDimitry Andric // Whatever this is, we didn't heap allocate it. 7670fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 7680fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc) 7690fca6ea1SDimitry Andric << Ptr.toDiagnosticString(S.getCtx()); 7700fca6ea1SDimitry Andric 7710fca6ea1SDimitry Andric if (Ptr.isTemporary()) 7720fca6ea1SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 7730fca6ea1SDimitry Andric else 7740fca6ea1SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at); 7750fca6ea1SDimitry Andric return false; 7760fca6ea1SDimitry Andric } 7770fca6ea1SDimitry Andric 7785f757f3fSDimitry Andric /// We aleady know the given DeclRefExpr is invalid for some reason, 7795f757f3fSDimitry Andric /// now figure out why and print appropriate diagnostics. 7805f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { 7815f757f3fSDimitry Andric const ValueDecl *D = DR->getDecl(); 7820fca6ea1SDimitry Andric return diagnoseUnknownDecl(S, OpPC, D); 7830fca6ea1SDimitry Andric } 7845f757f3fSDimitry Andric 7850fca6ea1SDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 7860fca6ea1SDimitry Andric AccessKinds AK) { 7870fca6ea1SDimitry Andric if (!Ptr.isDummy()) 7880fca6ea1SDimitry Andric return true; 7890fca6ea1SDimitry Andric 7900fca6ea1SDimitry Andric const Descriptor *Desc = Ptr.getDeclDesc(); 7910fca6ea1SDimitry Andric const ValueDecl *D = Desc->asValueDecl(); 7920fca6ea1SDimitry Andric if (!D) 7930fca6ea1SDimitry Andric return false; 7940fca6ea1SDimitry Andric 7950fca6ea1SDimitry Andric if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement) 7960fca6ea1SDimitry Andric return diagnoseUnknownDecl(S, OpPC, D); 7970fca6ea1SDimitry Andric 7980fca6ea1SDimitry Andric assert(AK == AK_Assign); 7995f757f3fSDimitry Andric if (S.getLangOpts().CPlusPlus11) { 8000fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 8010fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_modify_global); 8025f757f3fSDimitry Andric } 8035f757f3fSDimitry Andric return false; 8045f757f3fSDimitry Andric } 8055f757f3fSDimitry Andric 8060fca6ea1SDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, 8070fca6ea1SDimitry Andric const CallExpr *CE, unsigned ArgSize) { 8080fca6ea1SDimitry Andric auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs()); 8090fca6ea1SDimitry Andric auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args); 8100fca6ea1SDimitry Andric unsigned Offset = 0; 8110fca6ea1SDimitry Andric unsigned Index = 0; 8120fca6ea1SDimitry Andric for (const Expr *Arg : Args) { 8130fca6ea1SDimitry Andric if (NonNullArgs[Index] && Arg->getType()->isPointerType()) { 8140fca6ea1SDimitry Andric const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset); 8150fca6ea1SDimitry Andric if (ArgPtr.isZero()) { 8160fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 8170fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_non_null_attribute_failed); 8185f757f3fSDimitry Andric return false; 8195f757f3fSDimitry Andric } 8205f757f3fSDimitry Andric } 8215f757f3fSDimitry Andric 8220fca6ea1SDimitry Andric Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr))); 8230fca6ea1SDimitry Andric ++Index; 8240fca6ea1SDimitry Andric } 8250fca6ea1SDimitry Andric return true; 8260fca6ea1SDimitry Andric } 8270fca6ea1SDimitry Andric 8280fca6ea1SDimitry Andric // FIXME: This is similar to code we already have in Compiler.cpp. 8290fca6ea1SDimitry Andric // I think it makes sense to instead add the field and base destruction stuff 8300fca6ea1SDimitry Andric // to the destructor Function itself. Then destroying a record would really 8310fca6ea1SDimitry Andric // _just_ be calling its destructor. That would also help with the diagnostic 8320fca6ea1SDimitry Andric // difference when the destructor or a field/base fails. 8330fca6ea1SDimitry Andric static bool runRecordDestructor(InterpState &S, CodePtr OpPC, 8340fca6ea1SDimitry Andric const Pointer &BasePtr, 8350fca6ea1SDimitry Andric const Descriptor *Desc) { 8360fca6ea1SDimitry Andric assert(Desc->isRecord()); 8370fca6ea1SDimitry Andric const Record *R = Desc->ElemRecord; 8380fca6ea1SDimitry Andric assert(R); 8390fca6ea1SDimitry Andric 8400fca6ea1SDimitry Andric // Fields. 8410fca6ea1SDimitry Andric for (const Record::Field &Field : llvm::reverse(R->fields())) { 8420fca6ea1SDimitry Andric const Descriptor *D = Field.Desc; 8430fca6ea1SDimitry Andric if (D->isRecord()) { 8440fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atField(Field.Offset), D)) 8455f757f3fSDimitry Andric return false; 8460fca6ea1SDimitry Andric } else if (D->isCompositeArray()) { 8470fca6ea1SDimitry Andric const Descriptor *ElemDesc = Desc->ElemDesc; 8480fca6ea1SDimitry Andric assert(ElemDesc->isRecord()); 8490fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) { 8500fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atIndex(I).narrow(), 8510fca6ea1SDimitry Andric ElemDesc)) 8520fca6ea1SDimitry Andric return false; 8530fca6ea1SDimitry Andric } 8540fca6ea1SDimitry Andric } 8550fca6ea1SDimitry Andric } 8560fca6ea1SDimitry Andric 8570fca6ea1SDimitry Andric // Destructor of this record. 8580fca6ea1SDimitry Andric if (const CXXDestructorDecl *Dtor = R->getDestructor(); 8590fca6ea1SDimitry Andric Dtor && !Dtor->isTrivial()) { 8600fca6ea1SDimitry Andric const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor); 8610fca6ea1SDimitry Andric if (!DtorFunc) 8620fca6ea1SDimitry Andric return false; 8630fca6ea1SDimitry Andric 8640fca6ea1SDimitry Andric S.Stk.push<Pointer>(BasePtr); 8650fca6ea1SDimitry Andric if (!Call(S, OpPC, DtorFunc, 0)) 8660fca6ea1SDimitry Andric return false; 8670fca6ea1SDimitry Andric } 8680fca6ea1SDimitry Andric 8690fca6ea1SDimitry Andric // Bases. 8700fca6ea1SDimitry Andric for (const Record::Base &Base : llvm::reverse(R->bases())) { 8710fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atField(Base.Offset), Base.Desc)) 8720fca6ea1SDimitry Andric return false; 8730fca6ea1SDimitry Andric } 8740fca6ea1SDimitry Andric 8750fca6ea1SDimitry Andric return true; 8760fca6ea1SDimitry Andric } 8770fca6ea1SDimitry Andric 8780fca6ea1SDimitry Andric bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) { 8790fca6ea1SDimitry Andric assert(B); 8800fca6ea1SDimitry Andric const Descriptor *Desc = B->getDescriptor(); 8810fca6ea1SDimitry Andric 8820fca6ea1SDimitry Andric if (Desc->isPrimitive() || Desc->isPrimitiveArray()) 8830fca6ea1SDimitry Andric return true; 8840fca6ea1SDimitry Andric 8850fca6ea1SDimitry Andric assert(Desc->isRecord() || Desc->isCompositeArray()); 8860fca6ea1SDimitry Andric 8870fca6ea1SDimitry Andric if (Desc->isCompositeArray()) { 8880fca6ea1SDimitry Andric const Descriptor *ElemDesc = Desc->ElemDesc; 8890fca6ea1SDimitry Andric assert(ElemDesc->isRecord()); 8900fca6ea1SDimitry Andric 8910fca6ea1SDimitry Andric Pointer RP(const_cast<Block *>(B)); 8920fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) { 8930fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc)) 8940fca6ea1SDimitry Andric return false; 8950fca6ea1SDimitry Andric } 8960fca6ea1SDimitry Andric return true; 8970fca6ea1SDimitry Andric } 8980fca6ea1SDimitry Andric 8990fca6ea1SDimitry Andric assert(Desc->isRecord()); 9000fca6ea1SDimitry Andric return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc); 9010fca6ea1SDimitry Andric } 9020fca6ea1SDimitry Andric 9030fca6ea1SDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, 9040fca6ea1SDimitry Andric const APSInt &Value) { 9050fca6ea1SDimitry Andric llvm::APInt Min; 9060fca6ea1SDimitry Andric llvm::APInt Max; 9070fca6ea1SDimitry Andric 9080fca6ea1SDimitry Andric if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr()) 9090fca6ea1SDimitry Andric return; 9100fca6ea1SDimitry Andric 9110fca6ea1SDimitry Andric ED->getValueRange(Max, Min); 9120fca6ea1SDimitry Andric --Max; 9130fca6ea1SDimitry Andric 9140fca6ea1SDimitry Andric if (ED->getNumNegativeBits() && 9150fca6ea1SDimitry Andric (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) { 9160fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 9170fca6ea1SDimitry Andric S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range) 9180fca6ea1SDimitry Andric << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue() 9190fca6ea1SDimitry Andric << ED; 9200fca6ea1SDimitry Andric } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) { 9210fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 9220fca6ea1SDimitry Andric S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range) 9230fca6ea1SDimitry Andric << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue() 9240fca6ea1SDimitry Andric << ED; 9250fca6ea1SDimitry Andric } 9265f757f3fSDimitry Andric } 9275f757f3fSDimitry Andric 928*415efcecSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513 929*415efcecSDimitry Andric #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG) 930*415efcecSDimitry Andric #pragma optimize("", off) 931*415efcecSDimitry Andric #endif 932a7dea167SDimitry Andric bool Interpret(InterpState &S, APValue &Result) { 933bdd1243dSDimitry Andric // The current stack frame when we started Interpret(). 934bdd1243dSDimitry Andric // This is being used by the ops to determine wheter 935bdd1243dSDimitry Andric // to return from this function and thus terminate 936bdd1243dSDimitry Andric // interpretation. 937bdd1243dSDimitry Andric const InterpFrame *StartFrame = S.Current; 938bdd1243dSDimitry Andric assert(!S.Current->isRoot()); 939a7dea167SDimitry Andric CodePtr PC = S.Current->getPC(); 940a7dea167SDimitry Andric 941bdd1243dSDimitry Andric // Empty program. 942bdd1243dSDimitry Andric if (!PC) 943bdd1243dSDimitry Andric return true; 944bdd1243dSDimitry Andric 945a7dea167SDimitry Andric for (;;) { 946a7dea167SDimitry Andric auto Op = PC.read<Opcode>(); 947a7dea167SDimitry Andric CodePtr OpPC = PC; 948a7dea167SDimitry Andric 949a7dea167SDimitry Andric switch (Op) { 950a7dea167SDimitry Andric #define GET_INTERP 951a7dea167SDimitry Andric #include "Opcodes.inc" 952a7dea167SDimitry Andric #undef GET_INTERP 953a7dea167SDimitry Andric } 954a7dea167SDimitry Andric } 955a7dea167SDimitry Andric } 956*415efcecSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513 957*415efcecSDimitry Andric #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG) 958*415efcecSDimitry Andric #pragma optimize("", on) 959*415efcecSDimitry Andric #endif 960a7dea167SDimitry Andric 961a7dea167SDimitry Andric } // namespace interp 962a7dea167SDimitry Andric } // namespace clang 963