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 Pointer &Ptr,
44 AccessKinds AK);
45bool diagnoseDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
46 AccessKinds AK);
47
48bool arrayElemPtrOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
49 APSInt &&Index, bool AllowReplace = true);
50void noteValueLocation(InterpState &S, const Pointer &Ptr);
51
52/// Checks if a pointer is in range.
53inline bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr,
54 AccessKinds AK) {
55 if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray())
56 return true;
57 if (S.getLangOpts().CPlusPlus)
58 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_access_past_end)
59 << AK << S.Current->getRange(PC: OpPC);
60
61 return false;
62}
63inline bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 AccessKinds AK) {
65 if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray())
66 return true;
67 if (S.getLangOpts().CPlusPlus)
68 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_access_past_end)
69 << AK << S.Current->getRange(PC: OpPC);
70
71 return false;
72}
73
74/// Checks if a field from which a pointer is going to be derived is valid.
75bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76 CheckSubobjectKind CSK);
77
78/// Checks if a pointer points to a mutable field.
79bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr,
80 AccessKinds AK = AK_Read);
81inline bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
82 AccessKinds AK = AK_Read) {
83 if (!Ptr.isBlockPointer())
84 return true;
85 return CheckMutable(S, OpPC, Ptr: Ptr.view(), AK);
86}
87
88/// Checks if a value can be loaded from a block.
89bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
90 AccessKinds AK = AK_Read);
91bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr,
92 AccessKinds AK = AK_Read);
93
94/// Diagnose mismatched new[]/delete or new/delete[] pairs.
95bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
96 DynamicAllocator::Form AllocForm,
97 DynamicAllocator::Form DeleteForm, const Descriptor *D,
98 const Expr *NewExpr);
99
100/// Copy the contents of Src into Dest.
101bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest,
102 bool Activate = true, bool Diagnose = false);
103
104UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx,
105 unsigned Kind, Pointer &Ptr,
106 const Expr *E, bool IsDynamic = false);
107
108bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
109 const Block *B, Lifetime LT = Lifetime::Started,
110 AccessKinds AK = AK_Read);
111
112template <typename T>
113bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
114 const Expr *E = S.Current->getExpr(PC: OpPC);
115 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << SrcValue << E->getType();
116 return S.noteUndefinedBehavior();
117}
118
119inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
120 // Descriptors store the number of elements as unsigned.
121 if (NumElems > std::numeric_limits<unsigned>::max()) {
122 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_too_large)
123 << NumElems;
124 return false;
125 }
126
127 uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
128 if (Limit != 0 && NumElems > Limit) {
129 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
130 DiagId: diag::note_constexpr_new_exceeds_limits, ExtraNotes: 1)
131 << NumElems << Limit;
132 S.Note(Loc: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_steps);
133 return false;
134 }
135 return true;
136}
137
138static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
139 auto RM = FPO.getRoundingMode();
140 if (RM == llvm::RoundingMode::Dynamic)
141 return llvm::RoundingMode::NearestTiesToEven;
142 return RM;
143}
144
145inline bool Invalid(InterpState &S, CodePtr OpPC) {
146 if (S.diagnosing())
147 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
148 DiagId: diag::note_invalid_subexpr_in_const_expr)
149 << S.Current->getRange(PC: OpPC);
150 return false;
151}
152
153template <typename SizeT>
154bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT NumElements,
155 unsigned ElemSize, bool IsNoThrow) {
156
157 if (ElemSize == 0)
158 return true;
159
160 // FIXME: Both the SizeT::from() as well as the
161 // NumElements.toAPSInt() in this function are rather expensive.
162
163 // Can't be too many elements if the bitwidth of NumElements is lower than
164 // that of Descriptor::MaxArrayElemBytes.
165 if ((NumElements.bitWidth() - NumElements.isSigned()) <
166 (sizeof(Descriptor::MaxArrayElemBytes) * 8))
167 return true;
168
169 // FIXME: GH63562
170 // APValue stores array extents as unsigned,
171 // so anything that is greater that unsigned would overflow when
172 // constructing the array, we catch this here.
173 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
174 assert(MaxElements.isPositive());
175 if (NumElements.toAPSInt().getActiveBits() >
176 ConstantArrayType::getMaxSizeBits(Context: S.getASTContext()) ||
177 NumElements > MaxElements) {
178 if (!IsNoThrow) {
179 if (NumElements.isSigned() && NumElements.isNegative()) {
180 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_negative)
181 << NumElements.toDiagnosticString(S.getASTContext());
182 } else {
183 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_too_large)
184 << NumElements.toDiagnosticString(S.getASTContext());
185 }
186 }
187 return false;
188 }
189 return true;
190}
191
192} // namespace interp
193} // namespace clang
194
195#endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
196