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