1//===--- InterpHelpers.h - Interpreter Helper Functions --------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
10#define LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
11
12#include "DynamicAllocator.h"
13#include "InterpState.h"
14#include "Pointer.h"
15
16namespace clang {
17class CallExpr;
18class OffsetOfExpr;
19
20namespace interp {
21class Block;
22struct Descriptor;
23
24/// Interpreter entry point.
25bool Interpret(InterpState &S);
26
27/// Interpret a builtin function.
28bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
29 uint32_t BuiltinID);
30
31/// Interpret an offsetof operation.
32bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
33 ArrayRef<int64_t> ArrayIndices, int64_t &Result);
34
35/// Checks if the array is offsetable.
36bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
37
38/// Checks if a pointer is live and accessible.
39bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
40 AccessKinds AK);
41
42/// Checks if a pointer is a dummy pointer.
43bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
44
45/// Checks if a pointer is in range.
46bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK);
47inline bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
48 AccessKinds AK) {
49 if (!Ptr.isBlockPointer()) {
50 assert(!Ptr.isOnePastEnd());
51 return true;
52 }
53 return CheckRange(S, OpPC, Ptr: Ptr.view(), AK);
54}
55
56/// Checks if a field from which a pointer is going to be derived is valid.
57bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
58 CheckSubobjectKind CSK);
59
60/// Checks if a pointer points to a mutable field.
61bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr,
62 AccessKinds AK = AK_Read);
63inline bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 AccessKinds AK = AK_Read) {
65 if (!Ptr.isBlockPointer())
66 return true;
67 return CheckMutable(S, OpPC, Ptr: Ptr.view(), AK);
68}
69
70/// Checks if a value can be loaded from a block.
71bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72 AccessKinds AK = AK_Read);
73
74/// Diagnose mismatched new[]/delete or new/delete[] pairs.
75bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
76 DynamicAllocator::Form AllocForm,
77 DynamicAllocator::Form DeleteForm, const Descriptor *D,
78 const Expr *NewExpr);
79
80/// Copy the contents of Src into Dest.
81bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
82
83UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx,
84 unsigned Kind, Pointer &Ptr);
85
86template <typename T>
87bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
88 const Expr *E = S.Current->getExpr(PC: OpPC);
89 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << SrcValue << E->getType();
90 return S.noteUndefinedBehavior();
91}
92
93inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
94 uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
95 if (Limit != 0 && NumElems > Limit) {
96 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
97 DiagId: diag::note_constexpr_new_exceeds_limits)
98 << NumElems << Limit;
99 return false;
100 }
101 return true;
102}
103
104static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
105 auto RM = FPO.getRoundingMode();
106 if (RM == llvm::RoundingMode::Dynamic)
107 return llvm::RoundingMode::NearestTiesToEven;
108 return RM;
109}
110
111inline bool Invalid(InterpState &S, CodePtr OpPC) {
112 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
113 S.FFDiag(Loc, DiagId: diag::note_invalid_subexpr_in_const_expr)
114 << S.Current->getRange(PC: OpPC);
115 return false;
116}
117
118template <typename SizeT>
119bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
120 unsigned ElemSize, bool IsNoThrow) {
121
122 if (ElemSize == 0)
123 return true;
124
125 // FIXME: Both the SizeT::from() as well as the
126 // NumElements.toAPSInt() in this function are rather expensive.
127
128 // Can't be too many elements if the bitwidth of NumElements is lower than
129 // that of Descriptor::MaxArrayElemBytes.
130 if ((NumElements->bitWidth() - NumElements->isSigned()) <
131 (sizeof(Descriptor::MaxArrayElemBytes) * 8))
132 return true;
133
134 // FIXME: GH63562
135 // APValue stores array extents as unsigned,
136 // so anything that is greater that unsigned would overflow when
137 // constructing the array, we catch this here.
138 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
139 assert(MaxElements.isPositive());
140 if (NumElements->toAPSInt().getActiveBits() >
141 ConstantArrayType::getMaxSizeBits(Context: S.getASTContext()) ||
142 *NumElements > MaxElements) {
143 if (!IsNoThrow) {
144 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
145
146 if (NumElements->isSigned() && NumElements->isNegative()) {
147 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_new_negative)
148 << NumElements->toDiagnosticString(S.getASTContext());
149 } else {
150 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_new_too_large)
151 << NumElements->toDiagnosticString(S.getASTContext());
152 }
153 }
154 return false;
155 }
156 return true;
157}
158
159} // namespace interp
160} // namespace clang
161
162#endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
163