xref: /llvm-project/clang/lib/AST/ByteCode/Interp.h (revision e8674af6f41b2e78ceebabb23e40588c41da5a23)
1a07aba5dSTimm Baeder //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder //
9a07aba5dSTimm Baeder // Definition of the interpreter state and entry point.
10a07aba5dSTimm Baeder //
11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_INTERP_H
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder #include "../ExprConstShared.h"
171fbbf4c4STimm Baeder #include "BitcastBuffer.h"
18a07aba5dSTimm Baeder #include "Boolean.h"
19a07aba5dSTimm Baeder #include "DynamicAllocator.h"
20048bc672STimm Baeder #include "FixedPoint.h"
21a07aba5dSTimm Baeder #include "Floating.h"
22a07aba5dSTimm Baeder #include "Function.h"
23a07aba5dSTimm Baeder #include "FunctionPointer.h"
24ef2a104cSTimm Baeder #include "InterpBuiltinBitCast.h"
25a07aba5dSTimm Baeder #include "InterpFrame.h"
26a07aba5dSTimm Baeder #include "InterpStack.h"
27a07aba5dSTimm Baeder #include "InterpState.h"
28a07aba5dSTimm Baeder #include "MemberPointer.h"
29a07aba5dSTimm Baeder #include "Opcode.h"
30a07aba5dSTimm Baeder #include "PrimType.h"
31a07aba5dSTimm Baeder #include "Program.h"
32a07aba5dSTimm Baeder #include "State.h"
33a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h"
34a07aba5dSTimm Baeder #include "clang/AST/Expr.h"
35a07aba5dSTimm Baeder #include "llvm/ADT/APFloat.h"
36a07aba5dSTimm Baeder #include "llvm/ADT/APSInt.h"
37a07aba5dSTimm Baeder #include <type_traits>
38a07aba5dSTimm Baeder 
39a07aba5dSTimm Baeder namespace clang {
40a07aba5dSTimm Baeder namespace interp {
41a07aba5dSTimm Baeder 
42a07aba5dSTimm Baeder using APSInt = llvm::APSInt;
43641b4d53STimm Baeder using FixedPointSemantics = llvm::FixedPointSemantics;
44a07aba5dSTimm Baeder 
45a07aba5dSTimm Baeder /// Checks if the variable has externally defined storage.
46a07aba5dSTimm Baeder bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
47a07aba5dSTimm Baeder 
48a07aba5dSTimm Baeder /// Checks if the array is offsetable.
49a07aba5dSTimm Baeder bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50a07aba5dSTimm Baeder 
51a07aba5dSTimm Baeder /// Checks if a pointer is live and accessible.
52a07aba5dSTimm Baeder bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
53a07aba5dSTimm Baeder                AccessKinds AK);
54a07aba5dSTimm Baeder 
55a07aba5dSTimm Baeder /// Checks if a pointer is a dummy pointer.
56a07aba5dSTimm Baeder bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57a07aba5dSTimm Baeder                 AccessKinds AK);
58a07aba5dSTimm Baeder 
59a07aba5dSTimm Baeder /// Checks if a pointer is null.
60a07aba5dSTimm Baeder bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
61a07aba5dSTimm Baeder                CheckSubobjectKind CSK);
62a07aba5dSTimm Baeder 
63a07aba5dSTimm Baeder /// Checks if a pointer is in range.
64a07aba5dSTimm Baeder bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
65a07aba5dSTimm Baeder                 AccessKinds AK);
66a07aba5dSTimm Baeder 
67a07aba5dSTimm Baeder /// Checks if a field from which a pointer is going to be derived is valid.
68a07aba5dSTimm Baeder bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
69a07aba5dSTimm Baeder                 CheckSubobjectKind CSK);
70a07aba5dSTimm Baeder 
71a07aba5dSTimm Baeder /// Checks if Ptr is a one-past-the-end pointer.
72a07aba5dSTimm Baeder bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
73a07aba5dSTimm Baeder                     CheckSubobjectKind CSK);
74a07aba5dSTimm Baeder 
75a07aba5dSTimm Baeder /// Checks if the dowcast using the given offset is possible with the given
76a07aba5dSTimm Baeder /// pointer.
77a07aba5dSTimm Baeder bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
78a07aba5dSTimm Baeder                    uint32_t Offset);
79a07aba5dSTimm Baeder 
80a07aba5dSTimm Baeder /// Checks if a pointer points to const storage.
81a07aba5dSTimm Baeder bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82a07aba5dSTimm Baeder 
83a07aba5dSTimm Baeder /// Checks if the Descriptor is of a constexpr or const global variable.
84a07aba5dSTimm Baeder bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
85a07aba5dSTimm Baeder 
86a07aba5dSTimm Baeder /// Checks if a pointer points to a mutable field.
87a07aba5dSTimm Baeder bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88a07aba5dSTimm Baeder 
89a07aba5dSTimm Baeder /// Checks if a value can be loaded from a block.
90a07aba5dSTimm Baeder bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
91a07aba5dSTimm Baeder                AccessKinds AK = AK_Read);
92a14c7309STimm Baeder bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93a07aba5dSTimm Baeder 
94a07aba5dSTimm Baeder bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
95a07aba5dSTimm Baeder                       AccessKinds AK);
96a07aba5dSTimm Baeder /// Check if a global variable is initialized.
97a07aba5dSTimm Baeder bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
98a07aba5dSTimm Baeder 
99a07aba5dSTimm Baeder /// Checks if a value can be stored in a block.
100a07aba5dSTimm Baeder bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
101a07aba5dSTimm Baeder 
102a07aba5dSTimm Baeder /// Checks if a method can be invoked on an object.
103a07aba5dSTimm Baeder bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
104a07aba5dSTimm Baeder 
105a07aba5dSTimm Baeder /// Checks if a value can be initialized.
106a07aba5dSTimm Baeder bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
107a07aba5dSTimm Baeder 
108a07aba5dSTimm Baeder /// Checks if a method can be called.
109a07aba5dSTimm Baeder bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
110a07aba5dSTimm Baeder 
111a07aba5dSTimm Baeder /// Checks if calling the currently active function would exceed
112a07aba5dSTimm Baeder /// the allowed call depth.
113a07aba5dSTimm Baeder bool CheckCallDepth(InterpState &S, CodePtr OpPC);
114a07aba5dSTimm Baeder 
115a07aba5dSTimm Baeder /// Checks the 'this' pointer.
116a07aba5dSTimm Baeder bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
117a07aba5dSTimm Baeder 
118a07aba5dSTimm Baeder /// Checks if a method is pure virtual.
119a07aba5dSTimm Baeder bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
120a07aba5dSTimm Baeder 
121a07aba5dSTimm Baeder /// Checks if all the arguments annotated as 'nonnull' are in fact not null.
122a07aba5dSTimm Baeder bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
123a07aba5dSTimm Baeder                       const CallExpr *CE, unsigned ArgSize);
124a07aba5dSTimm Baeder 
125a07aba5dSTimm Baeder /// Checks if dynamic memory allocation is available in the current
126a07aba5dSTimm Baeder /// language mode.
127a07aba5dSTimm Baeder bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
128a07aba5dSTimm Baeder 
129a07aba5dSTimm Baeder /// Diagnose mismatched new[]/delete or new/delete[] pairs.
130610b8539STimm Baeder bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
131610b8539STimm Baeder                          DynamicAllocator::Form AllocForm,
132610b8539STimm Baeder                          DynamicAllocator::Form DeleteForm, const Descriptor *D,
133a07aba5dSTimm Baeder                          const Expr *NewExpr);
134a07aba5dSTimm Baeder 
135a07aba5dSTimm Baeder /// Check the source of the pointer passed to delete/delete[] has actually
136a07aba5dSTimm Baeder /// been heap allocated by us.
137a07aba5dSTimm Baeder bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
138a07aba5dSTimm Baeder                        const Pointer &Ptr);
139a07aba5dSTimm Baeder 
140a07aba5dSTimm Baeder /// Sets the given integral value to the pointer, which is of
141a07aba5dSTimm Baeder /// a std::{weak,partial,strong}_ordering type.
142a07aba5dSTimm Baeder bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
143a07aba5dSTimm Baeder                                 const Pointer &Ptr, const APSInt &IntValue);
144a07aba5dSTimm Baeder 
145a07aba5dSTimm Baeder /// Copy the contents of Src into Dest.
146a07aba5dSTimm Baeder bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
147a07aba5dSTimm Baeder 
148f70ccdaeSTimm Baeder bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
149f70ccdaeSTimm Baeder              uint32_t VarArgSize);
150f70ccdaeSTimm Baeder bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
151f70ccdaeSTimm Baeder           uint32_t VarArgSize);
152f70ccdaeSTimm Baeder bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
153f70ccdaeSTimm Baeder               uint32_t VarArgSize);
15446870175STimm Bäder bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func,
15578cf9b83STimm Baeder             const CallExpr *CE, uint32_t BuiltinID);
156f70ccdaeSTimm Baeder bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
157f70ccdaeSTimm Baeder              const CallExpr *CE);
158f86050deSTimm Baeder bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
159fed8695bSTimm Baeder bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
160ef2a104cSTimm Baeder bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
161ef2a104cSTimm Baeder                   bool TargetIsUCharOrByte);
162f70ccdaeSTimm Baeder 
16395ce78b7STimm Baeder template <typename T>
16495ce78b7STimm Baeder static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
16595ce78b7STimm Baeder   const Expr *E = S.Current->getExpr(OpPC);
16695ce78b7STimm Baeder   S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
16795ce78b7STimm Baeder   return S.noteUndefinedBehavior();
16895ce78b7STimm Baeder }
16995ce78b7STimm Baeder bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
17095ce78b7STimm Baeder                               const FixedPoint &FP);
17195ce78b7STimm Baeder 
1720050503bSTimm Baeder enum class ShiftDir { Left, Right };
1730050503bSTimm Baeder 
174a07aba5dSTimm Baeder /// Checks if the shift operation is legal.
1750050503bSTimm Baeder template <ShiftDir Dir, typename LT, typename RT>
176a07aba5dSTimm Baeder bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
177a07aba5dSTimm Baeder                 unsigned Bits) {
178a07aba5dSTimm Baeder   if (RHS.isNegative()) {
179a07aba5dSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
180a07aba5dSTimm Baeder     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
181a07aba5dSTimm Baeder     if (!S.noteUndefinedBehavior())
182a07aba5dSTimm Baeder       return false;
183a07aba5dSTimm Baeder   }
184a07aba5dSTimm Baeder 
185a07aba5dSTimm Baeder   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
186a07aba5dSTimm Baeder   // the shifted type.
187a07aba5dSTimm Baeder   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
188a07aba5dSTimm Baeder     const Expr *E = S.Current->getExpr(OpPC);
189a07aba5dSTimm Baeder     const APSInt Val = RHS.toAPSInt();
190a07aba5dSTimm Baeder     QualType Ty = E->getType();
191a07aba5dSTimm Baeder     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
192a07aba5dSTimm Baeder     if (!S.noteUndefinedBehavior())
193a07aba5dSTimm Baeder       return false;
194a07aba5dSTimm Baeder   }
195a07aba5dSTimm Baeder 
1960050503bSTimm Baeder   if constexpr (Dir == ShiftDir::Left) {
197a07aba5dSTimm Baeder     if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
198a07aba5dSTimm Baeder       const Expr *E = S.Current->getExpr(OpPC);
199a07aba5dSTimm Baeder       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
200a07aba5dSTimm Baeder       // operand, and must not overflow the corresponding unsigned type.
201a07aba5dSTimm Baeder       if (LHS.isNegative()) {
202a07aba5dSTimm Baeder         S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
203a07aba5dSTimm Baeder         if (!S.noteUndefinedBehavior())
204a07aba5dSTimm Baeder           return false;
205a07aba5dSTimm Baeder       } else if (LHS.toUnsigned().countLeadingZeros() <
206a07aba5dSTimm Baeder                  static_cast<unsigned>(RHS)) {
207a07aba5dSTimm Baeder         S.CCEDiag(E, diag::note_constexpr_lshift_discards);
208a07aba5dSTimm Baeder         if (!S.noteUndefinedBehavior())
209a07aba5dSTimm Baeder           return false;
210a07aba5dSTimm Baeder       }
211a07aba5dSTimm Baeder     }
2120050503bSTimm Baeder   }
213a07aba5dSTimm Baeder 
214a07aba5dSTimm Baeder   // C++2a [expr.shift]p2: [P0907R4]:
215a07aba5dSTimm Baeder   //    E1 << E2 is the unique value congruent to
216a07aba5dSTimm Baeder   //    E1 x 2^E2 module 2^N.
217a07aba5dSTimm Baeder   return true;
218a07aba5dSTimm Baeder }
219a07aba5dSTimm Baeder 
220a07aba5dSTimm Baeder /// Checks if Div/Rem operation on LHS and RHS is valid.
221a07aba5dSTimm Baeder template <typename T>
222a07aba5dSTimm Baeder bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
223a07aba5dSTimm Baeder   if (RHS.isZero()) {
224a07aba5dSTimm Baeder     const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
225a07aba5dSTimm Baeder     if constexpr (std::is_same_v<T, Floating>) {
226a07aba5dSTimm Baeder       S.CCEDiag(Op, diag::note_expr_divide_by_zero)
227a07aba5dSTimm Baeder           << Op->getRHS()->getSourceRange();
228a07aba5dSTimm Baeder       return true;
229a07aba5dSTimm Baeder     }
230a07aba5dSTimm Baeder 
231a07aba5dSTimm Baeder     S.FFDiag(Op, diag::note_expr_divide_by_zero)
232a07aba5dSTimm Baeder         << Op->getRHS()->getSourceRange();
233a07aba5dSTimm Baeder     return false;
234a07aba5dSTimm Baeder   }
235a07aba5dSTimm Baeder 
23679382eb9STimm Baeder   if constexpr (!std::is_same_v<T, FixedPoint>) {
237a07aba5dSTimm Baeder     if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
238a07aba5dSTimm Baeder       APSInt LHSInt = LHS.toAPSInt();
239a07aba5dSTimm Baeder       SmallString<32> Trunc;
240a07aba5dSTimm Baeder       (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
241a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
242a07aba5dSTimm Baeder       const Expr *E = S.Current->getExpr(OpPC);
243a07aba5dSTimm Baeder       S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
244a07aba5dSTimm Baeder       return false;
245a07aba5dSTimm Baeder     }
24679382eb9STimm Baeder   }
247a07aba5dSTimm Baeder   return true;
248a07aba5dSTimm Baeder }
249a07aba5dSTimm Baeder 
250a07aba5dSTimm Baeder template <typename SizeT>
251a07aba5dSTimm Baeder bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
252a07aba5dSTimm Baeder                     unsigned ElemSize, bool IsNoThrow) {
253a07aba5dSTimm Baeder   // FIXME: Both the SizeT::from() as well as the
254a07aba5dSTimm Baeder   // NumElements.toAPSInt() in this function are rather expensive.
255a07aba5dSTimm Baeder 
2569a32f283STimm Baeder   // Can't be too many elements if the bitwidth of NumElements is lower than
2579a32f283STimm Baeder   // that of Descriptor::MaxArrayElemBytes.
2589a32f283STimm Baeder   if ((NumElements->bitWidth() - NumElements->isSigned()) <
2599a32f283STimm Baeder       (sizeof(Descriptor::MaxArrayElemBytes) * 8))
2609a32f283STimm Baeder     return true;
2619a32f283STimm Baeder 
262a07aba5dSTimm Baeder   // FIXME: GH63562
263a07aba5dSTimm Baeder   // APValue stores array extents as unsigned,
264a07aba5dSTimm Baeder   // so anything that is greater that unsigned would overflow when
265a07aba5dSTimm Baeder   // constructing the array, we catch this here.
266a07aba5dSTimm Baeder   SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
2679a32f283STimm Baeder   assert(MaxElements.isPositive());
268a07aba5dSTimm Baeder   if (NumElements->toAPSInt().getActiveBits() >
269d9e72860Syronglin           ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
270a07aba5dSTimm Baeder       *NumElements > MaxElements) {
271a07aba5dSTimm Baeder     if (!IsNoThrow) {
272a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
273ccb7cc31STimm Baeder 
274ccb7cc31STimm Baeder       if (NumElements->isSigned() && NumElements->isNegative()) {
275ccb7cc31STimm Baeder         S.FFDiag(Loc, diag::note_constexpr_new_negative)
276ccb7cc31STimm Baeder             << NumElements->toDiagnosticString(S.getASTContext());
277ccb7cc31STimm Baeder       } else {
278a07aba5dSTimm Baeder         S.FFDiag(Loc, diag::note_constexpr_new_too_large)
279d9e72860Syronglin             << NumElements->toDiagnosticString(S.getASTContext());
280a07aba5dSTimm Baeder       }
281ccb7cc31STimm Baeder     }
282a07aba5dSTimm Baeder     return false;
283a07aba5dSTimm Baeder   }
284a07aba5dSTimm Baeder   return true;
285a07aba5dSTimm Baeder }
286a07aba5dSTimm Baeder 
287a07aba5dSTimm Baeder /// Checks if the result of a floating-point operation is valid
288a07aba5dSTimm Baeder /// in the current context.
289a07aba5dSTimm Baeder bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
2900f5f440fSTimm Baeder                       APFloat::opStatus Status, FPOptions FPO);
291a07aba5dSTimm Baeder 
292a07aba5dSTimm Baeder /// Checks why the given DeclRefExpr is invalid.
293a07aba5dSTimm Baeder bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
294a07aba5dSTimm Baeder 
295a07aba5dSTimm Baeder /// Interpreter entry point.
29682ed9c03STimm Baeder bool Interpret(InterpState &S);
297a07aba5dSTimm Baeder 
298a07aba5dSTimm Baeder /// Interpret a builtin function.
299a07aba5dSTimm Baeder bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
30078cf9b83STimm Baeder                       const CallExpr *Call, uint32_t BuiltinID);
301a07aba5dSTimm Baeder 
302a07aba5dSTimm Baeder /// Interpret an offsetof operation.
303a07aba5dSTimm Baeder bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
304a07aba5dSTimm Baeder                        llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
305a07aba5dSTimm Baeder 
306a07aba5dSTimm Baeder inline bool Invalid(InterpState &S, CodePtr OpPC);
307a07aba5dSTimm Baeder 
308a07aba5dSTimm Baeder enum class ArithOp { Add, Sub };
309a07aba5dSTimm Baeder 
310a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
311a07aba5dSTimm Baeder // Returning values
312a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
313a07aba5dSTimm Baeder 
31483fea8b8STimm Baeder void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
31583fea8b8STimm Baeder                               const Function *Func);
316a07aba5dSTimm Baeder 
317a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
31882ed9c03STimm Baeder bool Ret(InterpState &S, CodePtr &PC) {
319a07aba5dSTimm Baeder   const T &Ret = S.Stk.pop<T>();
320a07aba5dSTimm Baeder 
321a07aba5dSTimm Baeder   assert(S.Current);
322a07aba5dSTimm Baeder   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
323a07aba5dSTimm Baeder   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
32483fea8b8STimm Baeder     cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
325a07aba5dSTimm Baeder 
326a07aba5dSTimm Baeder   if (InterpFrame *Caller = S.Current->Caller) {
327a07aba5dSTimm Baeder     PC = S.Current->getRetPC();
328a07aba5dSTimm Baeder     delete S.Current;
329a07aba5dSTimm Baeder     S.Current = Caller;
330a07aba5dSTimm Baeder     S.Stk.push<T>(Ret);
331a07aba5dSTimm Baeder   } else {
332a07aba5dSTimm Baeder     delete S.Current;
333a07aba5dSTimm Baeder     S.Current = nullptr;
33482ed9c03STimm Baeder     // The topmost frame should come from an EvalEmitter,
33582ed9c03STimm Baeder     // which has its own implementation of the Ret<> instruction.
336a07aba5dSTimm Baeder   }
337a07aba5dSTimm Baeder   return true;
338a07aba5dSTimm Baeder }
339a07aba5dSTimm Baeder 
34082ed9c03STimm Baeder inline bool RetVoid(InterpState &S, CodePtr &PC) {
341a07aba5dSTimm Baeder   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
342a07aba5dSTimm Baeder 
343a07aba5dSTimm Baeder   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
34483fea8b8STimm Baeder     cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
345a07aba5dSTimm Baeder 
346a07aba5dSTimm Baeder   if (InterpFrame *Caller = S.Current->Caller) {
347a07aba5dSTimm Baeder     PC = S.Current->getRetPC();
348a07aba5dSTimm Baeder     delete S.Current;
349a07aba5dSTimm Baeder     S.Current = Caller;
350a07aba5dSTimm Baeder   } else {
351a07aba5dSTimm Baeder     delete S.Current;
352a07aba5dSTimm Baeder     S.Current = nullptr;
353a07aba5dSTimm Baeder   }
354a07aba5dSTimm Baeder   return true;
355a07aba5dSTimm Baeder }
356a07aba5dSTimm Baeder 
357a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
358a07aba5dSTimm Baeder // Add, Sub, Mul
359a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
360a07aba5dSTimm Baeder 
361a07aba5dSTimm Baeder template <typename T, bool (*OpFW)(T, T, unsigned, T *),
362a07aba5dSTimm Baeder           template <typename U> class OpAP>
363a07aba5dSTimm Baeder bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
364a07aba5dSTimm Baeder                      const T &RHS) {
365a07aba5dSTimm Baeder   // Fast path - add the numbers with fixed width.
366a07aba5dSTimm Baeder   T Result;
367a07aba5dSTimm Baeder   if (!OpFW(LHS, RHS, Bits, &Result)) {
368a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
369a07aba5dSTimm Baeder     return true;
370a07aba5dSTimm Baeder   }
371a07aba5dSTimm Baeder   // If for some reason evaluation continues, use the truncated results.
372a07aba5dSTimm Baeder   S.Stk.push<T>(Result);
373a07aba5dSTimm Baeder 
3745c811cccSTimm Baeder   // Short-circuit fixed-points here since the error handling is easier.
3755c811cccSTimm Baeder   if constexpr (std::is_same_v<T, FixedPoint>)
3765c811cccSTimm Baeder     return handleFixedPointOverflow(S, OpPC, Result);
3775c811cccSTimm Baeder 
378a07aba5dSTimm Baeder   // Slow path - compute the result using another bit of precision.
379a07aba5dSTimm Baeder   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
380a07aba5dSTimm Baeder 
381a07aba5dSTimm Baeder   // Report undefined behaviour, stopping if required.
382a07aba5dSTimm Baeder   const Expr *E = S.Current->getExpr(OpPC);
383a07aba5dSTimm Baeder   QualType Type = E->getType();
384a07aba5dSTimm Baeder   if (S.checkingForUndefinedBehavior()) {
385a07aba5dSTimm Baeder     SmallString<32> Trunc;
386a07aba5dSTimm Baeder     Value.trunc(Result.bitWidth())
387a07aba5dSTimm Baeder         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
388a07aba5dSTimm Baeder                   /*UpperCase=*/true, /*InsertSeparators=*/true);
389a07aba5dSTimm Baeder     auto Loc = E->getExprLoc();
390a07aba5dSTimm Baeder     S.report(Loc, diag::warn_integer_constant_overflow)
391a07aba5dSTimm Baeder         << Trunc << Type << E->getSourceRange();
392a07aba5dSTimm Baeder   }
393a07aba5dSTimm Baeder 
39495ce78b7STimm Baeder   if (!handleOverflow(S, OpPC, Value)) {
395a07aba5dSTimm Baeder     S.Stk.pop<T>();
396a07aba5dSTimm Baeder     return false;
397a07aba5dSTimm Baeder   }
398a07aba5dSTimm Baeder   return true;
399a07aba5dSTimm Baeder }
400a07aba5dSTimm Baeder 
401a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
402a07aba5dSTimm Baeder bool Add(InterpState &S, CodePtr OpPC) {
403a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
404a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
405a07aba5dSTimm Baeder   const unsigned Bits = RHS.bitWidth() + 1;
406a07aba5dSTimm Baeder   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
407a07aba5dSTimm Baeder }
408a07aba5dSTimm Baeder 
4090f5f440fSTimm Baeder static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
4100f5f440fSTimm Baeder   auto RM = FPO.getRoundingMode();
4110f5f440fSTimm Baeder   if (RM == llvm::RoundingMode::Dynamic)
4120f5f440fSTimm Baeder     return llvm::RoundingMode::NearestTiesToEven;
4130f5f440fSTimm Baeder   return RM;
4140f5f440fSTimm Baeder }
4150f5f440fSTimm Baeder 
4160f5f440fSTimm Baeder inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
417a07aba5dSTimm Baeder   const Floating &RHS = S.Stk.pop<Floating>();
418a07aba5dSTimm Baeder   const Floating &LHS = S.Stk.pop<Floating>();
419a07aba5dSTimm Baeder 
4200f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
421a07aba5dSTimm Baeder   Floating Result;
4220f5f440fSTimm Baeder   auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
423a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
4240f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
425a07aba5dSTimm Baeder }
426a07aba5dSTimm Baeder 
427a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
428a07aba5dSTimm Baeder bool Sub(InterpState &S, CodePtr OpPC) {
429a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
430a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
431a07aba5dSTimm Baeder   const unsigned Bits = RHS.bitWidth() + 1;
432a07aba5dSTimm Baeder   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
433a07aba5dSTimm Baeder }
434a07aba5dSTimm Baeder 
4350f5f440fSTimm Baeder inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
436a07aba5dSTimm Baeder   const Floating &RHS = S.Stk.pop<Floating>();
437a07aba5dSTimm Baeder   const Floating &LHS = S.Stk.pop<Floating>();
438a07aba5dSTimm Baeder 
4390f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
440a07aba5dSTimm Baeder   Floating Result;
4410f5f440fSTimm Baeder   auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
442a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
4430f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
444a07aba5dSTimm Baeder }
445a07aba5dSTimm Baeder 
446a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
447a07aba5dSTimm Baeder bool Mul(InterpState &S, CodePtr OpPC) {
448a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
449a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
450a07aba5dSTimm Baeder   const unsigned Bits = RHS.bitWidth() * 2;
451a07aba5dSTimm Baeder   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
452a07aba5dSTimm Baeder }
453a07aba5dSTimm Baeder 
4540f5f440fSTimm Baeder inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
455a07aba5dSTimm Baeder   const Floating &RHS = S.Stk.pop<Floating>();
456a07aba5dSTimm Baeder   const Floating &LHS = S.Stk.pop<Floating>();
457a07aba5dSTimm Baeder 
4580f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
459a07aba5dSTimm Baeder   Floating Result;
4600f5f440fSTimm Baeder   auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
461a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
4620f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
463a07aba5dSTimm Baeder }
464a07aba5dSTimm Baeder 
465a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
466a07aba5dSTimm Baeder inline bool Mulc(InterpState &S, CodePtr OpPC) {
467a07aba5dSTimm Baeder   const Pointer &RHS = S.Stk.pop<Pointer>();
468a07aba5dSTimm Baeder   const Pointer &LHS = S.Stk.pop<Pointer>();
469a07aba5dSTimm Baeder   const Pointer &Result = S.Stk.peek<Pointer>();
470a07aba5dSTimm Baeder 
471a07aba5dSTimm Baeder   if constexpr (std::is_same_v<T, Floating>) {
472a07aba5dSTimm Baeder     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
473a07aba5dSTimm Baeder     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
474a07aba5dSTimm Baeder     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
475a07aba5dSTimm Baeder     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
476a07aba5dSTimm Baeder 
477a07aba5dSTimm Baeder     APFloat ResR(A.getSemantics());
478a07aba5dSTimm Baeder     APFloat ResI(A.getSemantics());
479a07aba5dSTimm Baeder     HandleComplexComplexMul(A, B, C, D, ResR, ResI);
480a07aba5dSTimm Baeder 
481a07aba5dSTimm Baeder     // Copy into the result.
482a07aba5dSTimm Baeder     Result.atIndex(0).deref<Floating>() = Floating(ResR);
483a07aba5dSTimm Baeder     Result.atIndex(0).initialize();
484a07aba5dSTimm Baeder     Result.atIndex(1).deref<Floating>() = Floating(ResI);
485a07aba5dSTimm Baeder     Result.atIndex(1).initialize();
486a07aba5dSTimm Baeder     Result.initialize();
487a07aba5dSTimm Baeder   } else {
488a07aba5dSTimm Baeder     // Integer element type.
489a07aba5dSTimm Baeder     const T &LHSR = LHS.atIndex(0).deref<T>();
490a07aba5dSTimm Baeder     const T &LHSI = LHS.atIndex(1).deref<T>();
491a07aba5dSTimm Baeder     const T &RHSR = RHS.atIndex(0).deref<T>();
492a07aba5dSTimm Baeder     const T &RHSI = RHS.atIndex(1).deref<T>();
493a07aba5dSTimm Baeder     unsigned Bits = LHSR.bitWidth();
494a07aba5dSTimm Baeder 
495a07aba5dSTimm Baeder     // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
496a07aba5dSTimm Baeder     T A;
497a07aba5dSTimm Baeder     if (T::mul(LHSR, RHSR, Bits, &A))
498a07aba5dSTimm Baeder       return false;
499a07aba5dSTimm Baeder     T B;
500a07aba5dSTimm Baeder     if (T::mul(LHSI, RHSI, Bits, &B))
501a07aba5dSTimm Baeder       return false;
502a07aba5dSTimm Baeder     if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
503a07aba5dSTimm Baeder       return false;
504a07aba5dSTimm Baeder     Result.atIndex(0).initialize();
505a07aba5dSTimm Baeder 
506a07aba5dSTimm Baeder     // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
507a07aba5dSTimm Baeder     if (T::mul(LHSR, RHSI, Bits, &A))
508a07aba5dSTimm Baeder       return false;
509a07aba5dSTimm Baeder     if (T::mul(LHSI, RHSR, Bits, &B))
510a07aba5dSTimm Baeder       return false;
511a07aba5dSTimm Baeder     if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
512a07aba5dSTimm Baeder       return false;
513a07aba5dSTimm Baeder     Result.atIndex(1).initialize();
514a07aba5dSTimm Baeder     Result.initialize();
515a07aba5dSTimm Baeder   }
516a07aba5dSTimm Baeder 
517a07aba5dSTimm Baeder   return true;
518a07aba5dSTimm Baeder }
519a07aba5dSTimm Baeder 
520a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
521a07aba5dSTimm Baeder inline bool Divc(InterpState &S, CodePtr OpPC) {
522a07aba5dSTimm Baeder   const Pointer &RHS = S.Stk.pop<Pointer>();
523a07aba5dSTimm Baeder   const Pointer &LHS = S.Stk.pop<Pointer>();
524a07aba5dSTimm Baeder   const Pointer &Result = S.Stk.peek<Pointer>();
525a07aba5dSTimm Baeder 
526a07aba5dSTimm Baeder   if constexpr (std::is_same_v<T, Floating>) {
527a07aba5dSTimm Baeder     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
528a07aba5dSTimm Baeder     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
529a07aba5dSTimm Baeder     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
530a07aba5dSTimm Baeder     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
531a07aba5dSTimm Baeder 
532a07aba5dSTimm Baeder     APFloat ResR(A.getSemantics());
533a07aba5dSTimm Baeder     APFloat ResI(A.getSemantics());
534a07aba5dSTimm Baeder     HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
535a07aba5dSTimm Baeder 
536a07aba5dSTimm Baeder     // Copy into the result.
537a07aba5dSTimm Baeder     Result.atIndex(0).deref<Floating>() = Floating(ResR);
538a07aba5dSTimm Baeder     Result.atIndex(0).initialize();
539a07aba5dSTimm Baeder     Result.atIndex(1).deref<Floating>() = Floating(ResI);
540a07aba5dSTimm Baeder     Result.atIndex(1).initialize();
541a07aba5dSTimm Baeder     Result.initialize();
542a07aba5dSTimm Baeder   } else {
543a07aba5dSTimm Baeder     // Integer element type.
544a07aba5dSTimm Baeder     const T &LHSR = LHS.atIndex(0).deref<T>();
545a07aba5dSTimm Baeder     const T &LHSI = LHS.atIndex(1).deref<T>();
546a07aba5dSTimm Baeder     const T &RHSR = RHS.atIndex(0).deref<T>();
547a07aba5dSTimm Baeder     const T &RHSI = RHS.atIndex(1).deref<T>();
548a07aba5dSTimm Baeder     unsigned Bits = LHSR.bitWidth();
549a07aba5dSTimm Baeder     const T Zero = T::from(0, Bits);
550a07aba5dSTimm Baeder 
551a07aba5dSTimm Baeder     if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
552a07aba5dSTimm Baeder         Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
553a07aba5dSTimm Baeder       const SourceInfo &E = S.Current->getSource(OpPC);
554a07aba5dSTimm Baeder       S.FFDiag(E, diag::note_expr_divide_by_zero);
555a07aba5dSTimm Baeder       return false;
556a07aba5dSTimm Baeder     }
557a07aba5dSTimm Baeder 
558a07aba5dSTimm Baeder     // Den = real(RHS)² + imag(RHS)²
559a07aba5dSTimm Baeder     T A, B;
56040db2615STimm Baeder     if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
56140db2615STimm Baeder       // Ignore overflow here, because that's what the current interpeter does.
56240db2615STimm Baeder     }
563a07aba5dSTimm Baeder     T Den;
564a07aba5dSTimm Baeder     if (T::add(A, B, Bits, &Den))
565a07aba5dSTimm Baeder       return false;
566a07aba5dSTimm Baeder 
56740db2615STimm Baeder     if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) {
56840db2615STimm Baeder       const SourceInfo &E = S.Current->getSource(OpPC);
56940db2615STimm Baeder       S.FFDiag(E, diag::note_expr_divide_by_zero);
57040db2615STimm Baeder       return false;
57140db2615STimm Baeder     }
57240db2615STimm Baeder 
573a07aba5dSTimm Baeder     // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
574a07aba5dSTimm Baeder     T &ResultR = Result.atIndex(0).deref<T>();
575a07aba5dSTimm Baeder     T &ResultI = Result.atIndex(1).deref<T>();
576a07aba5dSTimm Baeder 
577a07aba5dSTimm Baeder     if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
578a07aba5dSTimm Baeder       return false;
579a07aba5dSTimm Baeder     if (T::add(A, B, Bits, &ResultR))
580a07aba5dSTimm Baeder       return false;
581a07aba5dSTimm Baeder     if (T::div(ResultR, Den, Bits, &ResultR))
582a07aba5dSTimm Baeder       return false;
583a07aba5dSTimm Baeder     Result.atIndex(0).initialize();
584a07aba5dSTimm Baeder 
585a07aba5dSTimm Baeder     // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
586a07aba5dSTimm Baeder     if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
587a07aba5dSTimm Baeder       return false;
588a07aba5dSTimm Baeder     if (T::sub(A, B, Bits, &ResultI))
589a07aba5dSTimm Baeder       return false;
590a07aba5dSTimm Baeder     if (T::div(ResultI, Den, Bits, &ResultI))
591a07aba5dSTimm Baeder       return false;
592a07aba5dSTimm Baeder     Result.atIndex(1).initialize();
593a07aba5dSTimm Baeder     Result.initialize();
594a07aba5dSTimm Baeder   }
595a07aba5dSTimm Baeder 
596a07aba5dSTimm Baeder   return true;
597a07aba5dSTimm Baeder }
598a07aba5dSTimm Baeder 
599a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack.
600a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack.
601a07aba5dSTimm Baeder /// 3) Pushes 'LHS & RHS' on the stack
602a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
603a07aba5dSTimm Baeder bool BitAnd(InterpState &S, CodePtr OpPC) {
604a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
605a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
606a07aba5dSTimm Baeder 
607a07aba5dSTimm Baeder   unsigned Bits = RHS.bitWidth();
608a07aba5dSTimm Baeder   T Result;
609a07aba5dSTimm Baeder   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
610a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
611a07aba5dSTimm Baeder     return true;
612a07aba5dSTimm Baeder   }
613a07aba5dSTimm Baeder   return false;
614a07aba5dSTimm Baeder }
615a07aba5dSTimm Baeder 
616a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack.
617a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack.
618a07aba5dSTimm Baeder /// 3) Pushes 'LHS | RHS' on the stack
619a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
620a07aba5dSTimm Baeder bool BitOr(InterpState &S, CodePtr OpPC) {
621a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
622a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
623a07aba5dSTimm Baeder 
624a07aba5dSTimm Baeder   unsigned Bits = RHS.bitWidth();
625a07aba5dSTimm Baeder   T Result;
626a07aba5dSTimm Baeder   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
627a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
628a07aba5dSTimm Baeder     return true;
629a07aba5dSTimm Baeder   }
630a07aba5dSTimm Baeder   return false;
631a07aba5dSTimm Baeder }
632a07aba5dSTimm Baeder 
633a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack.
634a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack.
635a07aba5dSTimm Baeder /// 3) Pushes 'LHS ^ RHS' on the stack
636a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
637a07aba5dSTimm Baeder bool BitXor(InterpState &S, CodePtr OpPC) {
638a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
639a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
640a07aba5dSTimm Baeder 
641a07aba5dSTimm Baeder   unsigned Bits = RHS.bitWidth();
642a07aba5dSTimm Baeder   T Result;
643a07aba5dSTimm Baeder   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
644a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
645a07aba5dSTimm Baeder     return true;
646a07aba5dSTimm Baeder   }
647a07aba5dSTimm Baeder   return false;
648a07aba5dSTimm Baeder }
649a07aba5dSTimm Baeder 
650a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack.
651a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack.
652a07aba5dSTimm Baeder /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
653a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
654a07aba5dSTimm Baeder bool Rem(InterpState &S, CodePtr OpPC) {
655a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
656a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
657a07aba5dSTimm Baeder 
658a07aba5dSTimm Baeder   if (!CheckDivRem(S, OpPC, LHS, RHS))
659a07aba5dSTimm Baeder     return false;
660a07aba5dSTimm Baeder 
661a07aba5dSTimm Baeder   const unsigned Bits = RHS.bitWidth() * 2;
662a07aba5dSTimm Baeder   T Result;
663a07aba5dSTimm Baeder   if (!T::rem(LHS, RHS, Bits, &Result)) {
664a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
665a07aba5dSTimm Baeder     return true;
666a07aba5dSTimm Baeder   }
667a07aba5dSTimm Baeder   return false;
668a07aba5dSTimm Baeder }
669a07aba5dSTimm Baeder 
670a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack.
671a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack.
672a07aba5dSTimm Baeder /// 3) Pushes 'LHS / RHS' on the stack
673a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
674a07aba5dSTimm Baeder bool Div(InterpState &S, CodePtr OpPC) {
675a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
676a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
677a07aba5dSTimm Baeder 
678a07aba5dSTimm Baeder   if (!CheckDivRem(S, OpPC, LHS, RHS))
679a07aba5dSTimm Baeder     return false;
680a07aba5dSTimm Baeder 
681a07aba5dSTimm Baeder   const unsigned Bits = RHS.bitWidth() * 2;
682a07aba5dSTimm Baeder   T Result;
683a07aba5dSTimm Baeder   if (!T::div(LHS, RHS, Bits, &Result)) {
684a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
685a07aba5dSTimm Baeder     return true;
686a07aba5dSTimm Baeder   }
6875c811cccSTimm Baeder 
6885c811cccSTimm Baeder   if constexpr (std::is_same_v<T, FixedPoint>) {
6895c811cccSTimm Baeder     if (handleFixedPointOverflow(S, OpPC, Result)) {
6905c811cccSTimm Baeder       S.Stk.push<T>(Result);
6915c811cccSTimm Baeder       return true;
6925c811cccSTimm Baeder     }
6935c811cccSTimm Baeder   }
694a07aba5dSTimm Baeder   return false;
695a07aba5dSTimm Baeder }
696a07aba5dSTimm Baeder 
6970f5f440fSTimm Baeder inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
698a07aba5dSTimm Baeder   const Floating &RHS = S.Stk.pop<Floating>();
699a07aba5dSTimm Baeder   const Floating &LHS = S.Stk.pop<Floating>();
700a07aba5dSTimm Baeder 
701a07aba5dSTimm Baeder   if (!CheckDivRem(S, OpPC, LHS, RHS))
702a07aba5dSTimm Baeder     return false;
703a07aba5dSTimm Baeder 
7040f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
705a07aba5dSTimm Baeder   Floating Result;
7060f5f440fSTimm Baeder   auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
707a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
7080f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
709a07aba5dSTimm Baeder }
710a07aba5dSTimm Baeder 
711a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
712a07aba5dSTimm Baeder // Inv
713a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
714a07aba5dSTimm Baeder 
715d082f1f3STimm Bäder inline bool Inv(InterpState &S, CodePtr OpPC) {
716d082f1f3STimm Bäder   const auto &Val = S.Stk.pop<Boolean>();
717d082f1f3STimm Bäder   S.Stk.push<Boolean>(!Val);
718a07aba5dSTimm Baeder   return true;
719a07aba5dSTimm Baeder }
720a07aba5dSTimm Baeder 
721a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
722a07aba5dSTimm Baeder // Neg
723a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
724a07aba5dSTimm Baeder 
725a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
726a07aba5dSTimm Baeder bool Neg(InterpState &S, CodePtr OpPC) {
727a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
728a07aba5dSTimm Baeder   T Result;
729a07aba5dSTimm Baeder 
730a07aba5dSTimm Baeder   if (!T::neg(Value, &Result)) {
731a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
732a07aba5dSTimm Baeder     return true;
733a07aba5dSTimm Baeder   }
734a07aba5dSTimm Baeder 
735a07aba5dSTimm Baeder   assert(isIntegralType(Name) &&
736a07aba5dSTimm Baeder          "don't expect other types to fail at constexpr negation");
737a07aba5dSTimm Baeder   S.Stk.push<T>(Result);
738a07aba5dSTimm Baeder 
739a07aba5dSTimm Baeder   APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
740a07aba5dSTimm Baeder   const Expr *E = S.Current->getExpr(OpPC);
741a07aba5dSTimm Baeder   QualType Type = E->getType();
742a07aba5dSTimm Baeder 
743a07aba5dSTimm Baeder   if (S.checkingForUndefinedBehavior()) {
744a07aba5dSTimm Baeder     SmallString<32> Trunc;
745a07aba5dSTimm Baeder     NegatedValue.trunc(Result.bitWidth())
746a07aba5dSTimm Baeder         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
747a07aba5dSTimm Baeder                   /*UpperCase=*/true, /*InsertSeparators=*/true);
748a07aba5dSTimm Baeder     auto Loc = E->getExprLoc();
749a07aba5dSTimm Baeder     S.report(Loc, diag::warn_integer_constant_overflow)
750a07aba5dSTimm Baeder         << Trunc << Type << E->getSourceRange();
751a07aba5dSTimm Baeder     return true;
752a07aba5dSTimm Baeder   }
753a07aba5dSTimm Baeder 
75495ce78b7STimm Baeder   return handleOverflow(S, OpPC, NegatedValue);
755a07aba5dSTimm Baeder }
756a07aba5dSTimm Baeder 
757a07aba5dSTimm Baeder enum class PushVal : bool {
758a07aba5dSTimm Baeder   No,
759a07aba5dSTimm Baeder   Yes,
760a07aba5dSTimm Baeder };
761a07aba5dSTimm Baeder enum class IncDecOp {
762a07aba5dSTimm Baeder   Inc,
763a07aba5dSTimm Baeder   Dec,
764a07aba5dSTimm Baeder };
765a07aba5dSTimm Baeder 
766a07aba5dSTimm Baeder template <typename T, IncDecOp Op, PushVal DoPush>
767a07aba5dSTimm Baeder bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
768a07aba5dSTimm Baeder   assert(!Ptr.isDummy());
769a07aba5dSTimm Baeder 
770a07aba5dSTimm Baeder   if constexpr (std::is_same_v<T, Boolean>) {
771a07aba5dSTimm Baeder     if (!S.getLangOpts().CPlusPlus14)
772a07aba5dSTimm Baeder       return Invalid(S, OpPC);
773a07aba5dSTimm Baeder   }
774a07aba5dSTimm Baeder 
775a07aba5dSTimm Baeder   const T &Value = Ptr.deref<T>();
776a07aba5dSTimm Baeder   T Result;
777a07aba5dSTimm Baeder 
778a07aba5dSTimm Baeder   if constexpr (DoPush == PushVal::Yes)
779a07aba5dSTimm Baeder     S.Stk.push<T>(Value);
780a07aba5dSTimm Baeder 
781a07aba5dSTimm Baeder   if constexpr (Op == IncDecOp::Inc) {
782a07aba5dSTimm Baeder     if (!T::increment(Value, &Result)) {
783a07aba5dSTimm Baeder       Ptr.deref<T>() = Result;
784a07aba5dSTimm Baeder       return true;
785a07aba5dSTimm Baeder     }
786a07aba5dSTimm Baeder   } else {
787a07aba5dSTimm Baeder     if (!T::decrement(Value, &Result)) {
788a07aba5dSTimm Baeder       Ptr.deref<T>() = Result;
789a07aba5dSTimm Baeder       return true;
790a07aba5dSTimm Baeder     }
791a07aba5dSTimm Baeder   }
792a07aba5dSTimm Baeder 
793a07aba5dSTimm Baeder   // Something went wrong with the previous operation. Compute the
794a07aba5dSTimm Baeder   // result with another bit of precision.
795a07aba5dSTimm Baeder   unsigned Bits = Value.bitWidth() + 1;
796a07aba5dSTimm Baeder   APSInt APResult;
797a07aba5dSTimm Baeder   if constexpr (Op == IncDecOp::Inc)
798a07aba5dSTimm Baeder     APResult = ++Value.toAPSInt(Bits);
799a07aba5dSTimm Baeder   else
800a07aba5dSTimm Baeder     APResult = --Value.toAPSInt(Bits);
801a07aba5dSTimm Baeder 
802a07aba5dSTimm Baeder   // Report undefined behaviour, stopping if required.
803a07aba5dSTimm Baeder   const Expr *E = S.Current->getExpr(OpPC);
804a07aba5dSTimm Baeder   QualType Type = E->getType();
805a07aba5dSTimm Baeder   if (S.checkingForUndefinedBehavior()) {
806a07aba5dSTimm Baeder     SmallString<32> Trunc;
807a07aba5dSTimm Baeder     APResult.trunc(Result.bitWidth())
808a07aba5dSTimm Baeder         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
809a07aba5dSTimm Baeder                   /*UpperCase=*/true, /*InsertSeparators=*/true);
810a07aba5dSTimm Baeder     auto Loc = E->getExprLoc();
811a07aba5dSTimm Baeder     S.report(Loc, diag::warn_integer_constant_overflow)
812a07aba5dSTimm Baeder         << Trunc << Type << E->getSourceRange();
813a07aba5dSTimm Baeder     return true;
814a07aba5dSTimm Baeder   }
815a07aba5dSTimm Baeder 
81695ce78b7STimm Baeder   return handleOverflow(S, OpPC, APResult);
817a07aba5dSTimm Baeder }
818a07aba5dSTimm Baeder 
819a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack
820a07aba5dSTimm Baeder /// 2) Load the value from the pointer
821a07aba5dSTimm Baeder /// 3) Writes the value increased by one back to the pointer
822a07aba5dSTimm Baeder /// 4) Pushes the original (pre-inc) value on the stack.
823a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
824a07aba5dSTimm Baeder bool Inc(InterpState &S, CodePtr OpPC) {
825a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
826a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
827a07aba5dSTimm Baeder     return false;
828a07aba5dSTimm Baeder 
829a07aba5dSTimm Baeder   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
830a07aba5dSTimm Baeder }
831a07aba5dSTimm Baeder 
832a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack
833a07aba5dSTimm Baeder /// 2) Load the value from the pointer
834a07aba5dSTimm Baeder /// 3) Writes the value increased by one back to the pointer
835a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
836a07aba5dSTimm Baeder bool IncPop(InterpState &S, CodePtr OpPC) {
837a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
838a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
839a07aba5dSTimm Baeder     return false;
840a07aba5dSTimm Baeder 
841a07aba5dSTimm Baeder   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
842a07aba5dSTimm Baeder }
843a07aba5dSTimm Baeder 
844a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack
845a07aba5dSTimm Baeder /// 2) Load the value from the pointer
846a07aba5dSTimm Baeder /// 3) Writes the value decreased by one back to the pointer
847a07aba5dSTimm Baeder /// 4) Pushes the original (pre-dec) value on the stack.
848a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
849a07aba5dSTimm Baeder bool Dec(InterpState &S, CodePtr OpPC) {
850a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
851a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
852a07aba5dSTimm Baeder     return false;
853a07aba5dSTimm Baeder 
854a07aba5dSTimm Baeder   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
855a07aba5dSTimm Baeder }
856a07aba5dSTimm Baeder 
857a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack
858a07aba5dSTimm Baeder /// 2) Load the value from the pointer
859a07aba5dSTimm Baeder /// 3) Writes the value decreased by one back to the pointer
860a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
861a07aba5dSTimm Baeder bool DecPop(InterpState &S, CodePtr OpPC) {
862a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
863a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
864a07aba5dSTimm Baeder     return false;
865a07aba5dSTimm Baeder 
866a07aba5dSTimm Baeder   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
867a07aba5dSTimm Baeder }
868a07aba5dSTimm Baeder 
869a07aba5dSTimm Baeder template <IncDecOp Op, PushVal DoPush>
870a07aba5dSTimm Baeder bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
8710f5f440fSTimm Baeder                        uint32_t FPOI) {
872a07aba5dSTimm Baeder   Floating Value = Ptr.deref<Floating>();
873a07aba5dSTimm Baeder   Floating Result;
874a07aba5dSTimm Baeder 
875a07aba5dSTimm Baeder   if constexpr (DoPush == PushVal::Yes)
876a07aba5dSTimm Baeder     S.Stk.push<Floating>(Value);
877a07aba5dSTimm Baeder 
8780f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
879a07aba5dSTimm Baeder   llvm::APFloat::opStatus Status;
880a07aba5dSTimm Baeder   if constexpr (Op == IncDecOp::Inc)
8810f5f440fSTimm Baeder     Status = Floating::increment(Value, getRoundingMode(FPO), &Result);
882a07aba5dSTimm Baeder   else
8830f5f440fSTimm Baeder     Status = Floating::decrement(Value, getRoundingMode(FPO), &Result);
884a07aba5dSTimm Baeder 
885a07aba5dSTimm Baeder   Ptr.deref<Floating>() = Result;
886a07aba5dSTimm Baeder 
8870f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
888a07aba5dSTimm Baeder }
889a07aba5dSTimm Baeder 
8900f5f440fSTimm Baeder inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
891a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
892a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
893a07aba5dSTimm Baeder     return false;
894a07aba5dSTimm Baeder 
8950f5f440fSTimm Baeder   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
896a07aba5dSTimm Baeder }
897a07aba5dSTimm Baeder 
8980f5f440fSTimm Baeder inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
899a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
900a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
901a07aba5dSTimm Baeder     return false;
902a07aba5dSTimm Baeder 
9030f5f440fSTimm Baeder   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
904a07aba5dSTimm Baeder }
905a07aba5dSTimm Baeder 
9060f5f440fSTimm Baeder inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
907a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
908a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
909a07aba5dSTimm Baeder     return false;
910a07aba5dSTimm Baeder 
9110f5f440fSTimm Baeder   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
912a07aba5dSTimm Baeder }
913a07aba5dSTimm Baeder 
9140f5f440fSTimm Baeder inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
915a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
916a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
917a07aba5dSTimm Baeder     return false;
918a07aba5dSTimm Baeder 
9190f5f440fSTimm Baeder   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
920a07aba5dSTimm Baeder }
921a07aba5dSTimm Baeder 
922a07aba5dSTimm Baeder /// 1) Pops the value from the stack.
923a07aba5dSTimm Baeder /// 2) Pushes the bitwise complemented value on the stack (~V).
924a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
925a07aba5dSTimm Baeder bool Comp(InterpState &S, CodePtr OpPC) {
926a07aba5dSTimm Baeder   const T &Val = S.Stk.pop<T>();
927a07aba5dSTimm Baeder   T Result;
928a07aba5dSTimm Baeder   if (!T::comp(Val, &Result)) {
929a07aba5dSTimm Baeder     S.Stk.push<T>(Result);
930a07aba5dSTimm Baeder     return true;
931a07aba5dSTimm Baeder   }
932a07aba5dSTimm Baeder 
933a07aba5dSTimm Baeder   return false;
934a07aba5dSTimm Baeder }
935a07aba5dSTimm Baeder 
936a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
937a07aba5dSTimm Baeder // EQ, NE, GT, GE, LT, LE
938a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
939a07aba5dSTimm Baeder 
940a07aba5dSTimm Baeder using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
941a07aba5dSTimm Baeder 
942a07aba5dSTimm Baeder template <typename T>
943a07aba5dSTimm Baeder bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
944a07aba5dSTimm Baeder   assert((!std::is_same_v<T, MemberPointer>) &&
945a07aba5dSTimm Baeder          "Non-equality comparisons on member pointer types should already be "
946a07aba5dSTimm Baeder          "rejected in Sema.");
947a07aba5dSTimm Baeder   using BoolT = PrimConv<PT_Bool>::T;
948a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
949a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
950a07aba5dSTimm Baeder   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
951a07aba5dSTimm Baeder   return true;
952a07aba5dSTimm Baeder }
953a07aba5dSTimm Baeder 
954a07aba5dSTimm Baeder template <typename T>
955a07aba5dSTimm Baeder bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
956a07aba5dSTimm Baeder   return CmpHelper<T>(S, OpPC, Fn);
957a07aba5dSTimm Baeder }
958a07aba5dSTimm Baeder 
959a07aba5dSTimm Baeder /// Function pointers cannot be compared in an ordered way.
960a07aba5dSTimm Baeder template <>
961a07aba5dSTimm Baeder inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
962a07aba5dSTimm Baeder                                        CompareFn Fn) {
963a07aba5dSTimm Baeder   const auto &RHS = S.Stk.pop<FunctionPointer>();
964a07aba5dSTimm Baeder   const auto &LHS = S.Stk.pop<FunctionPointer>();
965a07aba5dSTimm Baeder 
966a07aba5dSTimm Baeder   const SourceInfo &Loc = S.Current->getSource(OpPC);
967a07aba5dSTimm Baeder   S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
968d9e72860Syronglin       << LHS.toDiagnosticString(S.getASTContext())
969d9e72860Syronglin       << RHS.toDiagnosticString(S.getASTContext());
970a07aba5dSTimm Baeder   return false;
971a07aba5dSTimm Baeder }
972a07aba5dSTimm Baeder 
973a07aba5dSTimm Baeder template <>
974a07aba5dSTimm Baeder inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
975a07aba5dSTimm Baeder                                          CompareFn Fn) {
976a07aba5dSTimm Baeder   const auto &RHS = S.Stk.pop<FunctionPointer>();
977a07aba5dSTimm Baeder   const auto &LHS = S.Stk.pop<FunctionPointer>();
978a07aba5dSTimm Baeder 
979a07aba5dSTimm Baeder   // We cannot compare against weak declarations at compile time.
980a07aba5dSTimm Baeder   for (const auto &FP : {LHS, RHS}) {
981a07aba5dSTimm Baeder     if (FP.isWeak()) {
982a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
983a07aba5dSTimm Baeder       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
984d9e72860Syronglin           << FP.toDiagnosticString(S.getASTContext());
985a07aba5dSTimm Baeder       return false;
986a07aba5dSTimm Baeder     }
987a07aba5dSTimm Baeder   }
988a07aba5dSTimm Baeder 
989a07aba5dSTimm Baeder   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
990a07aba5dSTimm Baeder   return true;
991a07aba5dSTimm Baeder }
992a07aba5dSTimm Baeder 
993a07aba5dSTimm Baeder template <>
994a07aba5dSTimm Baeder inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
995a07aba5dSTimm Baeder   using BoolT = PrimConv<PT_Bool>::T;
996a07aba5dSTimm Baeder   const Pointer &RHS = S.Stk.pop<Pointer>();
997a07aba5dSTimm Baeder   const Pointer &LHS = S.Stk.pop<Pointer>();
998a07aba5dSTimm Baeder 
999a07aba5dSTimm Baeder   if (!Pointer::hasSameBase(LHS, RHS)) {
1000a07aba5dSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
1001a07aba5dSTimm Baeder     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1002d9e72860Syronglin         << LHS.toDiagnosticString(S.getASTContext())
1003d9e72860Syronglin         << RHS.toDiagnosticString(S.getASTContext());
1004a07aba5dSTimm Baeder     return false;
1005a07aba5dSTimm Baeder   } else {
1006a07aba5dSTimm Baeder     unsigned VL = LHS.getByteOffset();
1007a07aba5dSTimm Baeder     unsigned VR = RHS.getByteOffset();
1008a07aba5dSTimm Baeder     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1009a07aba5dSTimm Baeder     return true;
1010a07aba5dSTimm Baeder   }
1011a07aba5dSTimm Baeder }
1012a07aba5dSTimm Baeder 
1013a07aba5dSTimm Baeder template <>
1014a07aba5dSTimm Baeder inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1015a07aba5dSTimm Baeder   using BoolT = PrimConv<PT_Bool>::T;
1016a07aba5dSTimm Baeder   const Pointer &RHS = S.Stk.pop<Pointer>();
1017a07aba5dSTimm Baeder   const Pointer &LHS = S.Stk.pop<Pointer>();
1018a07aba5dSTimm Baeder 
1019a07aba5dSTimm Baeder   if (LHS.isZero() && RHS.isZero()) {
1020a07aba5dSTimm Baeder     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
1021a07aba5dSTimm Baeder     return true;
1022a07aba5dSTimm Baeder   }
1023a07aba5dSTimm Baeder 
1024a07aba5dSTimm Baeder   // Reject comparisons to weak pointers.
1025a07aba5dSTimm Baeder   for (const auto &P : {LHS, RHS}) {
1026a07aba5dSTimm Baeder     if (P.isZero())
1027a07aba5dSTimm Baeder       continue;
1028a07aba5dSTimm Baeder     if (P.isWeak()) {
1029a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
1030a07aba5dSTimm Baeder       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1031d9e72860Syronglin           << P.toDiagnosticString(S.getASTContext());
1032a07aba5dSTimm Baeder       return false;
1033a07aba5dSTimm Baeder     }
1034a07aba5dSTimm Baeder   }
1035a07aba5dSTimm Baeder 
1036360e4abfSTimm Baeder   if (Pointer::hasSameBase(LHS, RHS)) {
1037a07aba5dSTimm Baeder     unsigned VL = LHS.getByteOffset();
1038a07aba5dSTimm Baeder     unsigned VR = RHS.getByteOffset();
1039a07aba5dSTimm Baeder 
1040a07aba5dSTimm Baeder     // In our Pointer class, a pointer to an array and a pointer to the first
1041a07aba5dSTimm Baeder     // element in the same array are NOT equal. They have the same Base value,
1042a07aba5dSTimm Baeder     // but a different Offset. This is a pretty rare case, so we fix this here
1043a07aba5dSTimm Baeder     // by comparing pointers to the first elements.
1044a07aba5dSTimm Baeder     if (!LHS.isZero() && LHS.isArrayRoot())
1045a07aba5dSTimm Baeder       VL = LHS.atIndex(0).getByteOffset();
1046a07aba5dSTimm Baeder     if (!RHS.isZero() && RHS.isArrayRoot())
1047a07aba5dSTimm Baeder       VR = RHS.atIndex(0).getByteOffset();
1048a07aba5dSTimm Baeder 
1049a07aba5dSTimm Baeder     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1050a07aba5dSTimm Baeder     return true;
1051a07aba5dSTimm Baeder   }
1052360e4abfSTimm Baeder   // Otherwise we need to do a bunch of extra checks before returning Unordered.
1053360e4abfSTimm Baeder   if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
1054360e4abfSTimm Baeder       RHS.getOffset() == 0) {
1055360e4abfSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
1056360e4abfSTimm Baeder     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1057360e4abfSTimm Baeder         << LHS.toDiagnosticString(S.getASTContext());
1058360e4abfSTimm Baeder     return false;
1059360e4abfSTimm Baeder   } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1060360e4abfSTimm Baeder              LHS.getOffset() == 0) {
1061360e4abfSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
1062360e4abfSTimm Baeder     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1063360e4abfSTimm Baeder         << RHS.toDiagnosticString(S.getASTContext());
1064360e4abfSTimm Baeder     return false;
1065360e4abfSTimm Baeder   }
1066360e4abfSTimm Baeder 
1067360e4abfSTimm Baeder   bool BothNonNull = !LHS.isZero() && !RHS.isZero();
1068360e4abfSTimm Baeder   // Reject comparisons to literals.
1069360e4abfSTimm Baeder   for (const auto &P : {LHS, RHS}) {
1070360e4abfSTimm Baeder     if (P.isZero())
1071360e4abfSTimm Baeder       continue;
1072360e4abfSTimm Baeder     if (BothNonNull && P.pointsToLiteral()) {
1073360e4abfSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
1074360e4abfSTimm Baeder       S.FFDiag(Loc, diag::note_constexpr_literal_comparison);
1075360e4abfSTimm Baeder       return false;
1076360e4abfSTimm Baeder     }
1077360e4abfSTimm Baeder   }
1078360e4abfSTimm Baeder 
1079360e4abfSTimm Baeder   S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1080360e4abfSTimm Baeder   return true;
1081a07aba5dSTimm Baeder }
1082a07aba5dSTimm Baeder 
1083a07aba5dSTimm Baeder template <>
1084a07aba5dSTimm Baeder inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1085a07aba5dSTimm Baeder                                        CompareFn Fn) {
1086a07aba5dSTimm Baeder   const auto &RHS = S.Stk.pop<MemberPointer>();
1087a07aba5dSTimm Baeder   const auto &LHS = S.Stk.pop<MemberPointer>();
1088a07aba5dSTimm Baeder 
1089a07aba5dSTimm Baeder   // If either operand is a pointer to a weak function, the comparison is not
1090a07aba5dSTimm Baeder   // constant.
1091a07aba5dSTimm Baeder   for (const auto &MP : {LHS, RHS}) {
1092360e4abfSTimm Baeder     if (MP.isWeak()) {
1093a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
1094360e4abfSTimm Baeder       S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1095360e4abfSTimm Baeder           << MP.getMemberFunction();
1096a07aba5dSTimm Baeder       return false;
1097a07aba5dSTimm Baeder     }
1098a07aba5dSTimm Baeder   }
1099a07aba5dSTimm Baeder 
1100a07aba5dSTimm Baeder   // C++11 [expr.eq]p2:
1101a07aba5dSTimm Baeder   //   If both operands are null, they compare equal. Otherwise if only one is
1102a07aba5dSTimm Baeder   //   null, they compare unequal.
1103a07aba5dSTimm Baeder   if (LHS.isZero() && RHS.isZero()) {
1104a07aba5dSTimm Baeder     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
1105a07aba5dSTimm Baeder     return true;
1106a07aba5dSTimm Baeder   }
1107a07aba5dSTimm Baeder   if (LHS.isZero() || RHS.isZero()) {
1108a07aba5dSTimm Baeder     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
1109a07aba5dSTimm Baeder     return true;
1110a07aba5dSTimm Baeder   }
1111a07aba5dSTimm Baeder 
1112a07aba5dSTimm Baeder   // We cannot compare against virtual declarations at compile time.
1113a07aba5dSTimm Baeder   for (const auto &MP : {LHS, RHS}) {
1114a07aba5dSTimm Baeder     if (const CXXMethodDecl *MD = MP.getMemberFunction();
1115a07aba5dSTimm Baeder         MD && MD->isVirtual()) {
1116a07aba5dSTimm Baeder       const SourceInfo &Loc = S.Current->getSource(OpPC);
1117a07aba5dSTimm Baeder       S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1118a07aba5dSTimm Baeder     }
1119a07aba5dSTimm Baeder   }
1120a07aba5dSTimm Baeder 
1121a07aba5dSTimm Baeder   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1122a07aba5dSTimm Baeder   return true;
1123a07aba5dSTimm Baeder }
1124a07aba5dSTimm Baeder 
1125a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1126a07aba5dSTimm Baeder bool EQ(InterpState &S, CodePtr OpPC) {
1127a07aba5dSTimm Baeder   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1128a07aba5dSTimm Baeder     return R == ComparisonCategoryResult::Equal;
1129a07aba5dSTimm Baeder   });
1130a07aba5dSTimm Baeder }
1131a07aba5dSTimm Baeder 
1132a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1133a07aba5dSTimm Baeder bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1134a07aba5dSTimm Baeder   const T &RHS = S.Stk.pop<T>();
1135a07aba5dSTimm Baeder   const T &LHS = S.Stk.pop<T>();
1136a07aba5dSTimm Baeder   const Pointer &P = S.Stk.peek<Pointer>();
1137a07aba5dSTimm Baeder 
1138a07aba5dSTimm Baeder   ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1139a07aba5dSTimm Baeder   if (CmpResult == ComparisonCategoryResult::Unordered) {
1140a07aba5dSTimm Baeder     // This should only happen with pointers.
1141a07aba5dSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
1142a07aba5dSTimm Baeder     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1143d9e72860Syronglin         << LHS.toDiagnosticString(S.getASTContext())
1144d9e72860Syronglin         << RHS.toDiagnosticString(S.getASTContext());
1145a07aba5dSTimm Baeder     return false;
1146a07aba5dSTimm Baeder   }
1147a07aba5dSTimm Baeder 
1148a07aba5dSTimm Baeder   assert(CmpInfo);
1149a07aba5dSTimm Baeder   const auto *CmpValueInfo =
1150a07aba5dSTimm Baeder       CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1151a07aba5dSTimm Baeder   assert(CmpValueInfo);
1152a07aba5dSTimm Baeder   assert(CmpValueInfo->hasValidIntValue());
1153a07aba5dSTimm Baeder   return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1154a07aba5dSTimm Baeder }
1155a07aba5dSTimm Baeder 
1156a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1157a07aba5dSTimm Baeder bool NE(InterpState &S, CodePtr OpPC) {
1158a07aba5dSTimm Baeder   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1159a07aba5dSTimm Baeder     return R != ComparisonCategoryResult::Equal;
1160a07aba5dSTimm Baeder   });
1161a07aba5dSTimm Baeder }
1162a07aba5dSTimm Baeder 
1163a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1164a07aba5dSTimm Baeder bool LT(InterpState &S, CodePtr OpPC) {
1165a07aba5dSTimm Baeder   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1166a07aba5dSTimm Baeder     return R == ComparisonCategoryResult::Less;
1167a07aba5dSTimm Baeder   });
1168a07aba5dSTimm Baeder }
1169a07aba5dSTimm Baeder 
1170a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1171a07aba5dSTimm Baeder bool LE(InterpState &S, CodePtr OpPC) {
1172a07aba5dSTimm Baeder   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1173a07aba5dSTimm Baeder     return R == ComparisonCategoryResult::Less ||
1174a07aba5dSTimm Baeder            R == ComparisonCategoryResult::Equal;
1175a07aba5dSTimm Baeder   });
1176a07aba5dSTimm Baeder }
1177a07aba5dSTimm Baeder 
1178a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1179a07aba5dSTimm Baeder bool GT(InterpState &S, CodePtr OpPC) {
1180a07aba5dSTimm Baeder   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1181a07aba5dSTimm Baeder     return R == ComparisonCategoryResult::Greater;
1182a07aba5dSTimm Baeder   });
1183a07aba5dSTimm Baeder }
1184a07aba5dSTimm Baeder 
1185a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1186a07aba5dSTimm Baeder bool GE(InterpState &S, CodePtr OpPC) {
1187a07aba5dSTimm Baeder   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1188a07aba5dSTimm Baeder     return R == ComparisonCategoryResult::Greater ||
1189a07aba5dSTimm Baeder            R == ComparisonCategoryResult::Equal;
1190a07aba5dSTimm Baeder   });
1191a07aba5dSTimm Baeder }
1192a07aba5dSTimm Baeder 
1193a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1194a07aba5dSTimm Baeder // InRange
1195a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1196a07aba5dSTimm Baeder 
1197a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1198a07aba5dSTimm Baeder bool InRange(InterpState &S, CodePtr OpPC) {
1199a07aba5dSTimm Baeder   const T RHS = S.Stk.pop<T>();
1200a07aba5dSTimm Baeder   const T LHS = S.Stk.pop<T>();
1201a07aba5dSTimm Baeder   const T Value = S.Stk.pop<T>();
1202a07aba5dSTimm Baeder 
1203a07aba5dSTimm Baeder   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1204a07aba5dSTimm Baeder   return true;
1205a07aba5dSTimm Baeder }
1206a07aba5dSTimm Baeder 
1207a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1208a07aba5dSTimm Baeder // Dup, Pop, Test
1209a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1210a07aba5dSTimm Baeder 
1211a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1212a07aba5dSTimm Baeder bool Dup(InterpState &S, CodePtr OpPC) {
1213a07aba5dSTimm Baeder   S.Stk.push<T>(S.Stk.peek<T>());
1214a07aba5dSTimm Baeder   return true;
1215a07aba5dSTimm Baeder }
1216a07aba5dSTimm Baeder 
1217a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1218a07aba5dSTimm Baeder bool Pop(InterpState &S, CodePtr OpPC) {
1219a07aba5dSTimm Baeder   S.Stk.pop<T>();
1220a07aba5dSTimm Baeder   return true;
1221a07aba5dSTimm Baeder }
1222a07aba5dSTimm Baeder 
1223a07aba5dSTimm Baeder /// [Value1, Value2] -> [Value2, Value1]
1224a07aba5dSTimm Baeder template <PrimType TopName, PrimType BottomName>
1225a07aba5dSTimm Baeder bool Flip(InterpState &S, CodePtr OpPC) {
1226a07aba5dSTimm Baeder   using TopT = typename PrimConv<TopName>::T;
1227a07aba5dSTimm Baeder   using BottomT = typename PrimConv<BottomName>::T;
1228a07aba5dSTimm Baeder 
1229a07aba5dSTimm Baeder   const auto &Top = S.Stk.pop<TopT>();
1230a07aba5dSTimm Baeder   const auto &Bottom = S.Stk.pop<BottomT>();
1231a07aba5dSTimm Baeder 
1232a07aba5dSTimm Baeder   S.Stk.push<TopT>(Top);
1233a07aba5dSTimm Baeder   S.Stk.push<BottomT>(Bottom);
1234a07aba5dSTimm Baeder 
1235a07aba5dSTimm Baeder   return true;
1236a07aba5dSTimm Baeder }
1237a07aba5dSTimm Baeder 
1238a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1239a07aba5dSTimm Baeder // Const
1240a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1241a07aba5dSTimm Baeder 
1242a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1243a07aba5dSTimm Baeder bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1244a07aba5dSTimm Baeder   S.Stk.push<T>(Arg);
1245a07aba5dSTimm Baeder   return true;
1246a07aba5dSTimm Baeder }
1247a07aba5dSTimm Baeder 
1248a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1249a07aba5dSTimm Baeder // Get/Set Local/Param/Global/This
1250a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1251a07aba5dSTimm Baeder 
1252a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1253a07aba5dSTimm Baeder bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1254a07aba5dSTimm Baeder   const Pointer &Ptr = S.Current->getLocalPointer(I);
1255a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr))
1256a07aba5dSTimm Baeder     return false;
1257a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.deref<T>());
1258a07aba5dSTimm Baeder   return true;
1259a07aba5dSTimm Baeder }
1260a07aba5dSTimm Baeder 
1261a07aba5dSTimm Baeder /// 1) Pops the value from the stack.
1262a07aba5dSTimm Baeder /// 2) Writes the value to the local variable with the
1263a07aba5dSTimm Baeder ///    given offset.
1264a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1265a07aba5dSTimm Baeder bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1266a07aba5dSTimm Baeder   S.Current->setLocal<T>(I, S.Stk.pop<T>());
1267a07aba5dSTimm Baeder   return true;
1268a07aba5dSTimm Baeder }
1269a07aba5dSTimm Baeder 
1270a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1271a07aba5dSTimm Baeder bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1272a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression()) {
1273a07aba5dSTimm Baeder     return false;
1274a07aba5dSTimm Baeder   }
1275a07aba5dSTimm Baeder   S.Stk.push<T>(S.Current->getParam<T>(I));
1276a07aba5dSTimm Baeder   return true;
1277a07aba5dSTimm Baeder }
1278a07aba5dSTimm Baeder 
1279a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1280a07aba5dSTimm Baeder bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1281a07aba5dSTimm Baeder   S.Current->setParam<T>(I, S.Stk.pop<T>());
1282a07aba5dSTimm Baeder   return true;
1283a07aba5dSTimm Baeder }
1284a07aba5dSTimm Baeder 
1285a07aba5dSTimm Baeder /// 1) Peeks a pointer on the stack
1286a07aba5dSTimm Baeder /// 2) Pushes the value of the pointer's field on the stack
1287a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1288a07aba5dSTimm Baeder bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1289a07aba5dSTimm Baeder   const Pointer &Obj = S.Stk.peek<Pointer>();
1290a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1291a07aba5dSTimm Baeder     return false;
1292a07aba5dSTimm Baeder   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1293a07aba5dSTimm Baeder     return false;
1294a07aba5dSTimm Baeder   const Pointer &Field = Obj.atField(I);
1295a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Field))
1296a07aba5dSTimm Baeder     return false;
1297a07aba5dSTimm Baeder   S.Stk.push<T>(Field.deref<T>());
1298a07aba5dSTimm Baeder   return true;
1299a07aba5dSTimm Baeder }
1300a07aba5dSTimm Baeder 
1301a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1302a07aba5dSTimm Baeder bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1303a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1304a07aba5dSTimm Baeder   const Pointer &Obj = S.Stk.peek<Pointer>();
1305a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1306a07aba5dSTimm Baeder     return false;
1307a07aba5dSTimm Baeder   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1308a07aba5dSTimm Baeder     return false;
1309a07aba5dSTimm Baeder   const Pointer &Field = Obj.atField(I);
1310a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Field))
1311a07aba5dSTimm Baeder     return false;
1312a07aba5dSTimm Baeder   Field.initialize();
1313a07aba5dSTimm Baeder   Field.deref<T>() = Value;
1314a07aba5dSTimm Baeder   return true;
1315a07aba5dSTimm Baeder }
1316a07aba5dSTimm Baeder 
1317a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack
1318a07aba5dSTimm Baeder /// 2) Pushes the value of the pointer's field on the stack
1319a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1320a07aba5dSTimm Baeder bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1321a07aba5dSTimm Baeder   const Pointer &Obj = S.Stk.pop<Pointer>();
1322a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1323a07aba5dSTimm Baeder     return false;
1324a07aba5dSTimm Baeder   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1325a07aba5dSTimm Baeder     return false;
1326a07aba5dSTimm Baeder   const Pointer &Field = Obj.atField(I);
1327a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Field))
1328a07aba5dSTimm Baeder     return false;
1329a07aba5dSTimm Baeder   S.Stk.push<T>(Field.deref<T>());
1330a07aba5dSTimm Baeder   return true;
1331a07aba5dSTimm Baeder }
1332a07aba5dSTimm Baeder 
1333a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1334a07aba5dSTimm Baeder bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1335a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1336a07aba5dSTimm Baeder     return false;
1337a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1338a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1339a07aba5dSTimm Baeder     return false;
1340a07aba5dSTimm Baeder   const Pointer &Field = This.atField(I);
1341a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Field))
1342a07aba5dSTimm Baeder     return false;
1343a07aba5dSTimm Baeder   S.Stk.push<T>(Field.deref<T>());
1344a07aba5dSTimm Baeder   return true;
1345a07aba5dSTimm Baeder }
1346a07aba5dSTimm Baeder 
1347a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1348a07aba5dSTimm Baeder bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1349a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1350a07aba5dSTimm Baeder     return false;
1351a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1352a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1353a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1354a07aba5dSTimm Baeder     return false;
1355a07aba5dSTimm Baeder   const Pointer &Field = This.atField(I);
1356a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Field))
1357a07aba5dSTimm Baeder     return false;
1358a07aba5dSTimm Baeder   Field.deref<T>() = Value;
1359a07aba5dSTimm Baeder   return true;
1360a07aba5dSTimm Baeder }
1361a07aba5dSTimm Baeder 
1362a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1363a07aba5dSTimm Baeder bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1364a07aba5dSTimm Baeder   const Pointer &Ptr = S.P.getPtrGlobal(I);
1365a07aba5dSTimm Baeder   if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1366a07aba5dSTimm Baeder     return false;
1367a07aba5dSTimm Baeder   if (Ptr.isExtern())
1368a07aba5dSTimm Baeder     return false;
1369a07aba5dSTimm Baeder 
1370a07aba5dSTimm Baeder   // If a global variable is uninitialized, that means the initializer we've
1371a07aba5dSTimm Baeder   // compiled for it wasn't a constant expression. Diagnose that.
1372a07aba5dSTimm Baeder   if (!CheckGlobalInitialized(S, OpPC, Ptr))
1373a07aba5dSTimm Baeder     return false;
1374a07aba5dSTimm Baeder 
1375a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.deref<T>());
1376a07aba5dSTimm Baeder   return true;
1377a07aba5dSTimm Baeder }
1378a07aba5dSTimm Baeder 
1379a07aba5dSTimm Baeder /// Same as GetGlobal, but without the checks.
1380a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1381a07aba5dSTimm Baeder bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1382a07aba5dSTimm Baeder   const Pointer &Ptr = S.P.getPtrGlobal(I);
1383a07aba5dSTimm Baeder   if (!Ptr.isInitialized())
1384a07aba5dSTimm Baeder     return false;
1385a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.deref<T>());
1386a07aba5dSTimm Baeder   return true;
1387a07aba5dSTimm Baeder }
1388a07aba5dSTimm Baeder 
1389a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1390a07aba5dSTimm Baeder bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1391a07aba5dSTimm Baeder   // TODO: emit warning.
1392a07aba5dSTimm Baeder   return false;
1393a07aba5dSTimm Baeder }
1394a07aba5dSTimm Baeder 
1395a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1396a07aba5dSTimm Baeder bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1397a07aba5dSTimm Baeder   const Pointer &P = S.P.getGlobal(I);
1398a07aba5dSTimm Baeder   P.deref<T>() = S.Stk.pop<T>();
1399a07aba5dSTimm Baeder   P.initialize();
1400a07aba5dSTimm Baeder   return true;
1401a07aba5dSTimm Baeder }
1402a07aba5dSTimm Baeder 
1403a07aba5dSTimm Baeder /// 1) Converts the value on top of the stack to an APValue
1404a07aba5dSTimm Baeder /// 2) Sets that APValue on \Temp
1405a07aba5dSTimm Baeder /// 3) Initializes global with index \I with that
1406a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1407a07aba5dSTimm Baeder bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1408a07aba5dSTimm Baeder                     const LifetimeExtendedTemporaryDecl *Temp) {
1409a07aba5dSTimm Baeder   const Pointer &Ptr = S.P.getGlobal(I);
1410a07aba5dSTimm Baeder 
1411a07aba5dSTimm Baeder   const T Value = S.Stk.peek<T>();
1412d9e72860Syronglin   APValue APV = Value.toAPValue(S.getASTContext());
1413a07aba5dSTimm Baeder   APValue *Cached = Temp->getOrCreateValue(true);
1414a07aba5dSTimm Baeder   *Cached = APV;
1415a07aba5dSTimm Baeder 
1416a07aba5dSTimm Baeder   assert(Ptr.getDeclDesc()->asExpr());
1417a07aba5dSTimm Baeder 
1418a07aba5dSTimm Baeder   S.SeenGlobalTemporaries.push_back(
1419a07aba5dSTimm Baeder       std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1420a07aba5dSTimm Baeder 
1421a07aba5dSTimm Baeder   Ptr.deref<T>() = S.Stk.pop<T>();
1422a07aba5dSTimm Baeder   Ptr.initialize();
1423a07aba5dSTimm Baeder   return true;
1424a07aba5dSTimm Baeder }
1425a07aba5dSTimm Baeder 
1426a07aba5dSTimm Baeder /// 1) Converts the value on top of the stack to an APValue
1427a07aba5dSTimm Baeder /// 2) Sets that APValue on \Temp
1428a07aba5dSTimm Baeder /// 3) Initialized global with index \I with that
1429a07aba5dSTimm Baeder inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1430a07aba5dSTimm Baeder                                const LifetimeExtendedTemporaryDecl *Temp) {
1431a07aba5dSTimm Baeder   assert(Temp);
1432a07aba5dSTimm Baeder   const Pointer &P = S.Stk.peek<Pointer>();
1433a07aba5dSTimm Baeder   APValue *Cached = Temp->getOrCreateValue(true);
1434a07aba5dSTimm Baeder 
1435a07aba5dSTimm Baeder   S.SeenGlobalTemporaries.push_back(
1436a07aba5dSTimm Baeder       std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1437a07aba5dSTimm Baeder 
1438a07aba5dSTimm Baeder   if (std::optional<APValue> APV =
1439d9e72860Syronglin           P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) {
1440a07aba5dSTimm Baeder     *Cached = *APV;
1441a07aba5dSTimm Baeder     return true;
1442a07aba5dSTimm Baeder   }
1443a07aba5dSTimm Baeder 
1444a07aba5dSTimm Baeder   return false;
1445a07aba5dSTimm Baeder }
1446a07aba5dSTimm Baeder 
1447a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1448a07aba5dSTimm Baeder bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1449a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1450a07aba5dSTimm Baeder     return false;
1451a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1452a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1453a07aba5dSTimm Baeder     return false;
1454a07aba5dSTimm Baeder   const Pointer &Field = This.atField(I);
1455a07aba5dSTimm Baeder   Field.deref<T>() = S.Stk.pop<T>();
1456a07aba5dSTimm Baeder   Field.activate();
1457a07aba5dSTimm Baeder   Field.initialize();
1458a07aba5dSTimm Baeder   return true;
1459a07aba5dSTimm Baeder }
1460a07aba5dSTimm Baeder 
1461a07aba5dSTimm Baeder // FIXME: The Field pointer here is too much IMO and we could instead just
1462a07aba5dSTimm Baeder // pass an Offset + BitWidth pair.
1463a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1464a07aba5dSTimm Baeder bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1465a07aba5dSTimm Baeder                       uint32_t FieldOffset) {
1466a07aba5dSTimm Baeder   assert(F->isBitField());
1467a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1468a07aba5dSTimm Baeder     return false;
1469a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1470a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1471a07aba5dSTimm Baeder     return false;
1472a07aba5dSTimm Baeder   const Pointer &Field = This.atField(FieldOffset);
1473a07aba5dSTimm Baeder   const auto &Value = S.Stk.pop<T>();
1474cfe26358STimm Baeder   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1475a07aba5dSTimm Baeder   Field.initialize();
1476a07aba5dSTimm Baeder   return true;
1477a07aba5dSTimm Baeder }
1478a07aba5dSTimm Baeder 
1479a07aba5dSTimm Baeder /// 1) Pops the value from the stack
1480a07aba5dSTimm Baeder /// 2) Peeks a pointer from the stack
1481a07aba5dSTimm Baeder /// 3) Pushes the value to field I of the pointer on the stack
1482a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1483a07aba5dSTimm Baeder bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1484a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1485a07aba5dSTimm Baeder   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1486a07aba5dSTimm Baeder   Field.deref<T>() = Value;
1487a07aba5dSTimm Baeder   Field.activate();
1488a07aba5dSTimm Baeder   Field.initialize();
1489a07aba5dSTimm Baeder   return true;
1490a07aba5dSTimm Baeder }
1491a07aba5dSTimm Baeder 
1492a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1493a07aba5dSTimm Baeder bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1494a07aba5dSTimm Baeder   assert(F->isBitField());
1495a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1496a07aba5dSTimm Baeder   const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1497cfe26358STimm Baeder   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1498a07aba5dSTimm Baeder   Field.activate();
1499a07aba5dSTimm Baeder   Field.initialize();
1500a07aba5dSTimm Baeder   return true;
1501a07aba5dSTimm Baeder }
1502a07aba5dSTimm Baeder 
1503a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1504a07aba5dSTimm Baeder // GetPtr Local/Param/Global/Field/This
1505a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1506a07aba5dSTimm Baeder 
1507a07aba5dSTimm Baeder inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1508a07aba5dSTimm Baeder   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1509a07aba5dSTimm Baeder   return true;
1510a07aba5dSTimm Baeder }
1511a07aba5dSTimm Baeder 
1512a07aba5dSTimm Baeder inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1513a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression()) {
1514a07aba5dSTimm Baeder     return false;
1515a07aba5dSTimm Baeder   }
1516a07aba5dSTimm Baeder   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1517a07aba5dSTimm Baeder   return true;
1518a07aba5dSTimm Baeder }
1519a07aba5dSTimm Baeder 
1520a07aba5dSTimm Baeder inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1521a07aba5dSTimm Baeder   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1522a07aba5dSTimm Baeder   return true;
1523a07aba5dSTimm Baeder }
1524a07aba5dSTimm Baeder 
1525a07aba5dSTimm Baeder /// 1) Peeks a Pointer
1526a07aba5dSTimm Baeder /// 2) Pushes Pointer.atField(Off) on the stack
1527e86b68ffSTimm Baeder bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1528e86b68ffSTimm Baeder bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
1529a07aba5dSTimm Baeder 
1530a07aba5dSTimm Baeder inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1531a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1532a07aba5dSTimm Baeder     return false;
1533a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1534a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1535a07aba5dSTimm Baeder     return false;
1536a07aba5dSTimm Baeder   S.Stk.push<Pointer>(This.atField(Off));
1537a07aba5dSTimm Baeder   return true;
1538a07aba5dSTimm Baeder }
1539a07aba5dSTimm Baeder 
1540a07aba5dSTimm Baeder inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1541a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1542a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1543a07aba5dSTimm Baeder     return false;
1544a07aba5dSTimm Baeder   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1545a07aba5dSTimm Baeder     return false;
1546a07aba5dSTimm Baeder   Pointer Field = Ptr.atField(Off);
1547a07aba5dSTimm Baeder   Ptr.deactivate();
1548a07aba5dSTimm Baeder   Field.activate();
1549a07aba5dSTimm Baeder   S.Stk.push<Pointer>(std::move(Field));
1550a07aba5dSTimm Baeder   return true;
1551a07aba5dSTimm Baeder }
1552a07aba5dSTimm Baeder 
1553a07aba5dSTimm Baeder inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1554a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1555a07aba5dSTimm Baeder     return false;
1556a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1557a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1558a07aba5dSTimm Baeder     return false;
1559a07aba5dSTimm Baeder   Pointer Field = This.atField(Off);
1560a07aba5dSTimm Baeder   This.deactivate();
1561a07aba5dSTimm Baeder   Field.activate();
1562a07aba5dSTimm Baeder   S.Stk.push<Pointer>(std::move(Field));
1563a07aba5dSTimm Baeder   return true;
1564a07aba5dSTimm Baeder }
1565a07aba5dSTimm Baeder 
1566a07aba5dSTimm Baeder inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1567a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1568a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1569a07aba5dSTimm Baeder     return false;
1570a07aba5dSTimm Baeder   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1571a07aba5dSTimm Baeder     return false;
1572a07aba5dSTimm Baeder   if (!CheckDowncast(S, OpPC, Ptr, Off))
1573a07aba5dSTimm Baeder     return false;
1574a07aba5dSTimm Baeder 
1575a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1576a07aba5dSTimm Baeder   return true;
1577a07aba5dSTimm Baeder }
1578a07aba5dSTimm Baeder 
1579a07aba5dSTimm Baeder inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1580a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
158155c70f6dSTimm Baeder   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
158255c70f6dSTimm Baeder     return false;
158343fd2c40STimm Baeder 
158443fd2c40STimm Baeder   if (!Ptr.isBlockPointer()) {
158543fd2c40STimm Baeder     S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
158643fd2c40STimm Baeder     return true;
158743fd2c40STimm Baeder   }
158843fd2c40STimm Baeder 
1589a07aba5dSTimm Baeder   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1590a07aba5dSTimm Baeder     return false;
1591a07aba5dSTimm Baeder   const Pointer &Result = Ptr.atField(Off);
1592ba7dadf0STimm Baeder   if (Result.isPastEnd() || !Result.isBaseClass())
1593a07aba5dSTimm Baeder     return false;
1594a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Result);
1595a07aba5dSTimm Baeder   return true;
1596a07aba5dSTimm Baeder }
1597a07aba5dSTimm Baeder 
1598a07aba5dSTimm Baeder inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1599a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
160043fd2c40STimm Baeder 
160155c70f6dSTimm Baeder   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
160255c70f6dSTimm Baeder     return false;
160355c70f6dSTimm Baeder 
160443fd2c40STimm Baeder   if (!Ptr.isBlockPointer()) {
160543fd2c40STimm Baeder     S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
160643fd2c40STimm Baeder     return true;
160743fd2c40STimm Baeder   }
160843fd2c40STimm Baeder 
1609a07aba5dSTimm Baeder   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1610a07aba5dSTimm Baeder     return false;
1611a07aba5dSTimm Baeder   const Pointer &Result = Ptr.atField(Off);
1612ba7dadf0STimm Baeder   if (Result.isPastEnd() || !Result.isBaseClass())
1613a07aba5dSTimm Baeder     return false;
1614a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Result);
1615a07aba5dSTimm Baeder   return true;
1616a07aba5dSTimm Baeder }
1617a07aba5dSTimm Baeder 
1618a07aba5dSTimm Baeder inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1619a07aba5dSTimm Baeder   const auto &Ptr = S.Stk.pop<MemberPointer>();
1620a07aba5dSTimm Baeder   S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1621a07aba5dSTimm Baeder   return true;
1622a07aba5dSTimm Baeder }
1623a07aba5dSTimm Baeder 
1624a07aba5dSTimm Baeder inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1625a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1626a07aba5dSTimm Baeder     return false;
1627a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1628a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1629a07aba5dSTimm Baeder     return false;
1630a07aba5dSTimm Baeder   S.Stk.push<Pointer>(This.atField(Off));
1631a07aba5dSTimm Baeder   return true;
1632a07aba5dSTimm Baeder }
1633a07aba5dSTimm Baeder 
1634a07aba5dSTimm Baeder inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1635a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1636a07aba5dSTimm Baeder   if (Ptr.canBeInitialized()) {
1637a07aba5dSTimm Baeder     Ptr.initialize();
1638a07aba5dSTimm Baeder     Ptr.activate();
1639a07aba5dSTimm Baeder   }
1640a07aba5dSTimm Baeder   return true;
1641a07aba5dSTimm Baeder }
1642a07aba5dSTimm Baeder 
1643a07aba5dSTimm Baeder inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1644a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
1645a07aba5dSTimm Baeder   if (Ptr.canBeInitialized()) {
1646a07aba5dSTimm Baeder     Ptr.initialize();
1647a07aba5dSTimm Baeder     Ptr.activate();
1648a07aba5dSTimm Baeder   }
1649a07aba5dSTimm Baeder   return true;
1650a07aba5dSTimm Baeder }
1651a07aba5dSTimm Baeder 
1652a07aba5dSTimm Baeder inline bool Dump(InterpState &S, CodePtr OpPC) {
1653a07aba5dSTimm Baeder   S.Stk.dump();
1654a07aba5dSTimm Baeder   return true;
1655a07aba5dSTimm Baeder }
1656a07aba5dSTimm Baeder 
1657a07aba5dSTimm Baeder inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1658a07aba5dSTimm Baeder                            const Pointer &Ptr) {
1659a07aba5dSTimm Baeder   Pointer Base = Ptr;
1660a07aba5dSTimm Baeder   while (Base.isBaseClass())
1661a07aba5dSTimm Baeder     Base = Base.getBase();
1662a07aba5dSTimm Baeder 
1663a07aba5dSTimm Baeder   const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1664a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1665a07aba5dSTimm Baeder   return true;
1666a07aba5dSTimm Baeder }
1667a07aba5dSTimm Baeder 
1668a07aba5dSTimm Baeder inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
1669a07aba5dSTimm Baeder                               const RecordDecl *D) {
1670a07aba5dSTimm Baeder   assert(D);
1671a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1672a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1673a07aba5dSTimm Baeder     return false;
1674a07aba5dSTimm Baeder   return VirtBaseHelper(S, OpPC, D, Ptr);
1675a07aba5dSTimm Baeder }
1676a07aba5dSTimm Baeder 
1677a07aba5dSTimm Baeder inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1678a07aba5dSTimm Baeder                                const RecordDecl *D) {
1679a07aba5dSTimm Baeder   assert(D);
1680a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
1681a07aba5dSTimm Baeder     return false;
1682a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
1683a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
1684a07aba5dSTimm Baeder     return false;
1685a07aba5dSTimm Baeder   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1686a07aba5dSTimm Baeder }
1687a07aba5dSTimm Baeder 
1688a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1689a07aba5dSTimm Baeder // Load, Store, Init
1690a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1691a07aba5dSTimm Baeder 
1692a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1693a07aba5dSTimm Baeder bool Load(InterpState &S, CodePtr OpPC) {
1694a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
1695a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr))
1696a07aba5dSTimm Baeder     return false;
1697a07aba5dSTimm Baeder   if (!Ptr.isBlockPointer())
1698a07aba5dSTimm Baeder     return false;
1699a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.deref<T>());
1700a07aba5dSTimm Baeder   return true;
1701a07aba5dSTimm Baeder }
1702a07aba5dSTimm Baeder 
1703a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1704a07aba5dSTimm Baeder bool LoadPop(InterpState &S, CodePtr OpPC) {
1705a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1706a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr))
1707a07aba5dSTimm Baeder     return false;
1708a07aba5dSTimm Baeder   if (!Ptr.isBlockPointer())
1709a07aba5dSTimm Baeder     return false;
1710a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.deref<T>());
1711a07aba5dSTimm Baeder   return true;
1712a07aba5dSTimm Baeder }
1713a07aba5dSTimm Baeder 
1714a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1715a07aba5dSTimm Baeder bool Store(InterpState &S, CodePtr OpPC) {
1716a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1717a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
1718a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Ptr))
1719a07aba5dSTimm Baeder     return false;
1720a07aba5dSTimm Baeder   if (Ptr.canBeInitialized()) {
1721a07aba5dSTimm Baeder     Ptr.initialize();
1722a07aba5dSTimm Baeder     Ptr.activate();
1723a07aba5dSTimm Baeder   }
1724a07aba5dSTimm Baeder   Ptr.deref<T>() = Value;
1725a07aba5dSTimm Baeder   return true;
1726a07aba5dSTimm Baeder }
1727a07aba5dSTimm Baeder 
1728a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1729a07aba5dSTimm Baeder bool StorePop(InterpState &S, CodePtr OpPC) {
1730a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1731a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1732a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Ptr))
1733a07aba5dSTimm Baeder     return false;
1734a07aba5dSTimm Baeder   if (Ptr.canBeInitialized()) {
1735a07aba5dSTimm Baeder     Ptr.initialize();
1736a07aba5dSTimm Baeder     Ptr.activate();
1737a07aba5dSTimm Baeder   }
1738a07aba5dSTimm Baeder   Ptr.deref<T>() = Value;
1739a07aba5dSTimm Baeder   return true;
1740a07aba5dSTimm Baeder }
1741a07aba5dSTimm Baeder 
1742a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1743a07aba5dSTimm Baeder bool StoreBitField(InterpState &S, CodePtr OpPC) {
1744a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1745a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
1746a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Ptr))
1747a07aba5dSTimm Baeder     return false;
1748a07aba5dSTimm Baeder   if (Ptr.canBeInitialized())
1749a07aba5dSTimm Baeder     Ptr.initialize();
1750a07aba5dSTimm Baeder   if (const auto *FD = Ptr.getField())
1751cfe26358STimm Baeder     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1752a07aba5dSTimm Baeder   else
1753a07aba5dSTimm Baeder     Ptr.deref<T>() = Value;
1754a07aba5dSTimm Baeder   return true;
1755a07aba5dSTimm Baeder }
1756a07aba5dSTimm Baeder 
1757a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1758a07aba5dSTimm Baeder bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1759a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1760a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1761a07aba5dSTimm Baeder   if (!CheckStore(S, OpPC, Ptr))
1762a07aba5dSTimm Baeder     return false;
1763a07aba5dSTimm Baeder   if (Ptr.canBeInitialized())
1764a07aba5dSTimm Baeder     Ptr.initialize();
1765a07aba5dSTimm Baeder   if (const auto *FD = Ptr.getField())
1766cfe26358STimm Baeder     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1767a07aba5dSTimm Baeder   else
1768a07aba5dSTimm Baeder     Ptr.deref<T>() = Value;
1769a07aba5dSTimm Baeder   return true;
1770a07aba5dSTimm Baeder }
1771a07aba5dSTimm Baeder 
1772a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1773a07aba5dSTimm Baeder bool Init(InterpState &S, CodePtr OpPC) {
1774a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1775a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
1776a07aba5dSTimm Baeder   if (!CheckInit(S, OpPC, Ptr)) {
1777a07aba5dSTimm Baeder     assert(false);
1778a07aba5dSTimm Baeder     return false;
1779a07aba5dSTimm Baeder   }
17805d086253STimm Baeder   Ptr.activate();
1781a07aba5dSTimm Baeder   Ptr.initialize();
1782a07aba5dSTimm Baeder   new (&Ptr.deref<T>()) T(Value);
1783a07aba5dSTimm Baeder   return true;
1784a07aba5dSTimm Baeder }
1785a07aba5dSTimm Baeder 
1786a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1787a07aba5dSTimm Baeder bool InitPop(InterpState &S, CodePtr OpPC) {
1788a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
1789a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1790a07aba5dSTimm Baeder   if (!CheckInit(S, OpPC, Ptr))
1791a07aba5dSTimm Baeder     return false;
17925d086253STimm Baeder   Ptr.activate();
1793a07aba5dSTimm Baeder   Ptr.initialize();
1794a07aba5dSTimm Baeder   new (&Ptr.deref<T>()) T(Value);
1795a07aba5dSTimm Baeder   return true;
1796a07aba5dSTimm Baeder }
1797a07aba5dSTimm Baeder 
1798a07aba5dSTimm Baeder /// 1) Pops the value from the stack
1799a07aba5dSTimm Baeder /// 2) Peeks a pointer and gets its index \Idx
1800a07aba5dSTimm Baeder /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1801a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1802a07aba5dSTimm Baeder bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1803a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
180403888a90STimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
180503888a90STimm Baeder 
1806a07aba5dSTimm Baeder   if (Ptr.isUnknownSizeArray())
1807a07aba5dSTimm Baeder     return false;
180803888a90STimm Baeder 
180903888a90STimm Baeder   // In the unlikely event that we're initializing the first item of
181003888a90STimm Baeder   // a non-array, skip the atIndex().
181103888a90STimm Baeder   if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1812a07aba5dSTimm Baeder     Ptr.initialize();
1813a07aba5dSTimm Baeder     new (&Ptr.deref<T>()) T(Value);
1814a07aba5dSTimm Baeder     return true;
1815a07aba5dSTimm Baeder   }
1816a07aba5dSTimm Baeder 
181703888a90STimm Baeder   const Pointer &ElemPtr = Ptr.atIndex(Idx);
181803888a90STimm Baeder   if (!CheckInit(S, OpPC, ElemPtr))
181903888a90STimm Baeder     return false;
182003888a90STimm Baeder   ElemPtr.initialize();
182103888a90STimm Baeder   new (&ElemPtr.deref<T>()) T(Value);
182203888a90STimm Baeder   return true;
182303888a90STimm Baeder }
182403888a90STimm Baeder 
1825a07aba5dSTimm Baeder /// The same as InitElem, but pops the pointer as well.
1826a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1827a07aba5dSTimm Baeder bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1828a07aba5dSTimm Baeder   const T &Value = S.Stk.pop<T>();
182903888a90STimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
1830a07aba5dSTimm Baeder   if (Ptr.isUnknownSizeArray())
1831a07aba5dSTimm Baeder     return false;
183203888a90STimm Baeder 
183303888a90STimm Baeder   // In the unlikely event that we're initializing the first item of
183403888a90STimm Baeder   // a non-array, skip the atIndex().
183503888a90STimm Baeder   if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1836a07aba5dSTimm Baeder     Ptr.initialize();
1837a07aba5dSTimm Baeder     new (&Ptr.deref<T>()) T(Value);
1838a07aba5dSTimm Baeder     return true;
1839a07aba5dSTimm Baeder   }
1840a07aba5dSTimm Baeder 
184103888a90STimm Baeder   const Pointer &ElemPtr = Ptr.atIndex(Idx);
184203888a90STimm Baeder   if (!CheckInit(S, OpPC, ElemPtr))
184303888a90STimm Baeder     return false;
184403888a90STimm Baeder   ElemPtr.initialize();
184503888a90STimm Baeder   new (&ElemPtr.deref<T>()) T(Value);
184603888a90STimm Baeder   return true;
184703888a90STimm Baeder }
184803888a90STimm Baeder 
1849a07aba5dSTimm Baeder inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1850a07aba5dSTimm Baeder   const Pointer &Src = S.Stk.pop<Pointer>();
1851a07aba5dSTimm Baeder   Pointer &Dest = S.Stk.peek<Pointer>();
1852a07aba5dSTimm Baeder 
1853a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Src))
1854a07aba5dSTimm Baeder     return false;
1855a07aba5dSTimm Baeder 
1856a07aba5dSTimm Baeder   return DoMemcpy(S, OpPC, Src, Dest);
1857a07aba5dSTimm Baeder }
1858a07aba5dSTimm Baeder 
1859a07aba5dSTimm Baeder inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1860a07aba5dSTimm Baeder   const auto &Member = S.Stk.pop<MemberPointer>();
1861a07aba5dSTimm Baeder   const auto &Base = S.Stk.pop<Pointer>();
1862a07aba5dSTimm Baeder 
1863a07aba5dSTimm Baeder   S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1864a07aba5dSTimm Baeder   return true;
1865a07aba5dSTimm Baeder }
1866a07aba5dSTimm Baeder 
1867a07aba5dSTimm Baeder inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1868a07aba5dSTimm Baeder   const auto &MP = S.Stk.pop<MemberPointer>();
1869a07aba5dSTimm Baeder 
1870a07aba5dSTimm Baeder   if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1871a07aba5dSTimm Baeder     S.Stk.push<Pointer>(*Ptr);
1872a07aba5dSTimm Baeder     return true;
1873a07aba5dSTimm Baeder   }
1874a07aba5dSTimm Baeder   return false;
1875a07aba5dSTimm Baeder }
1876a07aba5dSTimm Baeder 
1877a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1878a07aba5dSTimm Baeder // AddOffset, SubOffset
1879a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
1880a07aba5dSTimm Baeder 
1881a07aba5dSTimm Baeder template <class T, ArithOp Op>
1882a07aba5dSTimm Baeder bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1883923b8eeaSTimm Baeder                   const Pointer &Ptr, bool IsPointerArith = false) {
1884a07aba5dSTimm Baeder   // A zero offset does not change the pointer.
1885a07aba5dSTimm Baeder   if (Offset.isZero()) {
1886a07aba5dSTimm Baeder     S.Stk.push<Pointer>(Ptr);
1887a07aba5dSTimm Baeder     return true;
1888a07aba5dSTimm Baeder   }
1889a07aba5dSTimm Baeder 
1890923b8eeaSTimm Baeder   if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1891a07aba5dSTimm Baeder     // The CheckNull will have emitted a note already, but we only
1892a07aba5dSTimm Baeder     // abort in C++, since this is fine in C.
1893a07aba5dSTimm Baeder     if (S.getLangOpts().CPlusPlus)
1894a07aba5dSTimm Baeder       return false;
1895a07aba5dSTimm Baeder   }
1896a07aba5dSTimm Baeder 
1897a07aba5dSTimm Baeder   // Arrays of unknown bounds cannot have pointers into them.
1898a07aba5dSTimm Baeder   if (!CheckArray(S, OpPC, Ptr))
1899a07aba5dSTimm Baeder     return false;
1900a07aba5dSTimm Baeder 
1901dac18299STimm Baeder   // This is much simpler for integral pointers, so handle them first.
1902dac18299STimm Baeder   if (Ptr.isIntegralPointer()) {
1903dac18299STimm Baeder     uint64_t V = Ptr.getIntegerRepresentation();
1904dac18299STimm Baeder     uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
1905dac18299STimm Baeder     if constexpr (Op == ArithOp::Add)
1906dac18299STimm Baeder       S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
1907dac18299STimm Baeder     else
1908dac18299STimm Baeder       S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
1909dac18299STimm Baeder     return true;
1910db94852bSTimm Baeder   } else if (Ptr.isFunctionPointer()) {
1911db94852bSTimm Baeder     uint64_t O = static_cast<uint64_t>(Offset);
1912db94852bSTimm Baeder     uint64_t N;
1913db94852bSTimm Baeder     if constexpr (Op == ArithOp::Add)
1914db94852bSTimm Baeder       N = Ptr.getByteOffset() + O;
1915db94852bSTimm Baeder     else
1916db94852bSTimm Baeder       N = Ptr.getByteOffset() - O;
1917db94852bSTimm Baeder 
1918db94852bSTimm Baeder     if (N > 1)
1919db94852bSTimm Baeder       S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1920db94852bSTimm Baeder           << N << /*non-array*/ true << 0;
1921db94852bSTimm Baeder     S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N);
1922db94852bSTimm Baeder     return true;
1923dac18299STimm Baeder   }
1924dac18299STimm Baeder 
1925db94852bSTimm Baeder   assert(Ptr.isBlockPointer());
1926db94852bSTimm Baeder 
1927a07aba5dSTimm Baeder   uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1928a07aba5dSTimm Baeder   uint64_t Index;
1929a07aba5dSTimm Baeder   if (Ptr.isOnePastEnd())
1930a07aba5dSTimm Baeder     Index = MaxIndex;
1931a07aba5dSTimm Baeder   else
1932a07aba5dSTimm Baeder     Index = Ptr.getIndex();
1933a07aba5dSTimm Baeder 
1934a07aba5dSTimm Baeder   bool Invalid = false;
1935a07aba5dSTimm Baeder   // Helper to report an invalid offset, computed as APSInt.
1936a07aba5dSTimm Baeder   auto DiagInvalidOffset = [&]() -> void {
1937a07aba5dSTimm Baeder     const unsigned Bits = Offset.bitWidth();
1938a07aba5dSTimm Baeder     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1939a07aba5dSTimm Baeder     APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1940a07aba5dSTimm Baeder                    /*IsUnsigned=*/false);
1941a07aba5dSTimm Baeder     APSInt NewIndex =
1942a07aba5dSTimm Baeder         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1943a07aba5dSTimm Baeder     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1944a07aba5dSTimm Baeder         << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1945a07aba5dSTimm Baeder     Invalid = true;
1946a07aba5dSTimm Baeder   };
1947a07aba5dSTimm Baeder 
1948a07aba5dSTimm Baeder   if (Ptr.isBlockPointer()) {
1949a07aba5dSTimm Baeder     uint64_t IOffset = static_cast<uint64_t>(Offset);
1950a07aba5dSTimm Baeder     uint64_t MaxOffset = MaxIndex - Index;
1951a07aba5dSTimm Baeder 
1952a07aba5dSTimm Baeder     if constexpr (Op == ArithOp::Add) {
1953a07aba5dSTimm Baeder       // If the new offset would be negative, bail out.
1954a07aba5dSTimm Baeder       if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1955a07aba5dSTimm Baeder         DiagInvalidOffset();
1956a07aba5dSTimm Baeder 
1957a07aba5dSTimm Baeder       // If the new offset would be out of bounds, bail out.
1958a07aba5dSTimm Baeder       if (Offset.isPositive() && IOffset > MaxOffset)
1959a07aba5dSTimm Baeder         DiagInvalidOffset();
1960a07aba5dSTimm Baeder     } else {
1961a07aba5dSTimm Baeder       // If the new offset would be negative, bail out.
1962a07aba5dSTimm Baeder       if (Offset.isPositive() && Index < IOffset)
1963a07aba5dSTimm Baeder         DiagInvalidOffset();
1964a07aba5dSTimm Baeder 
1965a07aba5dSTimm Baeder       // If the new offset would be out of bounds, bail out.
1966a07aba5dSTimm Baeder       if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1967a07aba5dSTimm Baeder         DiagInvalidOffset();
1968a07aba5dSTimm Baeder     }
1969a07aba5dSTimm Baeder   }
1970a07aba5dSTimm Baeder 
1971a07aba5dSTimm Baeder   if (Invalid && S.getLangOpts().CPlusPlus)
1972a07aba5dSTimm Baeder     return false;
1973a07aba5dSTimm Baeder 
1974a07aba5dSTimm Baeder   // Offset is valid - compute it on unsigned.
1975a07aba5dSTimm Baeder   int64_t WideIndex = static_cast<int64_t>(Index);
1976a07aba5dSTimm Baeder   int64_t WideOffset = static_cast<int64_t>(Offset);
1977a07aba5dSTimm Baeder   int64_t Result;
1978a07aba5dSTimm Baeder   if constexpr (Op == ArithOp::Add)
1979a07aba5dSTimm Baeder     Result = WideIndex + WideOffset;
1980a07aba5dSTimm Baeder   else
1981a07aba5dSTimm Baeder     Result = WideIndex - WideOffset;
1982a07aba5dSTimm Baeder 
1983a07aba5dSTimm Baeder   // When the pointer is one-past-end, going back to index 0 is the only
1984a07aba5dSTimm Baeder   // useful thing we can do. Any other index has been diagnosed before and
1985a07aba5dSTimm Baeder   // we don't get here.
1986a07aba5dSTimm Baeder   if (Result == 0 && Ptr.isOnePastEnd()) {
1987a07aba5dSTimm Baeder     S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
1988a07aba5dSTimm Baeder                         Ptr.asBlockPointer().Base);
1989a07aba5dSTimm Baeder     return true;
1990a07aba5dSTimm Baeder   }
1991a07aba5dSTimm Baeder 
1992a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1993a07aba5dSTimm Baeder   return true;
1994a07aba5dSTimm Baeder }
1995a07aba5dSTimm Baeder 
1996a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
1997a07aba5dSTimm Baeder bool AddOffset(InterpState &S, CodePtr OpPC) {
1998a07aba5dSTimm Baeder   const T &Offset = S.Stk.pop<T>();
1999d6d60707STimm Baeder   Pointer Ptr = S.Stk.pop<Pointer>();
2000d6d60707STimm Baeder   if (Ptr.isBlockPointer())
2001d6d60707STimm Baeder     Ptr = Ptr.expand();
2002923b8eeaSTimm Baeder   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
2003923b8eeaSTimm Baeder                                        /*IsPointerArith=*/true);
2004a07aba5dSTimm Baeder }
2005a07aba5dSTimm Baeder 
2006a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2007a07aba5dSTimm Baeder bool SubOffset(InterpState &S, CodePtr OpPC) {
2008a07aba5dSTimm Baeder   const T &Offset = S.Stk.pop<T>();
2009a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2010923b8eeaSTimm Baeder   return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
2011923b8eeaSTimm Baeder                                        /*IsPointerArith=*/true);
2012a07aba5dSTimm Baeder }
2013a07aba5dSTimm Baeder 
2014a07aba5dSTimm Baeder template <ArithOp Op>
2015a07aba5dSTimm Baeder static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2016a07aba5dSTimm Baeder                                    const Pointer &Ptr) {
2017a07aba5dSTimm Baeder   if (Ptr.isDummy())
2018a07aba5dSTimm Baeder     return false;
2019a07aba5dSTimm Baeder 
2020a07aba5dSTimm Baeder   using OneT = Integral<8, false>;
2021a07aba5dSTimm Baeder 
2022a07aba5dSTimm Baeder   const Pointer &P = Ptr.deref<Pointer>();
2023a07aba5dSTimm Baeder   if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
2024a07aba5dSTimm Baeder     return false;
2025a07aba5dSTimm Baeder 
2026a07aba5dSTimm Baeder   // Get the current value on the stack.
2027a07aba5dSTimm Baeder   S.Stk.push<Pointer>(P);
2028a07aba5dSTimm Baeder 
2029a07aba5dSTimm Baeder   // Now the current Ptr again and a constant 1.
2030a07aba5dSTimm Baeder   OneT One = OneT::from(1);
2031923b8eeaSTimm Baeder   if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true))
2032a07aba5dSTimm Baeder     return false;
2033a07aba5dSTimm Baeder 
2034a07aba5dSTimm Baeder   // Store the new value.
2035a07aba5dSTimm Baeder   Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
2036a07aba5dSTimm Baeder   return true;
2037a07aba5dSTimm Baeder }
2038a07aba5dSTimm Baeder 
2039a07aba5dSTimm Baeder static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2040a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2041a07aba5dSTimm Baeder 
2042a07aba5dSTimm Baeder   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
2043a07aba5dSTimm Baeder     return false;
2044a07aba5dSTimm Baeder 
2045a07aba5dSTimm Baeder   return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2046a07aba5dSTimm Baeder }
2047a07aba5dSTimm Baeder 
2048a07aba5dSTimm Baeder static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2049a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2050a07aba5dSTimm Baeder 
2051a07aba5dSTimm Baeder   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
2052a07aba5dSTimm Baeder     return false;
2053a07aba5dSTimm Baeder 
2054a07aba5dSTimm Baeder   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2055a07aba5dSTimm Baeder }
2056a07aba5dSTimm Baeder 
2057a07aba5dSTimm Baeder /// 1) Pops a Pointer from the stack.
2058a07aba5dSTimm Baeder /// 2) Pops another Pointer from the stack.
2059a07aba5dSTimm Baeder /// 3) Pushes the different of the indices of the two pointers on the stack.
2060a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2061a07aba5dSTimm Baeder inline bool SubPtr(InterpState &S, CodePtr OpPC) {
2062a07aba5dSTimm Baeder   const Pointer &LHS = S.Stk.pop<Pointer>();
2063a07aba5dSTimm Baeder   const Pointer &RHS = S.Stk.pop<Pointer>();
2064a07aba5dSTimm Baeder 
2065a07aba5dSTimm Baeder   for (const Pointer &P : {LHS, RHS}) {
2066a07aba5dSTimm Baeder     if (P.isZeroSizeArray()) {
2067a07aba5dSTimm Baeder       QualType PtrT = P.getType();
2068a07aba5dSTimm Baeder       while (auto *AT = dyn_cast<ArrayType>(PtrT))
2069a07aba5dSTimm Baeder         PtrT = AT->getElementType();
2070a07aba5dSTimm Baeder 
2071d9e72860Syronglin       QualType ArrayTy = S.getASTContext().getConstantArrayType(
2072a07aba5dSTimm Baeder           PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2073a07aba5dSTimm Baeder       S.FFDiag(S.Current->getSource(OpPC),
2074a07aba5dSTimm Baeder                diag::note_constexpr_pointer_subtraction_zero_size)
2075a07aba5dSTimm Baeder           << ArrayTy;
2076a07aba5dSTimm Baeder 
2077a07aba5dSTimm Baeder       return false;
2078a07aba5dSTimm Baeder     }
2079a07aba5dSTimm Baeder   }
2080a07aba5dSTimm Baeder 
2081a07aba5dSTimm Baeder   if (RHS.isZero()) {
2082a07aba5dSTimm Baeder     S.Stk.push<T>(T::from(LHS.getIndex()));
2083a07aba5dSTimm Baeder     return true;
2084a07aba5dSTimm Baeder   }
2085a07aba5dSTimm Baeder 
2086a07aba5dSTimm Baeder   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2087a07aba5dSTimm Baeder     // TODO: Diagnose.
2088a07aba5dSTimm Baeder     return false;
2089a07aba5dSTimm Baeder   }
2090a07aba5dSTimm Baeder 
2091a07aba5dSTimm Baeder   if (LHS.isZero() && RHS.isZero()) {
2092a07aba5dSTimm Baeder     S.Stk.push<T>();
2093a07aba5dSTimm Baeder     return true;
2094a07aba5dSTimm Baeder   }
2095a07aba5dSTimm Baeder 
2096db94852bSTimm Baeder   T A = LHS.isBlockPointer()
2097db94852bSTimm Baeder             ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
2098db94852bSTimm Baeder                                       : T::from(LHS.getIndex()))
2099db94852bSTimm Baeder             : T::from(LHS.getIntegerRepresentation());
2100db94852bSTimm Baeder   T B = RHS.isBlockPointer()
2101db94852bSTimm Baeder             ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2102db94852bSTimm Baeder                                       : T::from(RHS.getIndex()))
2103db94852bSTimm Baeder             : T::from(RHS.getIntegerRepresentation());
2104db94852bSTimm Baeder 
2105a07aba5dSTimm Baeder   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2106a07aba5dSTimm Baeder }
2107a07aba5dSTimm Baeder 
2108a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2109a07aba5dSTimm Baeder // Destroy
2110a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2111a07aba5dSTimm Baeder 
2112a07aba5dSTimm Baeder inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2113a07aba5dSTimm Baeder   S.Current->destroy(I);
2114a07aba5dSTimm Baeder   return true;
2115a07aba5dSTimm Baeder }
2116a07aba5dSTimm Baeder 
2117a07aba5dSTimm Baeder inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2118a07aba5dSTimm Baeder   S.Current->initScope(I);
2119a07aba5dSTimm Baeder   return true;
2120a07aba5dSTimm Baeder }
2121a07aba5dSTimm Baeder 
2122a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2123a07aba5dSTimm Baeder // Cast, CastFP
2124a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2125a07aba5dSTimm Baeder 
2126a07aba5dSTimm Baeder template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2127a07aba5dSTimm Baeder   using T = typename PrimConv<TIn>::T;
2128a07aba5dSTimm Baeder   using U = typename PrimConv<TOut>::T;
2129a07aba5dSTimm Baeder   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2130a07aba5dSTimm Baeder   return true;
2131a07aba5dSTimm Baeder }
2132a07aba5dSTimm Baeder 
2133a07aba5dSTimm Baeder /// 1) Pops a Floating from the stack.
2134a07aba5dSTimm Baeder /// 2) Pushes a new floating on the stack that uses the given semantics.
2135a07aba5dSTimm Baeder inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2136a07aba5dSTimm Baeder                    llvm::RoundingMode RM) {
2137a07aba5dSTimm Baeder   Floating F = S.Stk.pop<Floating>();
2138a07aba5dSTimm Baeder   Floating Result = F.toSemantics(Sem, RM);
2139a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
2140a07aba5dSTimm Baeder   return true;
2141a07aba5dSTimm Baeder }
2142a07aba5dSTimm Baeder 
2143c2a37e41STimm Baeder inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2144046b064dSTimm Baeder   FixedPointSemantics TargetSemantics =
2145046b064dSTimm Baeder       FixedPointSemantics::getFromOpaqueInt(FPS);
2146c2a37e41STimm Baeder   const auto &Source = S.Stk.pop<FixedPoint>();
2147c2a37e41STimm Baeder 
2148c2a37e41STimm Baeder   bool Overflow;
2149c2a37e41STimm Baeder   FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2150c2a37e41STimm Baeder 
215195ce78b7STimm Baeder   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2152c2a37e41STimm Baeder     return false;
2153c2a37e41STimm Baeder 
2154c2a37e41STimm Baeder   S.Stk.push<FixedPoint>(Result);
2155c2a37e41STimm Baeder   return true;
2156c2a37e41STimm Baeder }
2157c2a37e41STimm Baeder 
2158a07aba5dSTimm Baeder /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2159a07aba5dSTimm Baeder /// to know what bitwidth the result should be.
2160a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2161a07aba5dSTimm Baeder bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2162a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<false>>(
2163a07aba5dSTimm Baeder       IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2164a07aba5dSTimm Baeder   return true;
2165a07aba5dSTimm Baeder }
2166a07aba5dSTimm Baeder 
2167a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2168a07aba5dSTimm Baeder bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2169a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<true>>(
2170a07aba5dSTimm Baeder       IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2171a07aba5dSTimm Baeder   return true;
2172a07aba5dSTimm Baeder }
2173a07aba5dSTimm Baeder 
2174a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2175a07aba5dSTimm Baeder bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
21760f5f440fSTimm Baeder                           const llvm::fltSemantics *Sem, uint32_t FPOI) {
2177a07aba5dSTimm Baeder   const T &From = S.Stk.pop<T>();
2178a07aba5dSTimm Baeder   APSInt FromAP = From.toAPSInt();
2179a07aba5dSTimm Baeder   Floating Result;
2180a07aba5dSTimm Baeder 
21810f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
21820f5f440fSTimm Baeder   auto Status =
21830f5f440fSTimm Baeder       Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
2184a07aba5dSTimm Baeder   S.Stk.push<Floating>(Result);
2185a07aba5dSTimm Baeder 
21860f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, Result, Status, FPO);
2187a07aba5dSTimm Baeder }
2188a07aba5dSTimm Baeder 
2189a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
21900f5f440fSTimm Baeder bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2191a07aba5dSTimm Baeder   const Floating &F = S.Stk.pop<Floating>();
2192a07aba5dSTimm Baeder 
2193a07aba5dSTimm Baeder   if constexpr (std::is_same_v<T, Boolean>) {
2194a07aba5dSTimm Baeder     S.Stk.push<T>(T(F.isNonZero()));
2195a07aba5dSTimm Baeder     return true;
2196a07aba5dSTimm Baeder   } else {
2197a07aba5dSTimm Baeder     APSInt Result(std::max(8u, T::bitWidth()),
2198a07aba5dSTimm Baeder                   /*IsUnsigned=*/!T::isSigned());
2199a07aba5dSTimm Baeder     auto Status = F.convertToInteger(Result);
2200a07aba5dSTimm Baeder 
2201a07aba5dSTimm Baeder     // Float-to-Integral overflow check.
2202a07aba5dSTimm Baeder     if ((Status & APFloat::opStatus::opInvalidOp)) {
2203a07aba5dSTimm Baeder       const Expr *E = S.Current->getExpr(OpPC);
2204a07aba5dSTimm Baeder       QualType Type = E->getType();
2205a07aba5dSTimm Baeder 
2206a07aba5dSTimm Baeder       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2207a07aba5dSTimm Baeder       if (S.noteUndefinedBehavior()) {
2208a07aba5dSTimm Baeder         S.Stk.push<T>(T(Result));
2209a07aba5dSTimm Baeder         return true;
2210a07aba5dSTimm Baeder       }
2211a07aba5dSTimm Baeder       return false;
2212a07aba5dSTimm Baeder     }
2213a07aba5dSTimm Baeder 
22140f5f440fSTimm Baeder     FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2215a07aba5dSTimm Baeder     S.Stk.push<T>(T(Result));
22160f5f440fSTimm Baeder     return CheckFloatResult(S, OpPC, F, Status, FPO);
2217a07aba5dSTimm Baeder   }
2218a07aba5dSTimm Baeder }
2219a07aba5dSTimm Baeder 
2220a07aba5dSTimm Baeder static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
22210f5f440fSTimm Baeder                                           uint32_t BitWidth, uint32_t FPOI) {
2222a07aba5dSTimm Baeder   const Floating &F = S.Stk.pop<Floating>();
2223a07aba5dSTimm Baeder 
2224a07aba5dSTimm Baeder   APSInt Result(BitWidth, /*IsUnsigned=*/true);
2225a07aba5dSTimm Baeder   auto Status = F.convertToInteger(Result);
2226a07aba5dSTimm Baeder 
2227a07aba5dSTimm Baeder   // Float-to-Integral overflow check.
222895ce78b7STimm Baeder   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
222995ce78b7STimm Baeder     return handleOverflow(S, OpPC, F.getAPFloat());
2230a07aba5dSTimm Baeder 
22310f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2232a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
22330f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, F, Status, FPO);
2234a07aba5dSTimm Baeder }
2235a07aba5dSTimm Baeder 
2236a07aba5dSTimm Baeder static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
22370f5f440fSTimm Baeder                                            uint32_t BitWidth, uint32_t FPOI) {
2238a07aba5dSTimm Baeder   const Floating &F = S.Stk.pop<Floating>();
2239a07aba5dSTimm Baeder 
2240a07aba5dSTimm Baeder   APSInt Result(BitWidth, /*IsUnsigned=*/false);
2241a07aba5dSTimm Baeder   auto Status = F.convertToInteger(Result);
2242a07aba5dSTimm Baeder 
2243a07aba5dSTimm Baeder   // Float-to-Integral overflow check.
224495ce78b7STimm Baeder   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
224595ce78b7STimm Baeder     return handleOverflow(S, OpPC, F.getAPFloat());
2246a07aba5dSTimm Baeder 
22470f5f440fSTimm Baeder   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2248a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
22490f5f440fSTimm Baeder   return CheckFloatResult(S, OpPC, F, Status, FPO);
2250a07aba5dSTimm Baeder }
2251a07aba5dSTimm Baeder 
2252e637a5c9STimm Baeder bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2253e637a5c9STimm Baeder                                 const Pointer &Ptr, unsigned BitWidth);
2254e637a5c9STimm Baeder bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2255e637a5c9STimm Baeder bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2256e637a5c9STimm Baeder 
2257a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2258a07aba5dSTimm Baeder bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
2259a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2260a07aba5dSTimm Baeder 
2261e637a5c9STimm Baeder   if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2262a07aba5dSTimm Baeder     return false;
2263a07aba5dSTimm Baeder 
2264a07aba5dSTimm Baeder   S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2265a07aba5dSTimm Baeder   return true;
2266a07aba5dSTimm Baeder }
2267a07aba5dSTimm Baeder 
2268641b4d53STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2269641b4d53STimm Baeder static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2270641b4d53STimm Baeder                                           uint32_t FPS) {
2271641b4d53STimm Baeder   const T &Int = S.Stk.pop<T>();
2272641b4d53STimm Baeder 
2273046b064dSTimm Baeder   FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2274641b4d53STimm Baeder 
2275641b4d53STimm Baeder   bool Overflow;
227695ce78b7STimm Baeder   FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2277641b4d53STimm Baeder 
227895ce78b7STimm Baeder   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2279641b4d53STimm Baeder     return false;
2280641b4d53STimm Baeder 
22816cbd8a30STimm Baeder   S.Stk.push<FixedPoint>(Result);
22826cbd8a30STimm Baeder   return true;
22836cbd8a30STimm Baeder }
22846cbd8a30STimm Baeder 
22856cbd8a30STimm Baeder static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
22866cbd8a30STimm Baeder                                           uint32_t FPS) {
22876cbd8a30STimm Baeder   const auto &Float = S.Stk.pop<Floating>();
22886cbd8a30STimm Baeder 
2289046b064dSTimm Baeder   FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
22906cbd8a30STimm Baeder 
22916cbd8a30STimm Baeder   bool Overflow;
229295ce78b7STimm Baeder   FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
22936cbd8a30STimm Baeder 
229495ce78b7STimm Baeder   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
22956cbd8a30STimm Baeder     return false;
22966cbd8a30STimm Baeder 
22976cbd8a30STimm Baeder   S.Stk.push<FixedPoint>(Result);
2298641b4d53STimm Baeder   return true;
2299641b4d53STimm Baeder }
2300641b4d53STimm Baeder 
23013a5b9da1STimm Baeder static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
23023a5b9da1STimm Baeder                                           const llvm::fltSemantics *Sem) {
23033a5b9da1STimm Baeder   const auto &Fixed = S.Stk.pop<FixedPoint>();
23043a5b9da1STimm Baeder 
23053a5b9da1STimm Baeder   S.Stk.push<Floating>(Fixed.toFloat(Sem));
23063a5b9da1STimm Baeder   return true;
23073a5b9da1STimm Baeder }
23083a5b9da1STimm Baeder 
230995ce78b7STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
231095ce78b7STimm Baeder static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
231195ce78b7STimm Baeder   const auto &Fixed = S.Stk.pop<FixedPoint>();
231295ce78b7STimm Baeder 
231395ce78b7STimm Baeder   bool Overflow;
231495ce78b7STimm Baeder   APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
231595ce78b7STimm Baeder 
231695ce78b7STimm Baeder   if (Overflow && !handleOverflow(S, OpPC, Int))
231795ce78b7STimm Baeder     return false;
231895ce78b7STimm Baeder 
231995ce78b7STimm Baeder   S.Stk.push<T>(Int);
232095ce78b7STimm Baeder   return true;
232195ce78b7STimm Baeder }
232295ce78b7STimm Baeder 
2323a07aba5dSTimm Baeder static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2324a07aba5dSTimm Baeder   const auto &Ptr = S.Stk.peek<Pointer>();
2325a07aba5dSTimm Baeder 
2326a07aba5dSTimm Baeder   if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2327a07aba5dSTimm Baeder     bool HasValidResult = !Ptr.isZero();
2328a07aba5dSTimm Baeder 
2329a07aba5dSTimm Baeder     if (HasValidResult) {
2330a07aba5dSTimm Baeder       // FIXME: note_constexpr_invalid_void_star_cast
2331a07aba5dSTimm Baeder     } else if (!S.getLangOpts().CPlusPlus26) {
2332a07aba5dSTimm Baeder       const SourceInfo &E = S.Current->getSource(OpPC);
2333a07aba5dSTimm Baeder       S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2334a07aba5dSTimm Baeder           << 3 << "'void *'" << S.Current->getRange(OpPC);
2335a07aba5dSTimm Baeder     }
2336a07aba5dSTimm Baeder   } else {
2337a07aba5dSTimm Baeder     const SourceInfo &E = S.Current->getSource(OpPC);
2338a07aba5dSTimm Baeder     S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2339a07aba5dSTimm Baeder         << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2340a07aba5dSTimm Baeder   }
2341a07aba5dSTimm Baeder 
2342a07aba5dSTimm Baeder   return true;
2343a07aba5dSTimm Baeder }
2344a07aba5dSTimm Baeder 
2345a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2346a07aba5dSTimm Baeder // Zero, Nullptr
2347a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2348a07aba5dSTimm Baeder 
2349a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2350a07aba5dSTimm Baeder bool Zero(InterpState &S, CodePtr OpPC) {
2351a07aba5dSTimm Baeder   S.Stk.push<T>(T::zero());
2352a07aba5dSTimm Baeder   return true;
2353a07aba5dSTimm Baeder }
2354a07aba5dSTimm Baeder 
2355a07aba5dSTimm Baeder static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2356a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2357a07aba5dSTimm Baeder   return true;
2358a07aba5dSTimm Baeder }
2359a07aba5dSTimm Baeder 
2360a07aba5dSTimm Baeder static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2361a07aba5dSTimm Baeder   S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2362a07aba5dSTimm Baeder   return true;
2363a07aba5dSTimm Baeder }
2364a07aba5dSTimm Baeder 
2365a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
236644be7946STimm Baeder inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
236744be7946STimm Baeder                  const Descriptor *Desc) {
236844be7946STimm Baeder   // FIXME(perf): This is a somewhat often-used function and the value of a
236944be7946STimm Baeder   // null pointer is almost always 0.
237044be7946STimm Baeder   S.Stk.push<T>(Value, Desc);
2371a07aba5dSTimm Baeder   return true;
2372a07aba5dSTimm Baeder }
2373a07aba5dSTimm Baeder 
2374360e4abfSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2375360e4abfSTimm Baeder inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2376360e4abfSTimm Baeder   const auto &P = S.Stk.pop<T>();
2377360e4abfSTimm Baeder   if (P.isWeak())
2378360e4abfSTimm Baeder     return false;
2379360e4abfSTimm Baeder   S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2380360e4abfSTimm Baeder   return true;
2381360e4abfSTimm Baeder }
2382360e4abfSTimm Baeder 
2383a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2384a07aba5dSTimm Baeder // This, ImplicitThis
2385a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2386a07aba5dSTimm Baeder 
2387a07aba5dSTimm Baeder inline bool This(InterpState &S, CodePtr OpPC) {
2388a07aba5dSTimm Baeder   // Cannot read 'this' in this mode.
2389a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression()) {
2390a07aba5dSTimm Baeder     return false;
2391a07aba5dSTimm Baeder   }
2392a07aba5dSTimm Baeder 
2393a07aba5dSTimm Baeder   const Pointer &This = S.Current->getThis();
2394a07aba5dSTimm Baeder   if (!CheckThis(S, OpPC, This))
2395a07aba5dSTimm Baeder     return false;
2396a07aba5dSTimm Baeder 
2397a07aba5dSTimm Baeder   // Ensure the This pointer has been cast to the correct base.
2398a07aba5dSTimm Baeder   if (!This.isDummy()) {
2399a07aba5dSTimm Baeder     assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2400a07aba5dSTimm Baeder     assert(This.getRecord());
2401a07aba5dSTimm Baeder     assert(
2402a07aba5dSTimm Baeder         This.getRecord()->getDecl() ==
2403a07aba5dSTimm Baeder         cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2404a07aba5dSTimm Baeder   }
2405a07aba5dSTimm Baeder 
2406a07aba5dSTimm Baeder   S.Stk.push<Pointer>(This);
2407a07aba5dSTimm Baeder   return true;
2408a07aba5dSTimm Baeder }
2409a07aba5dSTimm Baeder 
2410a07aba5dSTimm Baeder inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2411a07aba5dSTimm Baeder   assert(S.Current->getFunction()->hasRVO());
2412a07aba5dSTimm Baeder   if (S.checkingPotentialConstantExpression())
2413a07aba5dSTimm Baeder     return false;
2414a07aba5dSTimm Baeder   S.Stk.push<Pointer>(S.Current->getRVOPtr());
2415a07aba5dSTimm Baeder   return true;
2416a07aba5dSTimm Baeder }
2417a07aba5dSTimm Baeder 
2418a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2419a07aba5dSTimm Baeder // Shr, Shl
2420a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2421a07aba5dSTimm Baeder 
2422a07aba5dSTimm Baeder template <class LT, class RT, ShiftDir Dir>
2423a07aba5dSTimm Baeder inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2424a07aba5dSTimm Baeder   const unsigned Bits = LHS.bitWidth();
2425a07aba5dSTimm Baeder 
2426a07aba5dSTimm Baeder   // OpenCL 6.3j: shift values are effectively % word size of LHS.
2427a07aba5dSTimm Baeder   if (S.getLangOpts().OpenCL)
2428a07aba5dSTimm Baeder     RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2429a07aba5dSTimm Baeder                RHS.bitWidth(), &RHS);
2430a07aba5dSTimm Baeder 
2431a07aba5dSTimm Baeder   if (RHS.isNegative()) {
2432a07aba5dSTimm Baeder     // During constant-folding, a negative shift is an opposite shift. Such a
2433a07aba5dSTimm Baeder     // shift is not a constant expression.
2434a07aba5dSTimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
2435a07aba5dSTimm Baeder     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2436a07aba5dSTimm Baeder     if (!S.noteUndefinedBehavior())
2437a07aba5dSTimm Baeder       return false;
2438a07aba5dSTimm Baeder     RHS = -RHS;
2439a07aba5dSTimm Baeder     return DoShift<LT, RT,
2440a07aba5dSTimm Baeder                    Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2441a07aba5dSTimm Baeder         S, OpPC, LHS, RHS);
2442a07aba5dSTimm Baeder   }
2443a07aba5dSTimm Baeder 
24440050503bSTimm Baeder   if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2445a07aba5dSTimm Baeder     return false;
2446a07aba5dSTimm Baeder 
2447a07aba5dSTimm Baeder   // Limit the shift amount to Bits - 1. If this happened,
2448a07aba5dSTimm Baeder   // it has already been diagnosed by CheckShift() above,
2449a07aba5dSTimm Baeder   // but we still need to handle it.
24502503a665STimm Bäder   // Note that we have to be extra careful here since we're doing the shift in
24512503a665STimm Bäder   // any case, but we need to adjust the shift amount or the way we do the shift
24522503a665STimm Bäder   // for the potential error cases.
2453a07aba5dSTimm Baeder   typename LT::AsUnsigned R;
24542503a665STimm Bäder   unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2455a07aba5dSTimm Baeder   if constexpr (Dir == ShiftDir::Left) {
24562503a665STimm Bäder     if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
24572503a665STimm Bäder         ComparisonCategoryResult::Greater) {
24582503a665STimm Bäder       if (LHS.isNegative())
24592503a665STimm Bäder         R = LT::AsUnsigned::zero(LHS.bitWidth());
24602503a665STimm Bäder       else {
24612503a665STimm Bäder         RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2462a6636ce4STimm Bäder         LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
246349c2207fSTimm Baeder                                   LT::AsUnsigned::from(RHS, Bits), Bits, &R);
246449c2207fSTimm Baeder       }
24652503a665STimm Bäder     } else if (LHS.isNegative()) {
24662503a665STimm Bäder       if (LHS.isMin()) {
24672503a665STimm Bäder         R = LT::AsUnsigned::zero(LHS.bitWidth());
24682503a665STimm Bäder       } else {
24692503a665STimm Bäder         // If the LHS is negative, perform the cast and invert the result.
24702503a665STimm Bäder         typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
24712503a665STimm Bäder         LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
24722503a665STimm Bäder                                   &R);
24732503a665STimm Bäder         R = -R;
24742503a665STimm Bäder       }
24752503a665STimm Bäder     } else {
24762503a665STimm Bäder       // The good case, a simple left shift.
24772503a665STimm Bäder       LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
24782503a665STimm Bäder                                 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
24792503a665STimm Bäder     }
24802503a665STimm Bäder   } else {
24812503a665STimm Bäder     // Right shift.
24822503a665STimm Bäder     if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
24832503a665STimm Bäder         ComparisonCategoryResult::Greater) {
24842503a665STimm Bäder       R = LT::AsUnsigned::from(-1);
24852503a665STimm Bäder     } else {
24862503a665STimm Bäder       // Do the shift on potentially signed LT, then convert to unsigned type.
24872503a665STimm Bäder       LT A;
24882503a665STimm Bäder       LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
24892503a665STimm Bäder       R = LT::AsUnsigned::from(A);
2490555399d5STimm Baeder     }
2491555399d5STimm Baeder   }
2492555399d5STimm Baeder 
2493a07aba5dSTimm Baeder   S.Stk.push<LT>(LT::from(R));
2494a07aba5dSTimm Baeder   return true;
2495a07aba5dSTimm Baeder }
2496a07aba5dSTimm Baeder 
2497a07aba5dSTimm Baeder template <PrimType NameL, PrimType NameR>
2498a07aba5dSTimm Baeder inline bool Shr(InterpState &S, CodePtr OpPC) {
2499a07aba5dSTimm Baeder   using LT = typename PrimConv<NameL>::T;
2500a07aba5dSTimm Baeder   using RT = typename PrimConv<NameR>::T;
2501a07aba5dSTimm Baeder   auto RHS = S.Stk.pop<RT>();
2502a07aba5dSTimm Baeder   auto LHS = S.Stk.pop<LT>();
2503a07aba5dSTimm Baeder 
2504a07aba5dSTimm Baeder   return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2505a07aba5dSTimm Baeder }
2506a07aba5dSTimm Baeder 
2507a07aba5dSTimm Baeder template <PrimType NameL, PrimType NameR>
2508a07aba5dSTimm Baeder inline bool Shl(InterpState &S, CodePtr OpPC) {
2509a07aba5dSTimm Baeder   using LT = typename PrimConv<NameL>::T;
2510a07aba5dSTimm Baeder   using RT = typename PrimConv<NameR>::T;
2511a07aba5dSTimm Baeder   auto RHS = S.Stk.pop<RT>();
2512a07aba5dSTimm Baeder   auto LHS = S.Stk.pop<LT>();
2513a07aba5dSTimm Baeder 
2514a07aba5dSTimm Baeder   return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2515a07aba5dSTimm Baeder }
2516a07aba5dSTimm Baeder 
25176f04e65cSTimm Baeder static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
25186f04e65cSTimm Baeder   const auto &RHS = S.Stk.pop<FixedPoint>();
25196f04e65cSTimm Baeder   const auto &LHS = S.Stk.pop<FixedPoint>();
25206f04e65cSTimm Baeder   llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
25216f04e65cSTimm Baeder 
25226f04e65cSTimm Baeder   unsigned ShiftBitWidth =
25236f04e65cSTimm Baeder       LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
25246f04e65cSTimm Baeder 
25256f04e65cSTimm Baeder   // Embedded-C 4.1.6.2.2:
25266f04e65cSTimm Baeder   //   The right operand must be nonnegative and less than the total number
25276f04e65cSTimm Baeder   //   of (nonpadding) bits of the fixed-point operand ...
25286f04e65cSTimm Baeder   if (RHS.isNegative()) {
25296f04e65cSTimm Baeder     S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
25306f04e65cSTimm Baeder         << RHS.toAPSInt();
25316f04e65cSTimm Baeder   } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
25326f04e65cSTimm Baeder                  ShiftBitWidth)) != RHS.toAPSInt()) {
25336f04e65cSTimm Baeder     const Expr *E = S.Current->getExpr(OpPC);
25346f04e65cSTimm Baeder     S.CCEDiag(E, diag::note_constexpr_large_shift)
25356f04e65cSTimm Baeder         << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
25366f04e65cSTimm Baeder   }
25376f04e65cSTimm Baeder 
25386f04e65cSTimm Baeder   FixedPoint Result;
25396f04e65cSTimm Baeder   if (Left) {
25406f04e65cSTimm Baeder     if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
25416f04e65cSTimm Baeder         !handleFixedPointOverflow(S, OpPC, Result))
25426f04e65cSTimm Baeder       return false;
25436f04e65cSTimm Baeder   } else {
25446f04e65cSTimm Baeder     if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
25456f04e65cSTimm Baeder         !handleFixedPointOverflow(S, OpPC, Result))
25466f04e65cSTimm Baeder       return false;
25476f04e65cSTimm Baeder   }
25486f04e65cSTimm Baeder 
25496f04e65cSTimm Baeder   S.Stk.push<FixedPoint>(Result);
25506f04e65cSTimm Baeder   return true;
25516f04e65cSTimm Baeder }
25526f04e65cSTimm Baeder 
2553a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2554a07aba5dSTimm Baeder // NoRet
2555a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2556a07aba5dSTimm Baeder 
2557a07aba5dSTimm Baeder inline bool NoRet(InterpState &S, CodePtr OpPC) {
2558a07aba5dSTimm Baeder   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2559a07aba5dSTimm Baeder   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2560a07aba5dSTimm Baeder   return false;
2561a07aba5dSTimm Baeder }
2562a07aba5dSTimm Baeder 
2563a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2564a07aba5dSTimm Baeder // NarrowPtr, ExpandPtr
2565a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
2566a07aba5dSTimm Baeder 
2567a07aba5dSTimm Baeder inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2568a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2569a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Ptr.narrow());
2570a07aba5dSTimm Baeder   return true;
2571a07aba5dSTimm Baeder }
2572a07aba5dSTimm Baeder 
2573a07aba5dSTimm Baeder inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2574a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2575a07aba5dSTimm Baeder   S.Stk.push<Pointer>(Ptr.expand());
2576a07aba5dSTimm Baeder   return true;
2577a07aba5dSTimm Baeder }
2578a07aba5dSTimm Baeder 
2579a07aba5dSTimm Baeder // 1) Pops an integral value from the stack
2580a07aba5dSTimm Baeder // 2) Peeks a pointer
2581a07aba5dSTimm Baeder // 3) Pushes a new pointer that's a narrowed array
2582a07aba5dSTimm Baeder //   element of the peeked pointer with the value
2583a07aba5dSTimm Baeder //   from 1) added as offset.
2584a07aba5dSTimm Baeder //
2585a07aba5dSTimm Baeder // This leaves the original pointer on the stack and pushes a new one
2586a07aba5dSTimm Baeder // with the offset applied and narrowed.
2587a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2588a07aba5dSTimm Baeder inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2589a07aba5dSTimm Baeder   const T &Offset = S.Stk.pop<T>();
2590a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
2591a07aba5dSTimm Baeder 
2592a07aba5dSTimm Baeder   if (!Ptr.isZero() && !Offset.isZero()) {
2593a07aba5dSTimm Baeder     if (!CheckArray(S, OpPC, Ptr))
2594a07aba5dSTimm Baeder       return false;
2595a07aba5dSTimm Baeder   }
2596a07aba5dSTimm Baeder 
2597a07aba5dSTimm Baeder   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2598a07aba5dSTimm Baeder     return false;
2599a07aba5dSTimm Baeder 
2600a07aba5dSTimm Baeder   return NarrowPtr(S, OpPC);
2601a07aba5dSTimm Baeder }
2602a07aba5dSTimm Baeder 
2603a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2604a07aba5dSTimm Baeder inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2605a07aba5dSTimm Baeder   const T &Offset = S.Stk.pop<T>();
2606a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2607a07aba5dSTimm Baeder 
2608a07aba5dSTimm Baeder   if (!Ptr.isZero() && !Offset.isZero()) {
2609a07aba5dSTimm Baeder     if (!CheckArray(S, OpPC, Ptr))
2610a07aba5dSTimm Baeder       return false;
2611a07aba5dSTimm Baeder   }
2612a07aba5dSTimm Baeder 
2613a07aba5dSTimm Baeder   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2614a07aba5dSTimm Baeder     return false;
2615a07aba5dSTimm Baeder 
2616a07aba5dSTimm Baeder   return NarrowPtr(S, OpPC);
2617a07aba5dSTimm Baeder }
2618a07aba5dSTimm Baeder 
2619a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2620a07aba5dSTimm Baeder inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2621a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.peek<Pointer>();
2622a07aba5dSTimm Baeder 
2623a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr))
2624a07aba5dSTimm Baeder     return false;
2625a07aba5dSTimm Baeder 
2626e1365ce2STimm Baeder   assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2627a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2628a07aba5dSTimm Baeder   return true;
2629a07aba5dSTimm Baeder }
2630a07aba5dSTimm Baeder 
2631a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2632a07aba5dSTimm Baeder inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2633a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2634a07aba5dSTimm Baeder 
2635a07aba5dSTimm Baeder   if (!CheckLoad(S, OpPC, Ptr))
2636a07aba5dSTimm Baeder     return false;
2637a07aba5dSTimm Baeder 
2638e1365ce2STimm Baeder   assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2639a07aba5dSTimm Baeder   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2640a07aba5dSTimm Baeder   return true;
2641a07aba5dSTimm Baeder }
2642a07aba5dSTimm Baeder 
2643a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2644a07aba5dSTimm Baeder inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2645a07aba5dSTimm Baeder                       uint32_t DestIndex, uint32_t Size) {
2646a07aba5dSTimm Baeder   const auto &SrcPtr = S.Stk.pop<Pointer>();
2647a07aba5dSTimm Baeder   const auto &DestPtr = S.Stk.peek<Pointer>();
2648a07aba5dSTimm Baeder 
2649a07aba5dSTimm Baeder   for (uint32_t I = 0; I != Size; ++I) {
2650a07aba5dSTimm Baeder     const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2651a07aba5dSTimm Baeder 
2652a07aba5dSTimm Baeder     if (!CheckLoad(S, OpPC, SP))
2653a07aba5dSTimm Baeder       return false;
2654a07aba5dSTimm Baeder 
2655a07aba5dSTimm Baeder     const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2656a07aba5dSTimm Baeder     DP.deref<T>() = SP.deref<T>();
2657a07aba5dSTimm Baeder     DP.initialize();
2658a07aba5dSTimm Baeder   }
2659a07aba5dSTimm Baeder   return true;
2660a07aba5dSTimm Baeder }
2661a07aba5dSTimm Baeder 
2662a07aba5dSTimm Baeder /// Just takes a pointer and checks if it's an incomplete
2663a07aba5dSTimm Baeder /// array type.
2664a07aba5dSTimm Baeder inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2665a07aba5dSTimm Baeder   const Pointer &Ptr = S.Stk.pop<Pointer>();
2666a07aba5dSTimm Baeder 
2667a07aba5dSTimm Baeder   if (Ptr.isZero()) {
2668a07aba5dSTimm Baeder     S.Stk.push<Pointer>(Ptr);
2669a07aba5dSTimm Baeder     return true;
2670a07aba5dSTimm Baeder   }
2671a07aba5dSTimm Baeder 
2672a07aba5dSTimm Baeder   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2673a07aba5dSTimm Baeder     return false;
2674a07aba5dSTimm Baeder 
2675f7a74eceSTimm Baeder   if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
2676a07aba5dSTimm Baeder     S.Stk.push<Pointer>(Ptr.atIndex(0));
2677a07aba5dSTimm Baeder     return true;
2678a07aba5dSTimm Baeder   }
2679a07aba5dSTimm Baeder 
2680a07aba5dSTimm Baeder   const SourceInfo &E = S.Current->getSource(OpPC);
2681a07aba5dSTimm Baeder   S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2682a07aba5dSTimm Baeder 
2683a07aba5dSTimm Baeder   return false;
2684a07aba5dSTimm Baeder }
2685a07aba5dSTimm Baeder 
2686a07aba5dSTimm Baeder inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2687a07aba5dSTimm Baeder   assert(Func);
2688a07aba5dSTimm Baeder   S.Stk.push<FunctionPointer>(Func);
2689a07aba5dSTimm Baeder   return true;
2690a07aba5dSTimm Baeder }
2691a07aba5dSTimm Baeder 
2692a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2693a07aba5dSTimm Baeder inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2694a07aba5dSTimm Baeder   const T &IntVal = S.Stk.pop<T>();
2695a07aba5dSTimm Baeder 
2696*e8674af6STimm Baeder   if (Desc)
2697*e8674af6STimm Baeder     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
2698*e8674af6STimm Baeder         << 2 << S.getLangOpts().CPlusPlus;
2699*e8674af6STimm Baeder 
2700a07aba5dSTimm Baeder   S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2701a07aba5dSTimm Baeder   return true;
2702a07aba5dSTimm Baeder }
2703a07aba5dSTimm Baeder 
27046f81c878STimm Baeder inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
2705a07aba5dSTimm Baeder   S.Stk.push<MemberPointer>(D);
2706a07aba5dSTimm Baeder   return true;
2707a07aba5dSTimm Baeder }
2708a07aba5dSTimm Baeder 
2709a07aba5dSTimm Baeder inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2710a07aba5dSTimm Baeder   const auto &MP = S.Stk.pop<MemberPointer>();
2711a07aba5dSTimm Baeder 
2712a07aba5dSTimm Baeder   S.Stk.push<Pointer>(MP.getBase());
2713a07aba5dSTimm Baeder   return true;
2714a07aba5dSTimm Baeder }
2715a07aba5dSTimm Baeder 
2716a07aba5dSTimm Baeder inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2717a07aba5dSTimm Baeder   const auto &MP = S.Stk.pop<MemberPointer>();
2718a07aba5dSTimm Baeder 
2719a07aba5dSTimm Baeder   const auto *FD = cast<FunctionDecl>(MP.getDecl());
2720a07aba5dSTimm Baeder   const auto *Func = S.getContext().getOrCreateFunction(FD);
2721a07aba5dSTimm Baeder 
2722a07aba5dSTimm Baeder   S.Stk.push<FunctionPointer>(Func);
2723a07aba5dSTimm Baeder   return true;
2724a07aba5dSTimm Baeder }
2725a07aba5dSTimm Baeder 
2726a07aba5dSTimm Baeder /// Just emit a diagnostic. The expression that caused emission of this
2727a07aba5dSTimm Baeder /// op is not valid in a constant context.
2728a07aba5dSTimm Baeder inline bool Invalid(InterpState &S, CodePtr OpPC) {
2729a07aba5dSTimm Baeder   const SourceLocation &Loc = S.Current->getLocation(OpPC);
2730a07aba5dSTimm Baeder   S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2731a07aba5dSTimm Baeder       << S.Current->getRange(OpPC);
2732a07aba5dSTimm Baeder   return false;
2733a07aba5dSTimm Baeder }
2734a07aba5dSTimm Baeder 
2735a07aba5dSTimm Baeder inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2736a07aba5dSTimm Baeder   const SourceLocation &Loc = S.Current->getLocation(OpPC);
2737a07aba5dSTimm Baeder   S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2738a07aba5dSTimm Baeder       << S.Current->getRange(OpPC);
2739a07aba5dSTimm Baeder   return false;
2740a07aba5dSTimm Baeder }
2741a07aba5dSTimm Baeder 
2742a07aba5dSTimm Baeder /// Do nothing and just abort execution.
2743a07aba5dSTimm Baeder inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
274483fea8b8STimm Baeder inline bool SideEffect(InterpState &S, CodePtr OpPC) {
274583fea8b8STimm Baeder   return S.noteSideEffect();
274683fea8b8STimm Baeder }
2747a07aba5dSTimm Baeder 
2748a07aba5dSTimm Baeder /// Same here, but only for casts.
2749a07aba5dSTimm Baeder inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2750a07aba5dSTimm Baeder                         bool Fatal) {
2751a07aba5dSTimm Baeder   const SourceLocation &Loc = S.Current->getLocation(OpPC);
2752a07aba5dSTimm Baeder 
2753a07aba5dSTimm Baeder   // FIXME: Support diagnosing other invalid cast kinds.
2754a07aba5dSTimm Baeder   if (Kind == CastKind::Reinterpret) {
2755a07aba5dSTimm Baeder     S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2756a07aba5dSTimm Baeder         << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2757a07aba5dSTimm Baeder     return !Fatal;
2758a07aba5dSTimm Baeder   }
2759a07aba5dSTimm Baeder   return false;
2760a07aba5dSTimm Baeder }
2761a07aba5dSTimm Baeder 
2762159f2530STimm Baeder inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
2763159f2530STimm Baeder                            bool InitializerFailed) {
2764a07aba5dSTimm Baeder   assert(DR);
2765159f2530STimm Baeder 
2766159f2530STimm Baeder   if (InitializerFailed) {
2767159f2530STimm Baeder     const SourceInfo &Loc = S.Current->getSource(OpPC);
2768159f2530STimm Baeder     const auto *VD = cast<VarDecl>(DR->getDecl());
2769159f2530STimm Baeder     S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2770159f2530STimm Baeder     S.Note(VD->getLocation(), diag::note_declared_at);
2771159f2530STimm Baeder     return false;
2772159f2530STimm Baeder   }
2773159f2530STimm Baeder 
2774a07aba5dSTimm Baeder   return CheckDeclRef(S, OpPC, DR);
2775a07aba5dSTimm Baeder }
2776a07aba5dSTimm Baeder 
2777a07aba5dSTimm Baeder inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
2778a07aba5dSTimm Baeder   if (S.inConstantContext()) {
2779a07aba5dSTimm Baeder     const SourceRange &ArgRange = S.Current->getRange(OpPC);
2780a07aba5dSTimm Baeder     const Expr *E = S.Current->getExpr(OpPC);
2781a07aba5dSTimm Baeder     S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2782a07aba5dSTimm Baeder   }
2783a07aba5dSTimm Baeder   return false;
2784a07aba5dSTimm Baeder }
2785a07aba5dSTimm Baeder 
2786a07aba5dSTimm Baeder inline bool Assume(InterpState &S, CodePtr OpPC) {
2787a07aba5dSTimm Baeder   const auto Val = S.Stk.pop<Boolean>();
2788a07aba5dSTimm Baeder 
2789a07aba5dSTimm Baeder   if (Val)
2790a07aba5dSTimm Baeder     return true;
2791a07aba5dSTimm Baeder 
2792a07aba5dSTimm Baeder   // Else, diagnose.
2793a07aba5dSTimm Baeder   const SourceLocation &Loc = S.Current->getLocation(OpPC);
2794a07aba5dSTimm Baeder   S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2795a07aba5dSTimm Baeder   return false;
2796a07aba5dSTimm Baeder }
2797a07aba5dSTimm Baeder 
2798a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2799a07aba5dSTimm Baeder inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2800a07aba5dSTimm Baeder   llvm::SmallVector<int64_t> ArrayIndices;
2801a07aba5dSTimm Baeder   for (size_t I = 0; I != E->getNumExpressions(); ++I)
2802a07aba5dSTimm Baeder     ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2803a07aba5dSTimm Baeder 
2804a07aba5dSTimm Baeder   int64_t Result;
2805a07aba5dSTimm Baeder   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2806a07aba5dSTimm Baeder     return false;
2807a07aba5dSTimm Baeder 
2808a07aba5dSTimm Baeder   S.Stk.push<T>(T::from(Result));
2809a07aba5dSTimm Baeder 
2810a07aba5dSTimm Baeder   return true;
2811a07aba5dSTimm Baeder }
2812a07aba5dSTimm Baeder 
2813a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2814a07aba5dSTimm Baeder inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2815a07aba5dSTimm Baeder   const T &Arg = S.Stk.peek<T>();
2816a07aba5dSTimm Baeder   if (!Arg.isZero())
2817a07aba5dSTimm Baeder     return true;
2818a07aba5dSTimm Baeder 
2819a07aba5dSTimm Baeder   const SourceLocation &Loc = S.Current->getLocation(OpPC);
2820a07aba5dSTimm Baeder   S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2821a07aba5dSTimm Baeder 
2822a07aba5dSTimm Baeder   return false;
2823a07aba5dSTimm Baeder }
2824a07aba5dSTimm Baeder 
2825a07aba5dSTimm Baeder void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2826a07aba5dSTimm Baeder                        const APSInt &Value);
2827a07aba5dSTimm Baeder 
2828a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2829a07aba5dSTimm Baeder inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2830a07aba5dSTimm Baeder   assert(ED);
2831a07aba5dSTimm Baeder   assert(!ED->isFixed());
2832a07aba5dSTimm Baeder   const APSInt Val = S.Stk.peek<T>().toAPSInt();
2833a07aba5dSTimm Baeder 
2834a07aba5dSTimm Baeder   if (S.inConstantContext())
2835a07aba5dSTimm Baeder     diagnoseEnumValue(S, OpPC, ED, Val);
2836a07aba5dSTimm Baeder   return true;
2837a07aba5dSTimm Baeder }
2838a07aba5dSTimm Baeder 
2839a07aba5dSTimm Baeder /// OldPtr -> Integer -> NewPtr.
2840a07aba5dSTimm Baeder template <PrimType TIn, PrimType TOut>
2841a07aba5dSTimm Baeder inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2842a07aba5dSTimm Baeder   static_assert(isPtrType(TIn) && isPtrType(TOut));
2843a07aba5dSTimm Baeder   using FromT = typename PrimConv<TIn>::T;
2844a07aba5dSTimm Baeder   using ToT = typename PrimConv<TOut>::T;
2845a07aba5dSTimm Baeder 
2846a07aba5dSTimm Baeder   const FromT &OldPtr = S.Stk.pop<FromT>();
2847a07aba5dSTimm Baeder 
2848a07aba5dSTimm Baeder   if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2849a07aba5dSTimm Baeder                 std::is_same_v<ToT, Pointer>) {
2850db94852bSTimm Baeder     S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2851a07aba5dSTimm Baeder     return true;
2852db94852bSTimm Baeder   } else if constexpr (std::is_same_v<FromT, Pointer> &&
2853db94852bSTimm Baeder                        std::is_same_v<ToT, FunctionPointer>) {
2854db94852bSTimm Baeder     if (OldPtr.isFunctionPointer()) {
2855db94852bSTimm Baeder       S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2856db94852bSTimm Baeder                                   OldPtr.getByteOffset());
2857db94852bSTimm Baeder       return true;
2858db94852bSTimm Baeder     }
2859a07aba5dSTimm Baeder   }
2860a07aba5dSTimm Baeder 
2861a07aba5dSTimm Baeder   S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2862a07aba5dSTimm Baeder   return true;
2863a07aba5dSTimm Baeder }
2864a07aba5dSTimm Baeder 
2865a07aba5dSTimm Baeder inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2866a07aba5dSTimm Baeder   // An expression E is a core constant expression unless the evaluation of E
2867a07aba5dSTimm Baeder   // would evaluate one of the following: [C++23] - a control flow that passes
2868a07aba5dSTimm Baeder   // through a declaration of a variable with static or thread storage duration
2869a07aba5dSTimm Baeder   // unless that variable is usable in constant expressions.
2870a07aba5dSTimm Baeder   assert(VD->isLocalVarDecl() &&
2871a07aba5dSTimm Baeder          VD->isStaticLocal()); // Checked before emitting this.
2872a07aba5dSTimm Baeder 
2873a07aba5dSTimm Baeder   if (VD == S.EvaluatingDecl)
2874a07aba5dSTimm Baeder     return true;
2875a07aba5dSTimm Baeder 
2876d9e72860Syronglin   if (!VD->isUsableInConstantExpressions(S.getASTContext())) {
2877a07aba5dSTimm Baeder     S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2878a07aba5dSTimm Baeder         << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2879a07aba5dSTimm Baeder     return false;
2880a07aba5dSTimm Baeder   }
2881a07aba5dSTimm Baeder   return true;
2882a07aba5dSTimm Baeder }
2883a07aba5dSTimm Baeder 
2884a07aba5dSTimm Baeder inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2885a07aba5dSTimm Baeder   assert(Desc);
2886a07aba5dSTimm Baeder 
2887a07aba5dSTimm Baeder   if (!CheckDynamicMemoryAllocation(S, OpPC))
2888a07aba5dSTimm Baeder     return false;
2889a07aba5dSTimm Baeder 
2890a07aba5dSTimm Baeder   DynamicAllocator &Allocator = S.getAllocator();
2891610b8539STimm Baeder   Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2892610b8539STimm Baeder                                 DynamicAllocator::Form::NonArray);
2893a07aba5dSTimm Baeder   assert(B);
2894a07aba5dSTimm Baeder 
2895610b8539STimm Baeder   S.Stk.push<Pointer>(B);
2896a07aba5dSTimm Baeder 
2897a07aba5dSTimm Baeder   return true;
2898a07aba5dSTimm Baeder }
2899a07aba5dSTimm Baeder 
2900a07aba5dSTimm Baeder template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2901a07aba5dSTimm Baeder inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2902a07aba5dSTimm Baeder                    bool IsNoThrow) {
2903a07aba5dSTimm Baeder   if (!CheckDynamicMemoryAllocation(S, OpPC))
2904a07aba5dSTimm Baeder     return false;
2905a07aba5dSTimm Baeder 
2906a07aba5dSTimm Baeder   SizeT NumElements = S.Stk.pop<SizeT>();
2907a07aba5dSTimm Baeder   if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2908a07aba5dSTimm Baeder     if (!IsNoThrow)
2909a07aba5dSTimm Baeder       return false;
2910a07aba5dSTimm Baeder 
2911a07aba5dSTimm Baeder     // If this failed and is nothrow, just return a null ptr.
2912a07aba5dSTimm Baeder     S.Stk.push<Pointer>(0, nullptr);
2913a07aba5dSTimm Baeder     return true;
2914a07aba5dSTimm Baeder   }
2915a07aba5dSTimm Baeder 
2916a07aba5dSTimm Baeder   DynamicAllocator &Allocator = S.getAllocator();
2917610b8539STimm Baeder   Block *B =
2918610b8539STimm Baeder       Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2919610b8539STimm Baeder                          S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2920a07aba5dSTimm Baeder   assert(B);
2921a07aba5dSTimm Baeder   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2922a07aba5dSTimm Baeder 
2923a07aba5dSTimm Baeder   return true;
2924a07aba5dSTimm Baeder }
2925a07aba5dSTimm Baeder 
2926a07aba5dSTimm Baeder template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2927a07aba5dSTimm Baeder inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2928a07aba5dSTimm Baeder                     bool IsNoThrow) {
2929a07aba5dSTimm Baeder   if (!CheckDynamicMemoryAllocation(S, OpPC))
2930a07aba5dSTimm Baeder     return false;
2931a07aba5dSTimm Baeder 
2932a07aba5dSTimm Baeder   SizeT NumElements = S.Stk.pop<SizeT>();
2933a07aba5dSTimm Baeder   if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2934a07aba5dSTimm Baeder                       IsNoThrow)) {
2935a07aba5dSTimm Baeder     if (!IsNoThrow)
2936a07aba5dSTimm Baeder       return false;
2937a07aba5dSTimm Baeder 
2938a07aba5dSTimm Baeder     // If this failed and is nothrow, just return a null ptr.
2939a07aba5dSTimm Baeder     S.Stk.push<Pointer>(0, ElementDesc);
2940a07aba5dSTimm Baeder     return true;
2941a07aba5dSTimm Baeder   }
2942a07aba5dSTimm Baeder 
2943a07aba5dSTimm Baeder   DynamicAllocator &Allocator = S.getAllocator();
2944610b8539STimm Baeder   Block *B =
2945610b8539STimm Baeder       Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2946610b8539STimm Baeder                          S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2947a07aba5dSTimm Baeder   assert(B);
2948a07aba5dSTimm Baeder 
2949a07aba5dSTimm Baeder   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2950a07aba5dSTimm Baeder 
2951a07aba5dSTimm Baeder   return true;
2952a07aba5dSTimm Baeder }
2953a07aba5dSTimm Baeder 
2954f93258e4STimm Baeder bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
2955f93258e4STimm Baeder           bool IsGlobalDelete);
2956a07aba5dSTimm Baeder 
2957b9c4c4ccSTimm Baeder static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
2958b9c4c4ccSTimm Baeder   S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
2959b9c4c4ccSTimm Baeder   return true;
2960b9c4c4ccSTimm Baeder }
2961b9c4c4ccSTimm Baeder 
29623eaf4a9dSTimm Baeder static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
29633eaf4a9dSTimm Baeder   return S.maybeDiagnoseDanglingAllocations();
29643eaf4a9dSTimm Baeder }
29653eaf4a9dSTimm Baeder 
2966c712ab82STimm Baeder /// Check if the initializer and storage types of a placement-new expression
2967c712ab82STimm Baeder /// match.
2968c712ab82STimm Baeder bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
2969c712ab82STimm Baeder                           std::optional<uint64_t> ArraySize = std::nullopt);
2970c712ab82STimm Baeder 
2971c712ab82STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
2972c712ab82STimm Baeder bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
2973c712ab82STimm Baeder   const auto &Size = S.Stk.pop<T>();
2974c712ab82STimm Baeder   return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
2975c712ab82STimm Baeder }
2976c712ab82STimm Baeder bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
2977ef2a104cSTimm Baeder 
2978ef2a104cSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T>
297956fd46edSTimm Baeder inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
298056fd46edSTimm Baeder                         uint32_t ResultBitWidth,
298156fd46edSTimm Baeder                         const llvm::fltSemantics *Sem) {
2982ef2a104cSTimm Baeder   const Pointer &FromPtr = S.Stk.pop<Pointer>();
2983ef2a104cSTimm Baeder 
2984ef2a104cSTimm Baeder   if (!CheckLoad(S, OpPC, FromPtr))
2985ef2a104cSTimm Baeder     return false;
2986ef2a104cSTimm Baeder 
298756fd46edSTimm Baeder   if constexpr (std::is_same_v<T, Pointer>) {
298856fd46edSTimm Baeder     // The only pointer type we can validly bitcast to is nullptr_t.
298956fd46edSTimm Baeder     S.Stk.push<Pointer>();
299056fd46edSTimm Baeder     return true;
299156fd46edSTimm Baeder   } else {
299256fd46edSTimm Baeder 
2993ef2a104cSTimm Baeder     size_t BuffSize = ResultBitWidth / 8;
2994ef2a104cSTimm Baeder     llvm::SmallVector<std::byte> Buff(BuffSize);
2995ef2a104cSTimm Baeder     bool HasIndeterminateBits = false;
2996ef2a104cSTimm Baeder 
29971fbbf4c4STimm Baeder     Bits FullBitWidth(ResultBitWidth);
29981fbbf4c4STimm Baeder     Bits BitWidth = FullBitWidth;
29991fbbf4c4STimm Baeder 
30001fbbf4c4STimm Baeder     if constexpr (std::is_same_v<T, Floating>) {
30011fbbf4c4STimm Baeder       assert(Sem);
30021fbbf4c4STimm Baeder       BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
30031fbbf4c4STimm Baeder     }
30041fbbf4c4STimm Baeder 
30051fbbf4c4STimm Baeder     if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
30061fbbf4c4STimm Baeder                    HasIndeterminateBits))
3007ef2a104cSTimm Baeder       return false;
3008ef2a104cSTimm Baeder 
3009ef2a104cSTimm Baeder     if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3010ef2a104cSTimm Baeder       return false;
3011ef2a104cSTimm Baeder 
3012ef2a104cSTimm Baeder     if constexpr (std::is_same_v<T, Floating>) {
30135b32c595STimm Baeder       assert(Sem);
30141fbbf4c4STimm Baeder       S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3015ef2a104cSTimm Baeder     } else {
3016ef2a104cSTimm Baeder       assert(!Sem);
3017ef2a104cSTimm Baeder       S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3018ef2a104cSTimm Baeder     }
3019ef2a104cSTimm Baeder     return true;
3020ef2a104cSTimm Baeder   }
302156fd46edSTimm Baeder }
3022ef2a104cSTimm Baeder 
302356fd46edSTimm Baeder inline bool BitCast(InterpState &S, CodePtr OpPC) {
30242588b8beSTimm Baeder   const Pointer &FromPtr = S.Stk.pop<Pointer>();
30252588b8beSTimm Baeder   Pointer &ToPtr = S.Stk.peek<Pointer>();
30262588b8beSTimm Baeder 
30271425fa91STimm Baeder   if (!CheckLoad(S, OpPC, FromPtr))
30281425fa91STimm Baeder     return false;
30291425fa91STimm Baeder 
30302588b8beSTimm Baeder   if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
30312588b8beSTimm Baeder     return false;
30322588b8beSTimm Baeder 
30332588b8beSTimm Baeder   return true;
30342588b8beSTimm Baeder }
30352588b8beSTimm Baeder 
3036e86b68ffSTimm Baeder /// Typeid support.
3037e86b68ffSTimm Baeder bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3038e86b68ffSTimm Baeder                const Type *TypeInfoType);
3039e86b68ffSTimm Baeder bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3040e86b68ffSTimm Baeder bool DiagTypeid(InterpState &S, CodePtr OpPC);
3041e86b68ffSTimm Baeder 
3042a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
3043a07aba5dSTimm Baeder // Read opcode arguments
3044a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
3045a07aba5dSTimm Baeder 
3046a07aba5dSTimm Baeder template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3047a07aba5dSTimm Baeder   if constexpr (std::is_pointer<T>::value) {
3048a07aba5dSTimm Baeder     uint32_t ID = OpPC.read<uint32_t>();
3049a07aba5dSTimm Baeder     return reinterpret_cast<T>(S.P.getNativePointer(ID));
3050a07aba5dSTimm Baeder   } else {
3051a07aba5dSTimm Baeder     return OpPC.read<T>();
3052a07aba5dSTimm Baeder   }
3053a07aba5dSTimm Baeder }
3054a07aba5dSTimm Baeder 
3055a07aba5dSTimm Baeder template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3056a07aba5dSTimm Baeder   Floating F = Floating::deserialize(*OpPC);
3057a07aba5dSTimm Baeder   OpPC += align(F.bytesToSerialize());
3058a07aba5dSTimm Baeder   return F;
3059a07aba5dSTimm Baeder }
3060a07aba5dSTimm Baeder 
3061a07aba5dSTimm Baeder template <>
3062a07aba5dSTimm Baeder inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3063a07aba5dSTimm Baeder                                                     CodePtr &OpPC) {
3064a07aba5dSTimm Baeder   IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3065a07aba5dSTimm Baeder   OpPC += align(I.bytesToSerialize());
3066a07aba5dSTimm Baeder   return I;
3067a07aba5dSTimm Baeder }
3068a07aba5dSTimm Baeder 
3069a07aba5dSTimm Baeder template <>
3070a07aba5dSTimm Baeder inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3071a07aba5dSTimm Baeder                                                   CodePtr &OpPC) {
3072a07aba5dSTimm Baeder   IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3073a07aba5dSTimm Baeder   OpPC += align(I.bytesToSerialize());
3074a07aba5dSTimm Baeder   return I;
3075a07aba5dSTimm Baeder }
3076a07aba5dSTimm Baeder 
3077b5c9cba3STimm Baeder template <>
3078b5c9cba3STimm Baeder inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {
3079b5c9cba3STimm Baeder   FixedPoint FP = FixedPoint::deserialize(*OpPC);
3080b5c9cba3STimm Baeder   OpPC += align(FP.bytesToSerialize());
3081b5c9cba3STimm Baeder   return FP;
3082b5c9cba3STimm Baeder }
3083b5c9cba3STimm Baeder 
3084a07aba5dSTimm Baeder } // namespace interp
3085a07aba5dSTimm Baeder } // namespace clang
3086a07aba5dSTimm Baeder 
3087a07aba5dSTimm Baeder #endif
3088