1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309 |
- //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Definition of the interpreter state and entry point.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
- #define LLVM_CLANG_AST_INTERP_INTERP_H
- #include "Boolean.h"
- #include "Function.h"
- #include "InterpFrame.h"
- #include "InterpStack.h"
- #include "InterpState.h"
- #include "Opcode.h"
- #include "PrimType.h"
- #include "Program.h"
- #include "State.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/ASTDiagnostic.h"
- #include "clang/AST/CXXInheritance.h"
- #include "clang/AST/Expr.h"
- #include "llvm/ADT/APFloat.h"
- #include "llvm/ADT/APSInt.h"
- #include "llvm/Support/Endian.h"
- #include <limits>
- #include <type_traits>
- namespace clang {
- namespace interp {
- using APInt = llvm::APInt;
- using APSInt = llvm::APSInt;
- /// Convert a value to an APValue.
- template <typename T> bool ReturnValue(const T &V, APValue &R) {
- R = V.toAPValue();
- return true;
- }
- /// Checks if the variable has externally defined storage.
- bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if the array is offsetable.
- bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a pointer is live and accessible.
- bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
- /// Checks if a pointer is null.
- bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- CheckSubobjectKind CSK);
- /// Checks if a pointer is in range.
- bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
- /// Checks if a field from which a pointer is going to be derived is valid.
- bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- CheckSubobjectKind CSK);
- /// Checks if a pointer points to const storage.
- bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a pointer points to a mutable field.
- bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a value can be loaded from a block.
- bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a value can be stored in a block.
- bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a method can be invoked on an object.
- bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a value can be initialized.
- bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
- /// Checks if a method can be called.
- bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
- /// Checks the 'this' pointer.
- bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
- /// Checks if a method is pure virtual.
- bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
- /// Checks that all fields are initialized after a constructor call.
- bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
- /// Checks if the shift operation is legal.
- template <typename RT>
- bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
- if (RHS.isNegative()) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
- return false;
- }
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of
- // the shifted type.
- if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
- const Expr *E = S.Current->getExpr(OpPC);
- const APSInt Val = RHS.toAPSInt();
- QualType Ty = E->getType();
- S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
- return false;
- }
- return true;
- }
- /// Checks if Div/Rem operation on LHS and RHS is valid.
- template <typename T>
- bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
- if (RHS.isZero()) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- S.FFDiag(Loc, diag::note_expr_divide_by_zero);
- return false;
- }
- if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
- APSInt LHSInt = LHS.toAPSInt();
- SmallString<32> Trunc;
- (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- const Expr *E = S.Current->getExpr(OpPC);
- S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
- return false;
- }
- return true;
- }
- /// Interpreter entry point.
- bool Interpret(InterpState &S, APValue &Result);
- //===----------------------------------------------------------------------===//
- // Add, Sub, Mul
- //===----------------------------------------------------------------------===//
- template <typename T, bool (*OpFW)(T, T, unsigned, T *),
- template <typename U> class OpAP>
- bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
- const T &RHS) {
- // Fast path - add the numbers with fixed width.
- T Result;
- if (!OpFW(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- // If for some reason evaluation continues, use the truncated results.
- S.Stk.push<T>(Result);
- // Slow path - compute the result using another bit of precision.
- APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
- // Report undefined behaviour, stopping if required.
- const Expr *E = S.Current->getExpr(OpPC);
- QualType Type = E->getType();
- if (S.checkingForUndefinedBehavior()) {
- SmallString<32> Trunc;
- Value.trunc(Result.bitWidth()).toString(Trunc, 10);
- auto Loc = E->getExprLoc();
- S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
- return true;
- } else {
- S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
- return S.noteUndefinedBehavior();
- }
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Add(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- const unsigned Bits = RHS.bitWidth() + 1;
- return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Sub(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- const unsigned Bits = RHS.bitWidth() + 1;
- return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Mul(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- const unsigned Bits = RHS.bitWidth() * 2;
- return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
- }
- /// 1) Pops the RHS from the stack.
- /// 2) Pops the LHS from the stack.
- /// 3) Pushes 'LHS & RHS' on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool BitAnd(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- unsigned Bits = RHS.bitWidth();
- T Result;
- if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- /// 1) Pops the RHS from the stack.
- /// 2) Pops the LHS from the stack.
- /// 3) Pushes 'LHS | RHS' on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool BitOr(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- unsigned Bits = RHS.bitWidth();
- T Result;
- if (!T::bitOr(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- /// 1) Pops the RHS from the stack.
- /// 2) Pops the LHS from the stack.
- /// 3) Pushes 'LHS ^ RHS' on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool BitXor(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- unsigned Bits = RHS.bitWidth();
- T Result;
- if (!T::bitXor(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- /// 1) Pops the RHS from the stack.
- /// 2) Pops the LHS from the stack.
- /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Rem(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- if (!CheckDivRem(S, OpPC, LHS, RHS))
- return false;
- const unsigned Bits = RHS.bitWidth() * 2;
- T Result;
- if (!T::rem(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- /// 1) Pops the RHS from the stack.
- /// 2) Pops the LHS from the stack.
- /// 3) Pushes 'LHS / RHS' on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Div(InterpState &S, CodePtr OpPC) {
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- if (!CheckDivRem(S, OpPC, LHS, RHS))
- return false;
- const unsigned Bits = RHS.bitWidth() * 2;
- T Result;
- if (!T::div(LHS, RHS, Bits, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // Inv
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Inv(InterpState &S, CodePtr OpPC) {
- using BoolT = PrimConv<PT_Bool>::T;
- const T &Val = S.Stk.pop<T>();
- const unsigned Bits = Val.bitWidth();
- Boolean R;
- Boolean::inv(BoolT::from(Val, Bits), &R);
- S.Stk.push<BoolT>(R);
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Neg
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Neg(InterpState &S, CodePtr OpPC) {
- const T &Val = S.Stk.pop<T>();
- T Result;
- T::neg(Val, &Result);
- S.Stk.push<T>(Result);
- return true;
- }
- enum class PushVal : bool {
- No,
- Yes,
- };
- enum class IncDecOp {
- Inc,
- Dec,
- };
- template <typename T, IncDecOp Op, PushVal DoPush>
- bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- T Value = Ptr.deref<T>();
- T Result;
- if constexpr (DoPush == PushVal::Yes)
- S.Stk.push<T>(Result);
- if constexpr (Op == IncDecOp::Inc) {
- if (!T::increment(Value, &Result)) {
- Ptr.deref<T>() = Result;
- return true;
- }
- } else {
- if (!T::decrement(Value, &Result)) {
- Ptr.deref<T>() = Result;
- return true;
- }
- }
- // Something went wrong with the previous operation. Compute the
- // result with another bit of precision.
- unsigned Bits = Value.bitWidth() + 1;
- APSInt APResult;
- if constexpr (Op == IncDecOp::Inc)
- APResult = ++Value.toAPSInt(Bits);
- else
- APResult = --Value.toAPSInt(Bits);
- // Report undefined behaviour, stopping if required.
- const Expr *E = S.Current->getExpr(OpPC);
- QualType Type = E->getType();
- if (S.checkingForUndefinedBehavior()) {
- SmallString<32> Trunc;
- APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
- auto Loc = E->getExprLoc();
- S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
- return true;
- }
- S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
- return S.noteUndefinedBehavior();
- }
- /// 1) Pops a pointer from the stack
- /// 2) Load the value from the pointer
- /// 3) Writes the value increased by one back to the pointer
- /// 4) Pushes the original (pre-inc) value on the stack.
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Inc(InterpState &S, CodePtr OpPC) {
- // FIXME: Check initialization of Ptr
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
- }
- /// 1) Pops a pointer from the stack
- /// 2) Load the value from the pointer
- /// 3) Writes the value increased by one back to the pointer
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool IncPop(InterpState &S, CodePtr OpPC) {
- // FIXME: Check initialization of Ptr
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
- }
- /// 1) Pops a pointer from the stack
- /// 2) Load the value from the pointer
- /// 3) Writes the value decreased by one back to the pointer
- /// 4) Pushes the original (pre-dec) value on the stack.
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Dec(InterpState &S, CodePtr OpPC) {
- // FIXME: Check initialization of Ptr
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
- }
- /// 1) Pops a pointer from the stack
- /// 2) Load the value from the pointer
- /// 3) Writes the value decreased by one back to the pointer
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool DecPop(InterpState &S, CodePtr OpPC) {
- // FIXME: Check initialization of Ptr
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
- }
- /// 1) Pops the value from the stack.
- /// 2) Pushes the bitwise complemented value on the stack (~V).
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Comp(InterpState &S, CodePtr OpPC) {
- const T &Val = S.Stk.pop<T>();
- T Result;
- if (!T::comp(Val, &Result)) {
- S.Stk.push<T>(Result);
- return true;
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // EQ, NE, GT, GE, LT, LE
- //===----------------------------------------------------------------------===//
- using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
- template <typename T>
- bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
- using BoolT = PrimConv<PT_Bool>::T;
- const T &RHS = S.Stk.pop<T>();
- const T &LHS = S.Stk.pop<T>();
- S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
- return true;
- }
- template <typename T>
- bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
- return CmpHelper<T>(S, OpPC, Fn);
- }
- template <>
- inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
- using BoolT = PrimConv<PT_Bool>::T;
- const Pointer &RHS = S.Stk.pop<Pointer>();
- const Pointer &LHS = S.Stk.pop<Pointer>();
- if (!Pointer::hasSameBase(LHS, RHS)) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
- return false;
- } else {
- unsigned VL = LHS.getByteOffset();
- unsigned VR = RHS.getByteOffset();
- S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
- return true;
- }
- }
- template <>
- inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
- using BoolT = PrimConv<PT_Bool>::T;
- const Pointer &RHS = S.Stk.pop<Pointer>();
- const Pointer &LHS = S.Stk.pop<Pointer>();
- if (LHS.isZero() && RHS.isZero()) {
- S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
- return true;
- }
- if (!Pointer::hasSameBase(LHS, RHS)) {
- S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
- return true;
- } else {
- unsigned VL = LHS.getByteOffset();
- unsigned VR = RHS.getByteOffset();
- // In our Pointer class, a pointer to an array and a pointer to the first
- // element in the same array are NOT equal. They have the same Base value,
- // but a different Offset. This is a pretty rare case, so we fix this here
- // by comparing pointers to the first elements.
- if (LHS.inArray() && LHS.isRoot())
- VL = LHS.atIndex(0).getByteOffset();
- if (RHS.inArray() && RHS.isRoot())
- VR = RHS.atIndex(0).getByteOffset();
- S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
- return true;
- }
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool EQ(InterpState &S, CodePtr OpPC) {
- return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R == ComparisonCategoryResult::Equal;
- });
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool NE(InterpState &S, CodePtr OpPC) {
- return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R != ComparisonCategoryResult::Equal;
- });
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool LT(InterpState &S, CodePtr OpPC) {
- return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R == ComparisonCategoryResult::Less;
- });
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool LE(InterpState &S, CodePtr OpPC) {
- return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R == ComparisonCategoryResult::Less ||
- R == ComparisonCategoryResult::Equal;
- });
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GT(InterpState &S, CodePtr OpPC) {
- return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R == ComparisonCategoryResult::Greater;
- });
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GE(InterpState &S, CodePtr OpPC) {
- return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
- return R == ComparisonCategoryResult::Greater ||
- R == ComparisonCategoryResult::Equal;
- });
- }
- //===----------------------------------------------------------------------===//
- // InRange
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InRange(InterpState &S, CodePtr OpPC) {
- const T RHS = S.Stk.pop<T>();
- const T LHS = S.Stk.pop<T>();
- const T Value = S.Stk.pop<T>();
- S.Stk.push<bool>(LHS <= Value && Value <= RHS);
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Dup, Pop, Test
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Dup(InterpState &S, CodePtr OpPC) {
- S.Stk.push<T>(S.Stk.peek<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Pop(InterpState &S, CodePtr OpPC) {
- S.Stk.pop<T>();
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Const
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
- S.Stk.push<T>(Arg);
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Get/Set Local/Param/Global/This
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.Current->getLocalPointer(I);
- if (!CheckLoad(S, OpPC, Ptr))
- return false;
- S.Stk.push<T>(Ptr.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Current->setLocal<T>(I, S.Stk.pop<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression()) {
- return false;
- }
- S.Stk.push<T>(S.Current->getParam<T>(I));
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Current->setParam<T>(I, S.Stk.pop<T>());
- return true;
- }
- /// 1) Peeks a pointer on the stack
- /// 2) Pushes the value of the pointer's field on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Obj = S.Stk.peek<Pointer>();
- if (!CheckNull(S, OpPC, Obj, CSK_Field))
- return false;
- if (!CheckRange(S, OpPC, Obj, CSK_Field))
- return false;
- const Pointer &Field = Obj.atField(I);
- if (!CheckLoad(S, OpPC, Field))
- return false;
- S.Stk.push<T>(Field.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Obj = S.Stk.peek<Pointer>();
- if (!CheckNull(S, OpPC, Obj, CSK_Field))
- return false;
- if (!CheckRange(S, OpPC, Obj, CSK_Field))
- return false;
- const Pointer &Field = Obj.atField(I);
- if (!CheckStore(S, OpPC, Field))
- return false;
- Field.deref<T>() = Value;
- return true;
- }
- /// 1) Pops a pointer from the stack
- /// 2) Pushes the value of the pointer's field on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Obj = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Obj, CSK_Field))
- return false;
- if (!CheckRange(S, OpPC, Obj, CSK_Field))
- return false;
- const Pointer &Field = Obj.atField(I);
- if (!CheckLoad(S, OpPC, Field))
- return false;
- S.Stk.push<T>(Field.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- const Pointer &Field = This.atField(I);
- if (!CheckLoad(S, OpPC, Field))
- return false;
- S.Stk.push<T>(Field.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const T &Value = S.Stk.pop<T>();
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- const Pointer &Field = This.atField(I);
- if (!CheckStore(S, OpPC, Field))
- return false;
- Field.deref<T>() = Value;
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- auto *B = S.P.getGlobal(I);
- if (B->isExtern())
- return false;
- S.Stk.push<T>(B->deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- // TODO: emit warning.
- return false;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- const Pointer &Field = This.atField(I);
- Field.deref<T>() = S.Stk.pop<T>();
- Field.initialize();
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- const Pointer &Field = This.atField(F->Offset);
- const auto &Value = S.Stk.pop<T>();
- Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
- Field.initialize();
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- const Pointer &Field = This.atField(I);
- Field.deref<T>() = S.Stk.pop<T>();
- Field.activate();
- Field.initialize();
- return true;
- }
- /// 1) Pops the value from the stack
- /// 2) Peeks a pointer from the stack
- /// 3) Pushes the value to field I of the pointer on the stack
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
- Field.deref<T>() = Value;
- Field.activate();
- Field.initialize();
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
- Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
- Field.activate();
- Field.initialize();
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- const Pointer &Field = Ptr.atField(I);
- Field.deref<T>() = Value;
- Field.activate();
- Field.initialize();
- return true;
- }
- //===----------------------------------------------------------------------===//
- // GetPtr Local/Param/Global/Field/This
- //===----------------------------------------------------------------------===//
- inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
- return true;
- }
- inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
- if (S.checkingPotentialConstantExpression()) {
- return false;
- }
- S.Stk.push<Pointer>(S.Current->getParamPointer(I));
- return true;
- }
- inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
- return true;
- }
- /// 1) Pops a Pointer from the stack
- /// 2) Pushes Pointer.atField(Off) on the stack
- inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Ptr, CSK_Field))
- return false;
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckRange(S, OpPC, Ptr, CSK_Field))
- return false;
- S.Stk.push<Pointer>(Ptr.atField(Off));
- return true;
- }
- inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- S.Stk.push<Pointer>(This.atField(Off));
- return true;
- }
- inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Ptr, CSK_Field))
- return false;
- if (!CheckRange(S, OpPC, Ptr, CSK_Field))
- return false;
- Pointer Field = Ptr.atField(Off);
- Ptr.deactivate();
- Field.activate();
- S.Stk.push<Pointer>(std::move(Field));
- return true;
- }
- inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- Pointer Field = This.atField(Off);
- This.deactivate();
- Field.activate();
- S.Stk.push<Pointer>(std::move(Field));
- return true;
- }
- inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Ptr, CSK_Base))
- return false;
- S.Stk.push<Pointer>(Ptr.atField(Off));
- return true;
- }
- inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- S.Stk.push<Pointer>(This.atField(Off));
- return true;
- }
- inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
- const Pointer &Ptr) {
- Pointer Base = Ptr;
- while (Base.isBaseClass())
- Base = Base.getBase();
- auto *Field = Base.getRecord()->getVirtualBase(Decl);
- S.Stk.push<Pointer>(Base.atField(Field->Offset));
- return true;
- }
- inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Ptr, CSK_Base))
- return false;
- return VirtBaseHelper(S, OpPC, D, Ptr);
- }
- inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
- const RecordDecl *D) {
- if (S.checkingPotentialConstantExpression())
- return false;
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
- }
- //===----------------------------------------------------------------------===//
- // Load, Store, Init
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Load(InterpState &S, CodePtr OpPC) {
- const Pointer &Ptr = S.Stk.peek<Pointer>();
- if (!CheckLoad(S, OpPC, Ptr))
- return false;
- S.Stk.push<T>(Ptr.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool LoadPop(InterpState &S, CodePtr OpPC) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckLoad(S, OpPC, Ptr))
- return false;
- S.Stk.push<T>(Ptr.deref<T>());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Store(InterpState &S, CodePtr OpPC) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.peek<Pointer>();
- if (!CheckStore(S, OpPC, Ptr))
- return false;
- if (!Ptr.isRoot())
- Ptr.initialize();
- Ptr.deref<T>() = Value;
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool StorePop(InterpState &S, CodePtr OpPC) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckStore(S, OpPC, Ptr))
- return false;
- if (!Ptr.isRoot())
- Ptr.initialize();
- Ptr.deref<T>() = Value;
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool StoreBitField(InterpState &S, CodePtr OpPC) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.peek<Pointer>();
- if (!CheckStore(S, OpPC, Ptr))
- return false;
- if (!Ptr.isRoot())
- Ptr.initialize();
- if (auto *FD = Ptr.getField()) {
- Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
- } else {
- Ptr.deref<T>() = Value;
- }
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckStore(S, OpPC, Ptr))
- return false;
- if (!Ptr.isRoot())
- Ptr.initialize();
- if (auto *FD = Ptr.getField()) {
- Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
- } else {
- Ptr.deref<T>() = Value;
- }
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitPop(InterpState &S, CodePtr OpPC) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckInit(S, OpPC, Ptr))
- return false;
- Ptr.initialize();
- new (&Ptr.deref<T>()) T(Value);
- return true;
- }
- /// 1) Pops the value from the stack
- /// 2) Peeks a pointer and gets its index \Idx
- /// 3) Sets the value on the pointer, leaving the pointer on the stack.
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
- if (!CheckInit(S, OpPC, Ptr))
- return false;
- Ptr.initialize();
- new (&Ptr.deref<T>()) T(Value);
- return true;
- }
- /// The same as InitElem, but pops the pointer as well.
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
- const T &Value = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
- if (!CheckInit(S, OpPC, Ptr))
- return false;
- Ptr.initialize();
- new (&Ptr.deref<T>()) T(Value);
- return true;
- }
- //===----------------------------------------------------------------------===//
- // AddOffset, SubOffset
- //===----------------------------------------------------------------------===//
- template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
- // Fetch the pointer and the offset.
- const T &Offset = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
- return false;
- // A zero offset does not change the pointer.
- if (Offset.isZero()) {
- S.Stk.push<Pointer>(Ptr);
- return true;
- }
- if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
- return false;
- // Arrays of unknown bounds cannot have pointers into them.
- if (!CheckArray(S, OpPC, Ptr))
- return false;
- // Get a version of the index comparable to the type.
- T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
- // Compute the largest index into the array.
- unsigned MaxIndex = Ptr.getNumElems();
- // Helper to report an invalid offset, computed as APSInt.
- auto InvalidOffset = [&]() {
- const unsigned Bits = Offset.bitWidth();
- APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
- APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
- APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
- S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
- << NewIndex
- << /*array*/ static_cast<int>(!Ptr.inArray())
- << static_cast<unsigned>(MaxIndex);
- return false;
- };
- unsigned MaxOffset = MaxIndex - Ptr.getIndex();
- if constexpr (Add) {
- // If the new offset would be negative, bail out.
- if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
- return InvalidOffset();
- // If the new offset would be out of bounds, bail out.
- if (Offset.isPositive() && Offset > MaxOffset)
- return InvalidOffset();
- } else {
- // If the new offset would be negative, bail out.
- if (Offset.isPositive() && Index < Offset)
- return InvalidOffset();
- // If the new offset would be out of bounds, bail out.
- if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
- return InvalidOffset();
- }
- // Offset is valid - compute it on unsigned.
- int64_t WideIndex = static_cast<int64_t>(Index);
- int64_t WideOffset = static_cast<int64_t>(Offset);
- int64_t Result;
- if constexpr (Add)
- Result = WideIndex + WideOffset;
- else
- Result = WideIndex - WideOffset;
- S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool AddOffset(InterpState &S, CodePtr OpPC) {
- return OffsetHelper<T, true>(S, OpPC);
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool SubOffset(InterpState &S, CodePtr OpPC) {
- return OffsetHelper<T, false>(S, OpPC);
- }
- /// 1) Pops a Pointer from the stack.
- /// 2) Pops another Pointer from the stack.
- /// 3) Pushes the different of the indices of the two pointers on the stack.
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- inline bool SubPtr(InterpState &S, CodePtr OpPC) {
- const Pointer &LHS = S.Stk.pop<Pointer>();
- const Pointer &RHS = S.Stk.pop<Pointer>();
- if (!Pointer::hasSameArray(LHS, RHS)) {
- // TODO: Diagnose.
- return false;
- }
- T A = T::from(LHS.getIndex());
- T B = T::from(RHS.getIndex());
- return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
- }
- //===----------------------------------------------------------------------===//
- // Destroy
- //===----------------------------------------------------------------------===//
- inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Current->destroy(I);
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Cast, CastFP
- //===----------------------------------------------------------------------===//
- template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
- using T = typename PrimConv<TIn>::T;
- using U = typename PrimConv<TOut>::T;
- S.Stk.push<U>(U::from(S.Stk.pop<T>()));
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Zero, Nullptr
- //===----------------------------------------------------------------------===//
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- bool Zero(InterpState &S, CodePtr OpPC) {
- S.Stk.push<T>(T::zero());
- return true;
- }
- template <PrimType Name, class T = typename PrimConv<Name>::T>
- inline bool Null(InterpState &S, CodePtr OpPC) {
- S.Stk.push<T>();
- return true;
- }
- //===----------------------------------------------------------------------===//
- // This, ImplicitThis
- //===----------------------------------------------------------------------===//
- inline bool This(InterpState &S, CodePtr OpPC) {
- // Cannot read 'this' in this mode.
- if (S.checkingPotentialConstantExpression()) {
- return false;
- }
- const Pointer &This = S.Current->getThis();
- if (!CheckThis(S, OpPC, This))
- return false;
- S.Stk.push<Pointer>(This);
- return true;
- }
- inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
- assert(S.Current->getFunction()->hasRVO());
- S.Stk.push<Pointer>(S.Current->getRVOPtr());
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Shr, Shl
- //===----------------------------------------------------------------------===//
- template <PrimType NameL, PrimType NameR>
- inline bool Shr(InterpState &S, CodePtr OpPC) {
- using LT = typename PrimConv<NameL>::T;
- using RT = typename PrimConv<NameR>::T;
- const auto &RHS = S.Stk.pop<RT>();
- const auto &LHS = S.Stk.pop<LT>();
- const unsigned Bits = LHS.bitWidth();
- if (!CheckShift<RT>(S, OpPC, RHS, Bits))
- return false;
- unsigned URHS = static_cast<unsigned>(RHS);
- S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
- return true;
- }
- template <PrimType NameL, PrimType NameR>
- inline bool Shl(InterpState &S, CodePtr OpPC) {
- using LT = typename PrimConv<NameL>::T;
- using RT = typename PrimConv<NameR>::T;
- const auto &RHS = S.Stk.pop<RT>();
- const auto &LHS = S.Stk.pop<LT>();
- const unsigned Bits = LHS.bitWidth();
- if (!CheckShift<RT>(S, OpPC, RHS, Bits))
- return false;
- unsigned URHS = static_cast<unsigned>(RHS);
- S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
- return true;
- }
- //===----------------------------------------------------------------------===//
- // NoRet
- //===----------------------------------------------------------------------===//
- inline bool NoRet(InterpState &S, CodePtr OpPC) {
- SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
- S.FFDiag(EndLoc, diag::note_constexpr_no_return);
- return false;
- }
- //===----------------------------------------------------------------------===//
- // NarrowPtr, ExpandPtr
- //===----------------------------------------------------------------------===//
- inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- S.Stk.push<Pointer>(Ptr.narrow());
- return true;
- }
- inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
- S.Stk.push<Pointer>(Ptr.expand());
- return true;
- }
- inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
- auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
- Pointer ThisPtr;
- if (Func->hasThisPointer()) {
- ThisPtr = NewFrame->getThis();
- if (!CheckInvoke(S, PC, ThisPtr)) {
- return false;
- }
- }
- if (!CheckCallable(S, PC, Func))
- return false;
- InterpFrame *FrameBefore = S.Current;
- S.Current = NewFrame.get();
- APValue CallResult;
- // Note that we cannot assert(CallResult.hasValue()) here since
- // Ret() above only sets the APValue if the curent frame doesn't
- // have a caller set.
- if (Interpret(S, CallResult)) {
- NewFrame.release(); // Frame was delete'd already.
- assert(S.Current == FrameBefore);
- // For constructors, check that all fields have been initialized.
- if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
- return false;
- return true;
- }
- // Interpreting the function failed somehow. Reset to
- // previous state.
- S.Current = FrameBefore;
- return false;
- }
- //===----------------------------------------------------------------------===//
- // Read opcode arguments
- //===----------------------------------------------------------------------===//
- template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
- if constexpr (std::is_pointer<T>::value) {
- uint32_t ID = OpPC.read<uint32_t>();
- return reinterpret_cast<T>(S.P.getNativePointer(ID));
- } else {
- return OpPC.read<T>();
- }
- }
- } // namespace interp
- } // namespace clang
- #endif
|