diff options
Diffstat (limited to 'clang/lib/AST/Interp/Interp.h')
-rw-r--r-- | clang/lib/AST/Interp/Interp.h | 960 |
1 files changed, 0 insertions, 960 deletions
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h deleted file mode 100644 index 24c7fb99741..00000000000 --- a/clang/lib/AST/Interp/Interp.h +++ /dev/null @@ -1,960 +0,0 @@ -//===--- 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 "Function.h" -#include "InterpFrame.h" -#include "InterpStack.h" -#include "InterpState.h" -#include "Opcode.h" -#include "Program.h" -#include "State.h" -#include "Type.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 <vector> - -namespace clang { -namespace interp { - -using APInt = llvm::APInt; -using APSInt = llvm::APSInt; - -/// Convers 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 accesible. -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, 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); - -template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); } - -//===----------------------------------------------------------------------===// -// 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.checkingForOverflow()) { - auto Trunc = Value.trunc(Result.bitWidth()).toString(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); -} - -//===----------------------------------------------------------------------===// -// 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()) { - if (LHS.isZero() && RHS.isZero()) - S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); - else - S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Nonequal))); - 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(); - 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) { - S.Stk.push<T>(S.Current->getLocal<T>(I)); - 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; -} - -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; -} - -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; -} - -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.pop<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; -} - -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; - 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; - 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 (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 (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; -} - -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; -} - -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 (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) - return false; - - // Get a version of the index comparable to the type. - T Index = T::from(Ptr.getIndex(), Offset.bitWidth()); - // A zero offset does not change the pointer, but in the case of an array - // it has to be adjusted to point to the first element instead of the array. - if (Offset.isZero()) { - S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr); - return true; - } - // Arrays of unknown bounds cannot have pointers into them. - if (!CheckArray(S, OpPC, Ptr)) - return false; - - // 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; - }; - - // If the new offset would be negative, bail out. - if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index)) - return InvalidOffset(); - if (!Add && Offset.isPositive() && Index < Offset) - return InvalidOffset(); - - // If the new offset would be out of bounds, bail out. - unsigned MaxOffset = MaxIndex - Ptr.getIndex(); - if (Add && Offset.isPositive() && Offset > MaxOffset) - return InvalidOffset(); - if (!Add && 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 = Add ? (WideIndex + WideOffset) : (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); -} - - -//===----------------------------------------------------------------------===// -// 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; -} - -//===----------------------------------------------------------------------===// -// Shr, Shl -//===----------------------------------------------------------------------===// - -template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T> -unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) { - // C++11 [expr.shift]p1: Shift width must be less than the bit width of - // the shifted type. - if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) { - const Expr *E = S.Current->getExpr(OpPC); - const APSInt Val = V.toAPSInt(); - QualType Ty = E->getType(); - S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; - return Bits; - } else { - return static_cast<unsigned>(V); - } -} - -template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T> -inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) { - if (RHS >= V.bitWidth()) { - S.Stk.push<T>(T::from(0, V.bitWidth())); - } else { - S.Stk.push<T>(T::from(V >> RHS, V.bitWidth())); - } - return true; -} - -template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T> -inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) { - if (V.isSigned() && !S.getLangOpts().CPlusPlus2a) { - // C++11 [expr.shift]p2: A signed left shift must have a non-negative - // operand, and must not overflow the corresponding unsigned type. - // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to - // E1 x 2^E2 module 2^N. - if (V.isNegative()) { - const Expr *E = S.Current->getExpr(OpPC); - S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt(); - } else if (V.countLeadingZeros() < RHS) { - S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards); - } - } - - if (V.bitWidth() == 1) { - S.Stk.push<T>(V); - } else if (RHS >= V.bitWidth()) { - S.Stk.push<T>(T::from(0, V.bitWidth())); - } else { - S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth())); - } - return true; -} - -template <PrimType TL, PrimType TR> -inline bool Shr(InterpState &S, CodePtr OpPC) { - const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>(); - const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>(); - const unsigned Bits = LHS.bitWidth(); - - if (RHS.isSigned() && RHS.isNegative()) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); - return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS)); - } else { - return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS)); - } -} - -template <PrimType TL, PrimType TR> -inline bool Shl(InterpState &S, CodePtr OpPC) { - const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>(); - const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>(); - const unsigned Bits = LHS.bitWidth(); - - if (RHS.isSigned() && RHS.isNegative()) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); - return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS)); - } else { - return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS)); - } -} - -//===----------------------------------------------------------------------===// -// 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; -} - -/// Interpreter entry point. -bool Interpret(InterpState &S, APValue &Result); - -} // namespace interp -} // namespace clang - -#endif |