| //===--- InterpHelpers.h - Interpreter Helper Functions --------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_INTERP_INTERPHELPERS_H |
| #define LLVM_CLANG_AST_INTERP_INTERPHELPERS_H |
| |
| #include "DynamicAllocator.h" |
| #include "InterpState.h" |
| #include "Pointer.h" |
| |
| namespace clang { |
| class CallExpr; |
| class OffsetOfExpr; |
| |
| namespace interp { |
| class Block; |
| struct Descriptor; |
| |
| /// Interpreter entry point. |
| bool Interpret(InterpState &S); |
| |
| /// Interpret a builtin function. |
| bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, |
| uint32_t BuiltinID); |
| |
| /// Interpret an offsetof operation. |
| bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, |
| ArrayRef<int64_t> ArrayIndices, int64_t &Result); |
| |
| /// 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 a dummy pointer. |
| bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); |
| |
| /// 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 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, |
| AccessKinds AK = AK_Read); |
| |
| /// Diagnose mismatched new[]/delete or new/delete[] pairs. |
| bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, |
| DynamicAllocator::Form AllocForm, |
| DynamicAllocator::Form DeleteForm, const Descriptor *D, |
| const Expr *NewExpr); |
| |
| /// Copy the contents of Src into Dest. |
| bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); |
| |
| template <typename T> |
| static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { |
| const Expr *E = S.Current->getExpr(OpPC); |
| S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); |
| return S.noteUndefinedBehavior(); |
| } |
| |
| inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) { |
| uint64_t Limit = S.getLangOpts().ConstexprStepLimit; |
| if (Limit != 0 && NumElems > Limit) { |
| S.FFDiag(S.Current->getSource(OpPC), |
| diag::note_constexpr_new_exceeds_limits) |
| << NumElems << Limit; |
| return false; |
| } |
| return true; |
| } |
| |
| static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { |
| auto RM = FPO.getRoundingMode(); |
| if (RM == llvm::RoundingMode::Dynamic) |
| return llvm::RoundingMode::NearestTiesToEven; |
| return RM; |
| } |
| |
| inline bool Invalid(InterpState &S, CodePtr OpPC) { |
| const SourceLocation &Loc = S.Current->getLocation(OpPC); |
| S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) |
| << S.Current->getRange(OpPC); |
| return false; |
| } |
| |
| template <typename SizeT> |
| bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, |
| unsigned ElemSize, bool IsNoThrow) { |
| // FIXME: Both the SizeT::from() as well as the |
| // NumElements.toAPSInt() in this function are rather expensive. |
| |
| // Can't be too many elements if the bitwidth of NumElements is lower than |
| // that of Descriptor::MaxArrayElemBytes. |
| if ((NumElements->bitWidth() - NumElements->isSigned()) < |
| (sizeof(Descriptor::MaxArrayElemBytes) * 8)) |
| return true; |
| |
| // FIXME: GH63562 |
| // APValue stores array extents as unsigned, |
| // so anything that is greater that unsigned would overflow when |
| // constructing the array, we catch this here. |
| SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); |
| assert(MaxElements.isPositive()); |
| if (NumElements->toAPSInt().getActiveBits() > |
| ConstantArrayType::getMaxSizeBits(S.getASTContext()) || |
| *NumElements > MaxElements) { |
| if (!IsNoThrow) { |
| const SourceInfo &Loc = S.Current->getSource(OpPC); |
| |
| if (NumElements->isSigned() && NumElements->isNegative()) { |
| S.FFDiag(Loc, diag::note_constexpr_new_negative) |
| << NumElements->toDiagnosticString(S.getASTContext()); |
| } else { |
| S.FFDiag(Loc, diag::note_constexpr_new_too_large) |
| << NumElements->toDiagnosticString(S.getASTContext()); |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace interp |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H |