17330f729Sjoerg //===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "Interp.h"
107330f729Sjoerg #include <limits>
117330f729Sjoerg #include <vector>
127330f729Sjoerg #include "Function.h"
137330f729Sjoerg #include "InterpFrame.h"
147330f729Sjoerg #include "InterpStack.h"
157330f729Sjoerg #include "Opcode.h"
167330f729Sjoerg #include "PrimType.h"
177330f729Sjoerg #include "Program.h"
187330f729Sjoerg #include "State.h"
197330f729Sjoerg #include "clang/AST/ASTContext.h"
207330f729Sjoerg #include "clang/AST/ASTDiagnostic.h"
217330f729Sjoerg #include "clang/AST/CXXInheritance.h"
227330f729Sjoerg #include "clang/AST/Expr.h"
237330f729Sjoerg #include "clang/AST/ExprCXX.h"
247330f729Sjoerg #include "llvm/ADT/APSInt.h"
257330f729Sjoerg
267330f729Sjoerg using namespace clang;
277330f729Sjoerg using namespace clang::interp;
287330f729Sjoerg
297330f729Sjoerg //===----------------------------------------------------------------------===//
307330f729Sjoerg // Ret
317330f729Sjoerg //===----------------------------------------------------------------------===//
327330f729Sjoerg
337330f729Sjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Ret(InterpState & S,CodePtr & PC,APValue & Result)347330f729Sjoerg static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
357330f729Sjoerg S.CallStackDepth--;
367330f729Sjoerg const T &Ret = S.Stk.pop<T>();
377330f729Sjoerg
387330f729Sjoerg assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
397330f729Sjoerg if (!S.checkingPotentialConstantExpression())
407330f729Sjoerg S.Current->popArgs();
417330f729Sjoerg
427330f729Sjoerg if (InterpFrame *Caller = S.Current->Caller) {
437330f729Sjoerg PC = S.Current->getRetPC();
447330f729Sjoerg delete S.Current;
457330f729Sjoerg S.Current = Caller;
467330f729Sjoerg S.Stk.push<T>(Ret);
477330f729Sjoerg } else {
487330f729Sjoerg delete S.Current;
497330f729Sjoerg S.Current = nullptr;
507330f729Sjoerg if (!ReturnValue<T>(Ret, Result))
517330f729Sjoerg return false;
527330f729Sjoerg }
537330f729Sjoerg return true;
547330f729Sjoerg }
557330f729Sjoerg
RetVoid(InterpState & S,CodePtr & PC,APValue & Result)567330f729Sjoerg static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
577330f729Sjoerg S.CallStackDepth--;
587330f729Sjoerg
597330f729Sjoerg assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
607330f729Sjoerg if (!S.checkingPotentialConstantExpression())
617330f729Sjoerg S.Current->popArgs();
627330f729Sjoerg
637330f729Sjoerg if (InterpFrame *Caller = S.Current->Caller) {
647330f729Sjoerg PC = S.Current->getRetPC();
657330f729Sjoerg delete S.Current;
667330f729Sjoerg S.Current = Caller;
677330f729Sjoerg } else {
687330f729Sjoerg delete S.Current;
697330f729Sjoerg S.Current = nullptr;
707330f729Sjoerg }
717330f729Sjoerg return true;
727330f729Sjoerg }
737330f729Sjoerg
RetValue(InterpState & S,CodePtr & Pt,APValue & Result)747330f729Sjoerg static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
757330f729Sjoerg llvm::report_fatal_error("Interpreter cannot return values");
767330f729Sjoerg }
777330f729Sjoerg
787330f729Sjoerg //===----------------------------------------------------------------------===//
797330f729Sjoerg // Jmp, Jt, Jf
807330f729Sjoerg //===----------------------------------------------------------------------===//
817330f729Sjoerg
Jmp(InterpState & S,CodePtr & PC,int32_t Offset)827330f729Sjoerg static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
837330f729Sjoerg PC += Offset;
847330f729Sjoerg return true;
857330f729Sjoerg }
867330f729Sjoerg
Jt(InterpState & S,CodePtr & PC,int32_t Offset)877330f729Sjoerg static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
887330f729Sjoerg if (S.Stk.pop<bool>()) {
897330f729Sjoerg PC += Offset;
907330f729Sjoerg }
917330f729Sjoerg return true;
927330f729Sjoerg }
937330f729Sjoerg
Jf(InterpState & S,CodePtr & PC,int32_t Offset)947330f729Sjoerg static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
957330f729Sjoerg if (!S.Stk.pop<bool>()) {
967330f729Sjoerg PC += Offset;
977330f729Sjoerg }
987330f729Sjoerg return true;
997330f729Sjoerg }
1007330f729Sjoerg
CheckInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)1017330f729Sjoerg static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1027330f729Sjoerg AccessKinds AK) {
1037330f729Sjoerg if (Ptr.isInitialized())
1047330f729Sjoerg return true;
1057330f729Sjoerg if (!S.checkingPotentialConstantExpression()) {
1067330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
1077330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
1087330f729Sjoerg }
1097330f729Sjoerg return false;
1107330f729Sjoerg }
1117330f729Sjoerg
CheckActive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)1127330f729Sjoerg static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1137330f729Sjoerg AccessKinds AK) {
1147330f729Sjoerg if (Ptr.isActive())
1157330f729Sjoerg return true;
1167330f729Sjoerg
1177330f729Sjoerg // Get the inactive field descriptor.
1187330f729Sjoerg const FieldDecl *InactiveField = Ptr.getField();
1197330f729Sjoerg
1207330f729Sjoerg // Walk up the pointer chain to find the union which is not active.
1217330f729Sjoerg Pointer U = Ptr.getBase();
1227330f729Sjoerg while (!U.isActive()) {
1237330f729Sjoerg U = U.getBase();
1247330f729Sjoerg }
1257330f729Sjoerg
1267330f729Sjoerg // Find the active field of the union.
1277330f729Sjoerg Record *R = U.getRecord();
1287330f729Sjoerg assert(R && R->isUnion() && "Not a union");
1297330f729Sjoerg const FieldDecl *ActiveField = nullptr;
1307330f729Sjoerg for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
1317330f729Sjoerg const Pointer &Field = U.atField(R->getField(I)->Offset);
1327330f729Sjoerg if (Field.isActive()) {
1337330f729Sjoerg ActiveField = Field.getField();
1347330f729Sjoerg break;
1357330f729Sjoerg }
1367330f729Sjoerg }
1377330f729Sjoerg
1387330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
1397330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
1407330f729Sjoerg << AK << InactiveField << !ActiveField << ActiveField;
1417330f729Sjoerg return false;
1427330f729Sjoerg }
1437330f729Sjoerg
CheckTemporary(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)1447330f729Sjoerg static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1457330f729Sjoerg AccessKinds AK) {
1467330f729Sjoerg if (auto ID = Ptr.getDeclID()) {
1477330f729Sjoerg if (!Ptr.isStaticTemporary())
1487330f729Sjoerg return true;
1497330f729Sjoerg
1507330f729Sjoerg if (Ptr.getDeclDesc()->getType().isConstQualified())
1517330f729Sjoerg return true;
1527330f729Sjoerg
1537330f729Sjoerg if (S.P.getCurrentDecl() == ID)
1547330f729Sjoerg return true;
1557330f729Sjoerg
1567330f729Sjoerg const SourceInfo &E = S.Current->getSource(OpPC);
1577330f729Sjoerg S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
1587330f729Sjoerg S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
1597330f729Sjoerg return false;
1607330f729Sjoerg }
1617330f729Sjoerg return true;
1627330f729Sjoerg }
1637330f729Sjoerg
CheckGlobal(InterpState & S,CodePtr OpPC,const Pointer & Ptr)1647330f729Sjoerg static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1657330f729Sjoerg if (auto ID = Ptr.getDeclID()) {
1667330f729Sjoerg if (!Ptr.isStatic())
1677330f729Sjoerg return true;
1687330f729Sjoerg
1697330f729Sjoerg if (S.P.getCurrentDecl() == ID)
1707330f729Sjoerg return true;
1717330f729Sjoerg
1727330f729Sjoerg S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
1737330f729Sjoerg return false;
1747330f729Sjoerg }
1757330f729Sjoerg return true;
1767330f729Sjoerg }
1777330f729Sjoerg
1787330f729Sjoerg namespace clang {
1797330f729Sjoerg namespace interp {
1807330f729Sjoerg
CheckExtern(InterpState & S,CodePtr OpPC,const Pointer & Ptr)1817330f729Sjoerg bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1827330f729Sjoerg if (!Ptr.isExtern())
1837330f729Sjoerg return true;
1847330f729Sjoerg
1857330f729Sjoerg if (!S.checkingPotentialConstantExpression()) {
1867330f729Sjoerg auto *VD = Ptr.getDeclDesc()->asValueDecl();
1877330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
1887330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
1897330f729Sjoerg S.Note(VD->getLocation(), diag::note_declared_at);
1907330f729Sjoerg }
1917330f729Sjoerg return false;
1927330f729Sjoerg }
1937330f729Sjoerg
CheckArray(InterpState & S,CodePtr OpPC,const Pointer & Ptr)1947330f729Sjoerg bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1957330f729Sjoerg if (!Ptr.isUnknownSizeArray())
1967330f729Sjoerg return true;
1977330f729Sjoerg const SourceInfo &E = S.Current->getSource(OpPC);
1987330f729Sjoerg S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
1997330f729Sjoerg return false;
2007330f729Sjoerg }
2017330f729Sjoerg
CheckLive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)2027330f729Sjoerg bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
2037330f729Sjoerg AccessKinds AK) {
2047330f729Sjoerg const auto &Src = S.Current->getSource(OpPC);
2057330f729Sjoerg if (Ptr.isZero()) {
2067330f729Sjoerg
2077330f729Sjoerg if (Ptr.isField())
2087330f729Sjoerg S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
2097330f729Sjoerg else
2107330f729Sjoerg S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
2117330f729Sjoerg
2127330f729Sjoerg return false;
2137330f729Sjoerg }
2147330f729Sjoerg
2157330f729Sjoerg if (!Ptr.isLive()) {
2167330f729Sjoerg bool IsTemp = Ptr.isTemporary();
2177330f729Sjoerg
2187330f729Sjoerg S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
2197330f729Sjoerg
2207330f729Sjoerg if (IsTemp)
2217330f729Sjoerg S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
2227330f729Sjoerg else
2237330f729Sjoerg S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
2247330f729Sjoerg
2257330f729Sjoerg return false;
2267330f729Sjoerg }
2277330f729Sjoerg
2287330f729Sjoerg return true;
2297330f729Sjoerg }
2307330f729Sjoerg
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)2317330f729Sjoerg bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
2327330f729Sjoerg CheckSubobjectKind CSK) {
2337330f729Sjoerg if (!Ptr.isZero())
2347330f729Sjoerg return true;
2357330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
2367330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
2377330f729Sjoerg return false;
2387330f729Sjoerg }
2397330f729Sjoerg
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)2407330f729Sjoerg bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
2417330f729Sjoerg AccessKinds AK) {
2427330f729Sjoerg if (!Ptr.isOnePastEnd())
2437330f729Sjoerg return true;
2447330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
2457330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
2467330f729Sjoerg return false;
2477330f729Sjoerg }
2487330f729Sjoerg
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)2497330f729Sjoerg bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
2507330f729Sjoerg CheckSubobjectKind CSK) {
2517330f729Sjoerg if (!Ptr.isElementPastEnd())
2527330f729Sjoerg return true;
2537330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
2547330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
2557330f729Sjoerg return false;
2567330f729Sjoerg }
2577330f729Sjoerg
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)2587330f729Sjoerg bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
2597330f729Sjoerg assert(Ptr.isLive() && "Pointer is not live");
2607330f729Sjoerg if (!Ptr.isConst()) {
2617330f729Sjoerg return true;
2627330f729Sjoerg }
2637330f729Sjoerg
2647330f729Sjoerg const QualType Ty = Ptr.getType();
2657330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
2667330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
2677330f729Sjoerg return false;
2687330f729Sjoerg }
2697330f729Sjoerg
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)2707330f729Sjoerg bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
2717330f729Sjoerg assert(Ptr.isLive() && "Pointer is not live");
2727330f729Sjoerg if (!Ptr.isMutable()) {
2737330f729Sjoerg return true;
2747330f729Sjoerg }
2757330f729Sjoerg
2767330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
2777330f729Sjoerg const FieldDecl *Field = Ptr.getField();
2787330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
2797330f729Sjoerg S.Note(Field->getLocation(), diag::note_declared_at);
2807330f729Sjoerg return false;
2817330f729Sjoerg }
2827330f729Sjoerg
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr)2837330f729Sjoerg bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
2847330f729Sjoerg if (!CheckLive(S, OpPC, Ptr, AK_Read))
2857330f729Sjoerg return false;
2867330f729Sjoerg if (!CheckExtern(S, OpPC, Ptr))
2877330f729Sjoerg return false;
2887330f729Sjoerg if (!CheckRange(S, OpPC, Ptr, AK_Read))
2897330f729Sjoerg return false;
2907330f729Sjoerg if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
2917330f729Sjoerg return false;
2927330f729Sjoerg if (!CheckActive(S, OpPC, Ptr, AK_Read))
2937330f729Sjoerg return false;
2947330f729Sjoerg if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
2957330f729Sjoerg return false;
2967330f729Sjoerg if (!CheckMutable(S, OpPC, Ptr))
2977330f729Sjoerg return false;
2987330f729Sjoerg return true;
2997330f729Sjoerg }
3007330f729Sjoerg
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)3017330f729Sjoerg bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
3027330f729Sjoerg if (!CheckLive(S, OpPC, Ptr, AK_Assign))
3037330f729Sjoerg return false;
3047330f729Sjoerg if (!CheckExtern(S, OpPC, Ptr))
3057330f729Sjoerg return false;
3067330f729Sjoerg if (!CheckRange(S, OpPC, Ptr, AK_Assign))
3077330f729Sjoerg return false;
3087330f729Sjoerg if (!CheckGlobal(S, OpPC, Ptr))
3097330f729Sjoerg return false;
3107330f729Sjoerg if (!CheckConst(S, OpPC, Ptr))
3117330f729Sjoerg return false;
3127330f729Sjoerg return true;
3137330f729Sjoerg }
3147330f729Sjoerg
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)3157330f729Sjoerg bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
3167330f729Sjoerg if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
3177330f729Sjoerg return false;
3187330f729Sjoerg if (!CheckExtern(S, OpPC, Ptr))
3197330f729Sjoerg return false;
3207330f729Sjoerg if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
3217330f729Sjoerg return false;
3227330f729Sjoerg return true;
3237330f729Sjoerg }
3247330f729Sjoerg
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)3257330f729Sjoerg bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
3267330f729Sjoerg if (!CheckLive(S, OpPC, Ptr, AK_Assign))
3277330f729Sjoerg return false;
3287330f729Sjoerg if (!CheckRange(S, OpPC, Ptr, AK_Assign))
3297330f729Sjoerg return false;
3307330f729Sjoerg return true;
3317330f729Sjoerg }
3327330f729Sjoerg
CheckCallable(InterpState & S,CodePtr OpPC,Function * F)3337330f729Sjoerg bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
3347330f729Sjoerg const SourceLocation &Loc = S.Current->getLocation(OpPC);
3357330f729Sjoerg
3367330f729Sjoerg if (F->isVirtual()) {
337*e038c9c4Sjoerg if (!S.getLangOpts().CPlusPlus20) {
3387330f729Sjoerg S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
3397330f729Sjoerg return false;
3407330f729Sjoerg }
3417330f729Sjoerg }
3427330f729Sjoerg
3437330f729Sjoerg if (!F->isConstexpr()) {
3447330f729Sjoerg if (S.getLangOpts().CPlusPlus11) {
3457330f729Sjoerg const FunctionDecl *DiagDecl = F->getDecl();
3467330f729Sjoerg
3477330f729Sjoerg // If this function is not constexpr because it is an inherited
3487330f729Sjoerg // non-constexpr constructor, diagnose that directly.
3497330f729Sjoerg auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
3507330f729Sjoerg if (CD && CD->isInheritingConstructor()) {
3517330f729Sjoerg auto *Inherited = CD->getInheritedConstructor().getConstructor();
3527330f729Sjoerg if (!Inherited->isConstexpr())
3537330f729Sjoerg DiagDecl = CD = Inherited;
3547330f729Sjoerg }
3557330f729Sjoerg
3567330f729Sjoerg // FIXME: If DiagDecl is an implicitly-declared special member function
3577330f729Sjoerg // or an inheriting constructor, we should be much more explicit about why
3587330f729Sjoerg // it's not constexpr.
3597330f729Sjoerg if (CD && CD->isInheritingConstructor())
3607330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
3617330f729Sjoerg << CD->getInheritedConstructor().getConstructor()->getParent();
3627330f729Sjoerg else
3637330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
3647330f729Sjoerg << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
3657330f729Sjoerg S.Note(DiagDecl->getLocation(), diag::note_declared_at);
3667330f729Sjoerg } else {
3677330f729Sjoerg S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
3687330f729Sjoerg }
3697330f729Sjoerg return false;
3707330f729Sjoerg }
3717330f729Sjoerg
3727330f729Sjoerg return true;
3737330f729Sjoerg }
3747330f729Sjoerg
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)3757330f729Sjoerg bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
3767330f729Sjoerg if (!This.isZero())
3777330f729Sjoerg return true;
3787330f729Sjoerg
3797330f729Sjoerg const SourceInfo &Loc = S.Current->getSource(OpPC);
3807330f729Sjoerg
3817330f729Sjoerg bool IsImplicit = false;
3827330f729Sjoerg if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
3837330f729Sjoerg IsImplicit = E->isImplicit();
3847330f729Sjoerg
3857330f729Sjoerg if (S.getLangOpts().CPlusPlus11)
3867330f729Sjoerg S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
3877330f729Sjoerg else
3887330f729Sjoerg S.FFDiag(Loc);
3897330f729Sjoerg
3907330f729Sjoerg return false;
3917330f729Sjoerg }
3927330f729Sjoerg
CheckPure(InterpState & S,CodePtr OpPC,const CXXMethodDecl * MD)3937330f729Sjoerg bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
3947330f729Sjoerg if (!MD->isPure())
3957330f729Sjoerg return true;
3967330f729Sjoerg const SourceInfo &E = S.Current->getSource(OpPC);
3977330f729Sjoerg S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
3987330f729Sjoerg S.Note(MD->getLocation(), diag::note_declared_at);
3997330f729Sjoerg return false;
4007330f729Sjoerg }
Interpret(InterpState & S,APValue & Result)4017330f729Sjoerg bool Interpret(InterpState &S, APValue &Result) {
4027330f729Sjoerg CodePtr PC = S.Current->getPC();
4037330f729Sjoerg
4047330f729Sjoerg for (;;) {
4057330f729Sjoerg auto Op = PC.read<Opcode>();
4067330f729Sjoerg CodePtr OpPC = PC;
4077330f729Sjoerg
4087330f729Sjoerg switch (Op) {
4097330f729Sjoerg #define GET_INTERP
4107330f729Sjoerg #include "Opcodes.inc"
4117330f729Sjoerg #undef GET_INTERP
4127330f729Sjoerg }
4137330f729Sjoerg }
4147330f729Sjoerg }
4157330f729Sjoerg
4167330f729Sjoerg } // namespace interp
4177330f729Sjoerg } // namespace clang
418