xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Interp.h (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
1a7dea167SDimitry Andric //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Definition of the interpreter state and entry point.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERP_H
15a7dea167SDimitry Andric 
160fca6ea1SDimitry Andric #include "../ExprConstShared.h"
17bdd1243dSDimitry Andric #include "Boolean.h"
180fca6ea1SDimitry Andric #include "DynamicAllocator.h"
1906c3fb27SDimitry Andric #include "Floating.h"
20a7dea167SDimitry Andric #include "Function.h"
2106c3fb27SDimitry Andric #include "FunctionPointer.h"
22a7dea167SDimitry Andric #include "InterpFrame.h"
23a7dea167SDimitry Andric #include "InterpStack.h"
24a7dea167SDimitry Andric #include "InterpState.h"
250fca6ea1SDimitry Andric #include "MemberPointer.h"
26a7dea167SDimitry Andric #include "Opcode.h"
27a7dea167SDimitry Andric #include "PrimType.h"
28a7dea167SDimitry Andric #include "Program.h"
29a7dea167SDimitry Andric #include "State.h"
30a7dea167SDimitry Andric #include "clang/AST/ASTContext.h"
31a7dea167SDimitry Andric #include "clang/AST/Expr.h"
32a7dea167SDimitry Andric #include "llvm/ADT/APFloat.h"
33a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h"
34349cc55cSDimitry Andric #include <type_traits>
35a7dea167SDimitry Andric 
36a7dea167SDimitry Andric namespace clang {
37a7dea167SDimitry Andric namespace interp {
38a7dea167SDimitry Andric 
39a7dea167SDimitry Andric using APSInt = llvm::APSInt;
40a7dea167SDimitry Andric 
41349cc55cSDimitry Andric /// Convert a value to an APValue.
420fca6ea1SDimitry Andric template <typename T>
430fca6ea1SDimitry Andric bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
440fca6ea1SDimitry Andric   R = V.toAPValue(S.getCtx());
45a7dea167SDimitry Andric   return true;
46a7dea167SDimitry Andric }
47a7dea167SDimitry Andric 
48a7dea167SDimitry Andric /// Checks if the variable has externally defined storage.
49a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50a7dea167SDimitry Andric 
51a7dea167SDimitry Andric /// Checks if the array is offsetable.
52a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53a7dea167SDimitry Andric 
54349cc55cSDimitry Andric /// Checks if a pointer is live and accessible.
55a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56a7dea167SDimitry Andric                AccessKinds AK);
575f757f3fSDimitry Andric 
585f757f3fSDimitry Andric /// Checks if a pointer is a dummy pointer.
590fca6ea1SDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
600fca6ea1SDimitry Andric                 AccessKinds AK);
615f757f3fSDimitry Andric 
62a7dea167SDimitry Andric /// Checks if a pointer is null.
63a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64a7dea167SDimitry Andric                CheckSubobjectKind CSK);
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric /// Checks if a pointer is in range.
67a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68a7dea167SDimitry Andric                 AccessKinds AK);
69a7dea167SDimitry Andric 
70a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
71a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72a7dea167SDimitry Andric                 CheckSubobjectKind CSK);
73a7dea167SDimitry Andric 
745f757f3fSDimitry Andric /// Checks if Ptr is a one-past-the-end pointer.
755f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
765f757f3fSDimitry Andric                     CheckSubobjectKind CSK);
775f757f3fSDimitry Andric 
780fca6ea1SDimitry Andric /// Checks if the dowcast using the given offset is possible with the given
790fca6ea1SDimitry Andric /// pointer.
800fca6ea1SDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
810fca6ea1SDimitry Andric                    uint32_t Offset);
820fca6ea1SDimitry Andric 
83a7dea167SDimitry Andric /// Checks if a pointer points to const storage.
84a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85a7dea167SDimitry Andric 
867a6dacacSDimitry Andric /// Checks if the Descriptor is of a constexpr or const global variable.
877a6dacacSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
887a6dacacSDimitry Andric 
89a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field.
90a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
91a7dea167SDimitry Andric 
92a7dea167SDimitry Andric /// Checks if a value can be loaded from a block.
930fca6ea1SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
940fca6ea1SDimitry Andric                AccessKinds AK = AK_Read);
95a7dea167SDimitry Andric 
9606c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
9706c3fb27SDimitry Andric                       AccessKinds AK);
980fca6ea1SDimitry Andric /// Check if a global variable is initialized.
990fca6ea1SDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
10006c3fb27SDimitry Andric 
101a7dea167SDimitry Andric /// Checks if a value can be stored in a block.
102a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
103a7dea167SDimitry Andric 
104a7dea167SDimitry Andric /// Checks if a method can be invoked on an object.
105a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
106a7dea167SDimitry Andric 
107a7dea167SDimitry Andric /// Checks if a value can be initialized.
108a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
109a7dea167SDimitry Andric 
110a7dea167SDimitry Andric /// Checks if a method can be called.
111bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
112a7dea167SDimitry Andric 
11306c3fb27SDimitry Andric /// Checks if calling the currently active function would exceed
11406c3fb27SDimitry Andric /// the allowed call depth.
11506c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC);
11606c3fb27SDimitry Andric 
117a7dea167SDimitry Andric /// Checks the 'this' pointer.
118a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
119a7dea167SDimitry Andric 
120a7dea167SDimitry Andric /// Checks if a method is pure virtual.
121a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
122a7dea167SDimitry Andric 
1230fca6ea1SDimitry Andric /// Checks if all the arguments annotated as 'nonnull' are in fact not null.
1240fca6ea1SDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
1250fca6ea1SDimitry Andric                       const CallExpr *CE, unsigned ArgSize);
1260fca6ea1SDimitry Andric 
1270fca6ea1SDimitry Andric /// Checks if dynamic memory allocation is available in the current
1280fca6ea1SDimitry Andric /// language mode.
1290fca6ea1SDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
1300fca6ea1SDimitry Andric 
1310fca6ea1SDimitry Andric /// Diagnose mismatched new[]/delete or new/delete[] pairs.
1320fca6ea1SDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
1330fca6ea1SDimitry Andric                          bool DeleteIsArray, const Descriptor *D,
1340fca6ea1SDimitry Andric                          const Expr *NewExpr);
1350fca6ea1SDimitry Andric 
1360fca6ea1SDimitry Andric /// Check the source of the pointer passed to delete/delete[] has actually
1370fca6ea1SDimitry Andric /// been heap allocated by us.
1380fca6ea1SDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
1395f757f3fSDimitry Andric                        const Pointer &Ptr);
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric /// Sets the given integral value to the pointer, which is of
1425f757f3fSDimitry Andric /// a std::{weak,partial,strong}_ordering type.
1435f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
1445f757f3fSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue);
1455f757f3fSDimitry Andric 
1460fca6ea1SDimitry Andric /// Copy the contents of Src into Dest.
1470fca6ea1SDimitry Andric bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
1480fca6ea1SDimitry Andric 
149bdd1243dSDimitry Andric /// Checks if the shift operation is legal.
15006c3fb27SDimitry Andric template <typename LT, typename RT>
15106c3fb27SDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
15206c3fb27SDimitry Andric                 unsigned Bits) {
153bdd1243dSDimitry Andric   if (RHS.isNegative()) {
154bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
155bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
156*36b606aeSDimitry Andric     if (!S.noteUndefinedBehavior())
157bdd1243dSDimitry Andric       return false;
158bdd1243dSDimitry Andric   }
159bdd1243dSDimitry Andric 
160bdd1243dSDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
161bdd1243dSDimitry Andric   // the shifted type.
162bdd1243dSDimitry Andric   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
163bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
164bdd1243dSDimitry Andric     const APSInt Val = RHS.toAPSInt();
165bdd1243dSDimitry Andric     QualType Ty = E->getType();
166bdd1243dSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
167*36b606aeSDimitry Andric     if (!S.noteUndefinedBehavior())
168*36b606aeSDimitry Andric       return false;
169bdd1243dSDimitry Andric   }
17006c3fb27SDimitry Andric 
17106c3fb27SDimitry Andric   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
17206c3fb27SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
17306c3fb27SDimitry Andric     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
17406c3fb27SDimitry Andric     // operand, and must not overflow the corresponding unsigned type.
175*36b606aeSDimitry Andric     if (LHS.isNegative()) {
17606c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
177*36b606aeSDimitry Andric       if (!S.noteUndefinedBehavior())
178*36b606aeSDimitry Andric         return false;
179*36b606aeSDimitry Andric     } else if (LHS.toUnsigned().countLeadingZeros() <
180*36b606aeSDimitry Andric                static_cast<unsigned>(RHS)) {
18106c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
182*36b606aeSDimitry Andric       if (!S.noteUndefinedBehavior())
183*36b606aeSDimitry Andric         return false;
184*36b606aeSDimitry Andric     }
18506c3fb27SDimitry Andric   }
18606c3fb27SDimitry Andric 
18706c3fb27SDimitry Andric   // C++2a [expr.shift]p2: [P0907R4]:
18806c3fb27SDimitry Andric   //    E1 << E2 is the unique value congruent to
18906c3fb27SDimitry Andric   //    E1 x 2^E2 module 2^N.
190bdd1243dSDimitry Andric   return true;
191bdd1243dSDimitry Andric }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid.
194bdd1243dSDimitry Andric template <typename T>
195bdd1243dSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
196bdd1243dSDimitry Andric   if (RHS.isZero()) {
1975f757f3fSDimitry Andric     const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
1980fca6ea1SDimitry Andric     if constexpr (std::is_same_v<T, Floating>) {
1990fca6ea1SDimitry Andric       S.CCEDiag(Op, diag::note_expr_divide_by_zero)
2000fca6ea1SDimitry Andric           << Op->getRHS()->getSourceRange();
2010fca6ea1SDimitry Andric       return true;
2020fca6ea1SDimitry Andric     }
2030fca6ea1SDimitry Andric 
2045f757f3fSDimitry Andric     S.FFDiag(Op, diag::note_expr_divide_by_zero)
2055f757f3fSDimitry Andric         << Op->getRHS()->getSourceRange();
206bdd1243dSDimitry Andric     return false;
207bdd1243dSDimitry Andric   }
208bdd1243dSDimitry Andric 
209bdd1243dSDimitry Andric   if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
210bdd1243dSDimitry Andric     APSInt LHSInt = LHS.toAPSInt();
211bdd1243dSDimitry Andric     SmallString<32> Trunc;
212bdd1243dSDimitry Andric     (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
213bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
214bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
215bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
216bdd1243dSDimitry Andric     return false;
217bdd1243dSDimitry Andric   }
218bdd1243dSDimitry Andric   return true;
219bdd1243dSDimitry Andric }
220bdd1243dSDimitry Andric 
2210fca6ea1SDimitry Andric template <typename SizeT>
2220fca6ea1SDimitry Andric bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
2230fca6ea1SDimitry Andric                     unsigned ElemSize, bool IsNoThrow) {
2240fca6ea1SDimitry Andric   // FIXME: Both the SizeT::from() as well as the
2250fca6ea1SDimitry Andric   // NumElements.toAPSInt() in this function are rather expensive.
2260fca6ea1SDimitry Andric 
2270fca6ea1SDimitry Andric   // FIXME: GH63562
2280fca6ea1SDimitry Andric   // APValue stores array extents as unsigned,
2290fca6ea1SDimitry Andric   // so anything that is greater that unsigned would overflow when
2300fca6ea1SDimitry Andric   // constructing the array, we catch this here.
2310fca6ea1SDimitry Andric   SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
2320fca6ea1SDimitry Andric   if (NumElements->toAPSInt().getActiveBits() >
2330fca6ea1SDimitry Andric           ConstantArrayType::getMaxSizeBits(S.getCtx()) ||
2340fca6ea1SDimitry Andric       *NumElements > MaxElements) {
2350fca6ea1SDimitry Andric     if (!IsNoThrow) {
2360fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
2370fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_new_too_large)
2380fca6ea1SDimitry Andric           << NumElements->toDiagnosticString(S.getCtx());
2390fca6ea1SDimitry Andric     }
2400fca6ea1SDimitry Andric     return false;
2410fca6ea1SDimitry Andric   }
2420fca6ea1SDimitry Andric   return true;
2430fca6ea1SDimitry Andric }
2440fca6ea1SDimitry Andric 
2455f757f3fSDimitry Andric /// Checks if the result of a floating-point operation is valid
24606c3fb27SDimitry Andric /// in the current context.
2475f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
2485f757f3fSDimitry Andric                       APFloat::opStatus Status);
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric /// Checks why the given DeclRefExpr is invalid.
2515f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
25206c3fb27SDimitry Andric 
253bdd1243dSDimitry Andric /// Interpreter entry point.
254bdd1243dSDimitry Andric bool Interpret(InterpState &S, APValue &Result);
255a7dea167SDimitry Andric 
25606c3fb27SDimitry Andric /// Interpret a builtin function.
2575f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
2585f757f3fSDimitry Andric                       const CallExpr *Call);
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric /// Interpret an offsetof operation.
2615f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
2625f757f3fSDimitry Andric                        llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
26306c3fb27SDimitry Andric 
2640fca6ea1SDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC);
2650fca6ea1SDimitry Andric 
26606c3fb27SDimitry Andric enum class ArithOp { Add, Sub };
26706c3fb27SDimitry Andric 
26806c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
26906c3fb27SDimitry Andric // Returning values
27006c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
27106c3fb27SDimitry Andric 
2725f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
2735f757f3fSDimitry Andric 
2745f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
27506c3fb27SDimitry Andric bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
27606c3fb27SDimitry Andric   const T &Ret = S.Stk.pop<T>();
27706c3fb27SDimitry Andric 
2785f757f3fSDimitry Andric   // Make sure returned pointers are live. We might be trying to return a
2795f757f3fSDimitry Andric   // pointer or reference to a local variable.
2805f757f3fSDimitry Andric   // Just return false, since a diagnostic has already been emitted in Sema.
2815f757f3fSDimitry Andric   if constexpr (std::is_same_v<T, Pointer>) {
2825f757f3fSDimitry Andric     // FIXME: We could be calling isLive() here, but the emitted diagnostics
2835f757f3fSDimitry Andric     // seem a little weird, at least if the returned expression is of
2845f757f3fSDimitry Andric     // pointer type.
2855f757f3fSDimitry Andric     // Null pointers are considered live here.
2865f757f3fSDimitry Andric     if (!Ret.isZero() && !Ret.isLive())
2875f757f3fSDimitry Andric       return false;
2885f757f3fSDimitry Andric   }
2895f757f3fSDimitry Andric 
2905f757f3fSDimitry Andric   assert(S.Current);
29106c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
2925f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
2935f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
29406c3fb27SDimitry Andric 
29506c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
29606c3fb27SDimitry Andric     PC = S.Current->getRetPC();
29706c3fb27SDimitry Andric     delete S.Current;
29806c3fb27SDimitry Andric     S.Current = Caller;
29906c3fb27SDimitry Andric     S.Stk.push<T>(Ret);
30006c3fb27SDimitry Andric   } else {
30106c3fb27SDimitry Andric     delete S.Current;
30206c3fb27SDimitry Andric     S.Current = nullptr;
3030fca6ea1SDimitry Andric     if (!ReturnValue<T>(S, Ret, Result))
30406c3fb27SDimitry Andric       return false;
30506c3fb27SDimitry Andric   }
30606c3fb27SDimitry Andric   return true;
30706c3fb27SDimitry Andric }
30806c3fb27SDimitry Andric 
30906c3fb27SDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
31006c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
3115f757f3fSDimitry Andric 
3125f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
3135f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
31406c3fb27SDimitry Andric 
31506c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
31606c3fb27SDimitry Andric     PC = S.Current->getRetPC();
31706c3fb27SDimitry Andric     delete S.Current;
31806c3fb27SDimitry Andric     S.Current = Caller;
31906c3fb27SDimitry Andric   } else {
32006c3fb27SDimitry Andric     delete S.Current;
32106c3fb27SDimitry Andric     S.Current = nullptr;
32206c3fb27SDimitry Andric   }
32306c3fb27SDimitry Andric   return true;
32406c3fb27SDimitry Andric }
32506c3fb27SDimitry Andric 
326a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
327a7dea167SDimitry Andric // Add, Sub, Mul
328a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
329a7dea167SDimitry Andric 
330a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
331a7dea167SDimitry Andric           template <typename U> class OpAP>
332a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
333a7dea167SDimitry Andric                      const T &RHS) {
334a7dea167SDimitry Andric   // Fast path - add the numbers with fixed width.
335a7dea167SDimitry Andric   T Result;
336a7dea167SDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
337a7dea167SDimitry Andric     S.Stk.push<T>(Result);
338a7dea167SDimitry Andric     return true;
339a7dea167SDimitry Andric   }
340a7dea167SDimitry Andric 
341a7dea167SDimitry Andric   // If for some reason evaluation continues, use the truncated results.
342a7dea167SDimitry Andric   S.Stk.push<T>(Result);
343a7dea167SDimitry Andric 
344a7dea167SDimitry Andric   // Slow path - compute the result using another bit of precision.
345a7dea167SDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
346a7dea167SDimitry Andric 
347a7dea167SDimitry Andric   // Report undefined behaviour, stopping if required.
348a7dea167SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
349a7dea167SDimitry Andric   QualType Type = E->getType();
350a7dea167SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
351fe6060f1SDimitry Andric     SmallString<32> Trunc;
3520fca6ea1SDimitry Andric     Value.trunc(Result.bitWidth())
3530fca6ea1SDimitry Andric         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
3540fca6ea1SDimitry Andric                   /*UpperCase=*/true, /*InsertSeparators=*/true);
355a7dea167SDimitry Andric     auto Loc = E->getExprLoc();
3565f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
3575f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
3580fca6ea1SDimitry Andric   }
3590fca6ea1SDimitry Andric 
360a7dea167SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
3610fca6ea1SDimitry Andric 
3625f757f3fSDimitry Andric   if (!S.noteUndefinedBehavior()) {
3635f757f3fSDimitry Andric     S.Stk.pop<T>();
3645f757f3fSDimitry Andric     return false;
3655f757f3fSDimitry Andric   }
3660fca6ea1SDimitry Andric 
3675f757f3fSDimitry Andric   return true;
368a7dea167SDimitry Andric }
369a7dea167SDimitry Andric 
370a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
371a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
372a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
373a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
374a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
375a7dea167SDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
376a7dea167SDimitry Andric }
377a7dea167SDimitry Andric 
37806c3fb27SDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
37906c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
38006c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
38106c3fb27SDimitry Andric 
38206c3fb27SDimitry Andric   Floating Result;
38306c3fb27SDimitry Andric   auto Status = Floating::add(LHS, RHS, RM, &Result);
38406c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
3855f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
38606c3fb27SDimitry Andric }
38706c3fb27SDimitry Andric 
388a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
389a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
390a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
391a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
392a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
393a7dea167SDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
394a7dea167SDimitry Andric }
395a7dea167SDimitry Andric 
39606c3fb27SDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
39706c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
39806c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
39906c3fb27SDimitry Andric 
40006c3fb27SDimitry Andric   Floating Result;
40106c3fb27SDimitry Andric   auto Status = Floating::sub(LHS, RHS, RM, &Result);
40206c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
4035f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
40406c3fb27SDimitry Andric }
40506c3fb27SDimitry Andric 
406a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
407a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
408a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
409a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
410a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
411a7dea167SDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
412a7dea167SDimitry Andric }
413a7dea167SDimitry Andric 
41406c3fb27SDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
41506c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
41606c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
41706c3fb27SDimitry Andric 
41806c3fb27SDimitry Andric   Floating Result;
41906c3fb27SDimitry Andric   auto Status = Floating::mul(LHS, RHS, RM, &Result);
42006c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
4215f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
42206c3fb27SDimitry Andric }
4230fca6ea1SDimitry Andric 
4240fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
4250fca6ea1SDimitry Andric inline bool Mulc(InterpState &S, CodePtr OpPC) {
4260fca6ea1SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
4270fca6ea1SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
4280fca6ea1SDimitry Andric   const Pointer &Result = S.Stk.peek<Pointer>();
4290fca6ea1SDimitry Andric 
4300fca6ea1SDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
4310fca6ea1SDimitry Andric     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
4320fca6ea1SDimitry Andric     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
4330fca6ea1SDimitry Andric     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
4340fca6ea1SDimitry Andric     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
4350fca6ea1SDimitry Andric 
4360fca6ea1SDimitry Andric     APFloat ResR(A.getSemantics());
4370fca6ea1SDimitry Andric     APFloat ResI(A.getSemantics());
4380fca6ea1SDimitry Andric     HandleComplexComplexMul(A, B, C, D, ResR, ResI);
4390fca6ea1SDimitry Andric 
4400fca6ea1SDimitry Andric     // Copy into the result.
4410fca6ea1SDimitry Andric     Result.atIndex(0).deref<Floating>() = Floating(ResR);
4420fca6ea1SDimitry Andric     Result.atIndex(0).initialize();
4430fca6ea1SDimitry Andric     Result.atIndex(1).deref<Floating>() = Floating(ResI);
4440fca6ea1SDimitry Andric     Result.atIndex(1).initialize();
4450fca6ea1SDimitry Andric     Result.initialize();
4460fca6ea1SDimitry Andric   } else {
4470fca6ea1SDimitry Andric     // Integer element type.
4480fca6ea1SDimitry Andric     const T &LHSR = LHS.atIndex(0).deref<T>();
4490fca6ea1SDimitry Andric     const T &LHSI = LHS.atIndex(1).deref<T>();
4500fca6ea1SDimitry Andric     const T &RHSR = RHS.atIndex(0).deref<T>();
4510fca6ea1SDimitry Andric     const T &RHSI = RHS.atIndex(1).deref<T>();
4520fca6ea1SDimitry Andric     unsigned Bits = LHSR.bitWidth();
4530fca6ea1SDimitry Andric 
4540fca6ea1SDimitry Andric     // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
4550fca6ea1SDimitry Andric     T A;
4560fca6ea1SDimitry Andric     if (T::mul(LHSR, RHSR, Bits, &A))
4570fca6ea1SDimitry Andric       return false;
4580fca6ea1SDimitry Andric     T B;
4590fca6ea1SDimitry Andric     if (T::mul(LHSI, RHSI, Bits, &B))
4600fca6ea1SDimitry Andric       return false;
4610fca6ea1SDimitry Andric     if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
4620fca6ea1SDimitry Andric       return false;
4630fca6ea1SDimitry Andric     Result.atIndex(0).initialize();
4640fca6ea1SDimitry Andric 
4650fca6ea1SDimitry Andric     // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
4660fca6ea1SDimitry Andric     if (T::mul(LHSR, RHSI, Bits, &A))
4670fca6ea1SDimitry Andric       return false;
4680fca6ea1SDimitry Andric     if (T::mul(LHSI, RHSR, Bits, &B))
4690fca6ea1SDimitry Andric       return false;
4700fca6ea1SDimitry Andric     if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
4710fca6ea1SDimitry Andric       return false;
4720fca6ea1SDimitry Andric     Result.atIndex(1).initialize();
4730fca6ea1SDimitry Andric     Result.initialize();
4740fca6ea1SDimitry Andric   }
4750fca6ea1SDimitry Andric 
4760fca6ea1SDimitry Andric   return true;
4770fca6ea1SDimitry Andric }
4780fca6ea1SDimitry Andric 
4790fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
4800fca6ea1SDimitry Andric inline bool Divc(InterpState &S, CodePtr OpPC) {
4810fca6ea1SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
4820fca6ea1SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
4830fca6ea1SDimitry Andric   const Pointer &Result = S.Stk.peek<Pointer>();
4840fca6ea1SDimitry Andric 
4850fca6ea1SDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
4860fca6ea1SDimitry Andric     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
4870fca6ea1SDimitry Andric     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
4880fca6ea1SDimitry Andric     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
4890fca6ea1SDimitry Andric     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
4900fca6ea1SDimitry Andric 
4910fca6ea1SDimitry Andric     APFloat ResR(A.getSemantics());
4920fca6ea1SDimitry Andric     APFloat ResI(A.getSemantics());
4930fca6ea1SDimitry Andric     HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
4940fca6ea1SDimitry Andric 
4950fca6ea1SDimitry Andric     // Copy into the result.
4960fca6ea1SDimitry Andric     Result.atIndex(0).deref<Floating>() = Floating(ResR);
4970fca6ea1SDimitry Andric     Result.atIndex(0).initialize();
4980fca6ea1SDimitry Andric     Result.atIndex(1).deref<Floating>() = Floating(ResI);
4990fca6ea1SDimitry Andric     Result.atIndex(1).initialize();
5000fca6ea1SDimitry Andric     Result.initialize();
5010fca6ea1SDimitry Andric   } else {
5020fca6ea1SDimitry Andric     // Integer element type.
5030fca6ea1SDimitry Andric     const T &LHSR = LHS.atIndex(0).deref<T>();
5040fca6ea1SDimitry Andric     const T &LHSI = LHS.atIndex(1).deref<T>();
5050fca6ea1SDimitry Andric     const T &RHSR = RHS.atIndex(0).deref<T>();
5060fca6ea1SDimitry Andric     const T &RHSI = RHS.atIndex(1).deref<T>();
5070fca6ea1SDimitry Andric     unsigned Bits = LHSR.bitWidth();
5080fca6ea1SDimitry Andric     const T Zero = T::from(0, Bits);
5090fca6ea1SDimitry Andric 
5100fca6ea1SDimitry Andric     if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
5110fca6ea1SDimitry Andric         Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
5120fca6ea1SDimitry Andric       const SourceInfo &E = S.Current->getSource(OpPC);
5130fca6ea1SDimitry Andric       S.FFDiag(E, diag::note_expr_divide_by_zero);
5140fca6ea1SDimitry Andric       return false;
5150fca6ea1SDimitry Andric     }
5160fca6ea1SDimitry Andric 
5170fca6ea1SDimitry Andric     // Den = real(RHS)² + imag(RHS)²
5180fca6ea1SDimitry Andric     T A, B;
5190fca6ea1SDimitry Andric     if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
5200fca6ea1SDimitry Andric       return false;
5210fca6ea1SDimitry Andric     T Den;
5220fca6ea1SDimitry Andric     if (T::add(A, B, Bits, &Den))
5230fca6ea1SDimitry Andric       return false;
5240fca6ea1SDimitry Andric 
5250fca6ea1SDimitry Andric     // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
5260fca6ea1SDimitry Andric     T &ResultR = Result.atIndex(0).deref<T>();
5270fca6ea1SDimitry Andric     T &ResultI = Result.atIndex(1).deref<T>();
5280fca6ea1SDimitry Andric 
5290fca6ea1SDimitry Andric     if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
5300fca6ea1SDimitry Andric       return false;
5310fca6ea1SDimitry Andric     if (T::add(A, B, Bits, &ResultR))
5320fca6ea1SDimitry Andric       return false;
5330fca6ea1SDimitry Andric     if (T::div(ResultR, Den, Bits, &ResultR))
5340fca6ea1SDimitry Andric       return false;
5350fca6ea1SDimitry Andric     Result.atIndex(0).initialize();
5360fca6ea1SDimitry Andric 
5370fca6ea1SDimitry Andric     // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
5380fca6ea1SDimitry Andric     if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
5390fca6ea1SDimitry Andric       return false;
5400fca6ea1SDimitry Andric     if (T::sub(A, B, Bits, &ResultI))
5410fca6ea1SDimitry Andric       return false;
5420fca6ea1SDimitry Andric     if (T::div(ResultI, Den, Bits, &ResultI))
5430fca6ea1SDimitry Andric       return false;
5440fca6ea1SDimitry Andric     Result.atIndex(1).initialize();
5450fca6ea1SDimitry Andric     Result.initialize();
5460fca6ea1SDimitry Andric   }
5470fca6ea1SDimitry Andric 
5480fca6ea1SDimitry Andric   return true;
5490fca6ea1SDimitry Andric }
5500fca6ea1SDimitry Andric 
551bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
552bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
553bdd1243dSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack
554bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
555bdd1243dSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) {
556bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
557bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
558bdd1243dSDimitry Andric 
559bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
560bdd1243dSDimitry Andric   T Result;
561bdd1243dSDimitry Andric   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
562bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
563bdd1243dSDimitry Andric     return true;
564bdd1243dSDimitry Andric   }
565bdd1243dSDimitry Andric   return false;
566bdd1243dSDimitry Andric }
567bdd1243dSDimitry Andric 
568bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
569bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
570bdd1243dSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack
571bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
572bdd1243dSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) {
573bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
574bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
575bdd1243dSDimitry Andric 
576bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
577bdd1243dSDimitry Andric   T Result;
578bdd1243dSDimitry Andric   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
579bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
580bdd1243dSDimitry Andric     return true;
581bdd1243dSDimitry Andric   }
582bdd1243dSDimitry Andric   return false;
583bdd1243dSDimitry Andric }
584bdd1243dSDimitry Andric 
585bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
586bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
587bdd1243dSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack
588bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
589bdd1243dSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) {
590bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
591bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
592bdd1243dSDimitry Andric 
593bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
594bdd1243dSDimitry Andric   T Result;
595bdd1243dSDimitry Andric   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
596bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
597bdd1243dSDimitry Andric     return true;
598bdd1243dSDimitry Andric   }
599bdd1243dSDimitry Andric   return false;
600bdd1243dSDimitry Andric }
601bdd1243dSDimitry Andric 
602bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
603bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
604bdd1243dSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
605bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
606bdd1243dSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) {
607bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
608bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
609bdd1243dSDimitry Andric 
610bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
611bdd1243dSDimitry Andric     return false;
612bdd1243dSDimitry Andric 
613bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
614bdd1243dSDimitry Andric   T Result;
615bdd1243dSDimitry Andric   if (!T::rem(LHS, RHS, Bits, &Result)) {
616bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
617bdd1243dSDimitry Andric     return true;
618bdd1243dSDimitry Andric   }
619bdd1243dSDimitry Andric   return false;
620bdd1243dSDimitry Andric }
621bdd1243dSDimitry Andric 
622bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
623bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
624bdd1243dSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack
625bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
626bdd1243dSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) {
627bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
628bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
629bdd1243dSDimitry Andric 
630bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
631bdd1243dSDimitry Andric     return false;
632bdd1243dSDimitry Andric 
633bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
634bdd1243dSDimitry Andric   T Result;
635bdd1243dSDimitry Andric   if (!T::div(LHS, RHS, Bits, &Result)) {
636bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
637bdd1243dSDimitry Andric     return true;
638bdd1243dSDimitry Andric   }
639bdd1243dSDimitry Andric   return false;
640bdd1243dSDimitry Andric }
641bdd1243dSDimitry Andric 
64206c3fb27SDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
64306c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
64406c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
64506c3fb27SDimitry Andric 
64606c3fb27SDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
64706c3fb27SDimitry Andric     return false;
64806c3fb27SDimitry Andric 
64906c3fb27SDimitry Andric   Floating Result;
65006c3fb27SDimitry Andric   auto Status = Floating::div(LHS, RHS, RM, &Result);
65106c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
6525f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
65306c3fb27SDimitry Andric }
65406c3fb27SDimitry Andric 
655bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
656bdd1243dSDimitry Andric // Inv
657bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
658bdd1243dSDimitry Andric 
659bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
660bdd1243dSDimitry Andric bool Inv(InterpState &S, CodePtr OpPC) {
661bdd1243dSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
662bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
663bdd1243dSDimitry Andric   const unsigned Bits = Val.bitWidth();
664bdd1243dSDimitry Andric   Boolean R;
665bdd1243dSDimitry Andric   Boolean::inv(BoolT::from(Val, Bits), &R);
666bdd1243dSDimitry Andric 
667bdd1243dSDimitry Andric   S.Stk.push<BoolT>(R);
668bdd1243dSDimitry Andric   return true;
669bdd1243dSDimitry Andric }
670bdd1243dSDimitry Andric 
671bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
672bdd1243dSDimitry Andric // Neg
673bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
674bdd1243dSDimitry Andric 
675bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
676bdd1243dSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) {
67706c3fb27SDimitry Andric   const T &Value = S.Stk.pop<T>();
678bdd1243dSDimitry Andric   T Result;
679bdd1243dSDimitry Andric 
68006c3fb27SDimitry Andric   if (!T::neg(Value, &Result)) {
681bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
682bdd1243dSDimitry Andric     return true;
683bdd1243dSDimitry Andric   }
684bdd1243dSDimitry Andric 
68506c3fb27SDimitry Andric   assert(isIntegralType(Name) &&
68606c3fb27SDimitry Andric          "don't expect other types to fail at constexpr negation");
68706c3fb27SDimitry Andric   S.Stk.push<T>(Result);
68806c3fb27SDimitry Andric 
68906c3fb27SDimitry Andric   APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
69006c3fb27SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
69106c3fb27SDimitry Andric   QualType Type = E->getType();
69206c3fb27SDimitry Andric 
69306c3fb27SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
69406c3fb27SDimitry Andric     SmallString<32> Trunc;
6950fca6ea1SDimitry Andric     NegatedValue.trunc(Result.bitWidth())
6960fca6ea1SDimitry Andric         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
6970fca6ea1SDimitry Andric                   /*UpperCase=*/true, /*InsertSeparators=*/true);
69806c3fb27SDimitry Andric     auto Loc = E->getExprLoc();
6995f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
7005f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
70106c3fb27SDimitry Andric     return true;
70206c3fb27SDimitry Andric   }
70306c3fb27SDimitry Andric 
70406c3fb27SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
70506c3fb27SDimitry Andric   return S.noteUndefinedBehavior();
70606c3fb27SDimitry Andric }
70706c3fb27SDimitry Andric 
708bdd1243dSDimitry Andric enum class PushVal : bool {
709bdd1243dSDimitry Andric   No,
710bdd1243dSDimitry Andric   Yes,
711bdd1243dSDimitry Andric };
712bdd1243dSDimitry Andric enum class IncDecOp {
713bdd1243dSDimitry Andric   Inc,
714bdd1243dSDimitry Andric   Dec,
715bdd1243dSDimitry Andric };
716bdd1243dSDimitry Andric 
717bdd1243dSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush>
718bdd1243dSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
7190fca6ea1SDimitry Andric   assert(!Ptr.isDummy());
7200fca6ea1SDimitry Andric 
7210fca6ea1SDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
7220fca6ea1SDimitry Andric     if (!S.getLangOpts().CPlusPlus14)
7230fca6ea1SDimitry Andric       return Invalid(S, OpPC);
7240fca6ea1SDimitry Andric   }
7250fca6ea1SDimitry Andric 
7265f757f3fSDimitry Andric   const T &Value = Ptr.deref<T>();
727bdd1243dSDimitry Andric   T Result;
728bdd1243dSDimitry Andric 
729bdd1243dSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
73006c3fb27SDimitry Andric     S.Stk.push<T>(Value);
731bdd1243dSDimitry Andric 
732bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc) {
733bdd1243dSDimitry Andric     if (!T::increment(Value, &Result)) {
734bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
735bdd1243dSDimitry Andric       return true;
736bdd1243dSDimitry Andric     }
737bdd1243dSDimitry Andric   } else {
738bdd1243dSDimitry Andric     if (!T::decrement(Value, &Result)) {
739bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
740bdd1243dSDimitry Andric       return true;
741bdd1243dSDimitry Andric     }
742bdd1243dSDimitry Andric   }
743bdd1243dSDimitry Andric 
744bdd1243dSDimitry Andric   // Something went wrong with the previous operation. Compute the
745bdd1243dSDimitry Andric   // result with another bit of precision.
746bdd1243dSDimitry Andric   unsigned Bits = Value.bitWidth() + 1;
747bdd1243dSDimitry Andric   APSInt APResult;
748bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
749bdd1243dSDimitry Andric     APResult = ++Value.toAPSInt(Bits);
750bdd1243dSDimitry Andric   else
751bdd1243dSDimitry Andric     APResult = --Value.toAPSInt(Bits);
752bdd1243dSDimitry Andric 
753bdd1243dSDimitry Andric   // Report undefined behaviour, stopping if required.
754bdd1243dSDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
755bdd1243dSDimitry Andric   QualType Type = E->getType();
756bdd1243dSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
757bdd1243dSDimitry Andric     SmallString<32> Trunc;
7580fca6ea1SDimitry Andric     APResult.trunc(Result.bitWidth())
7590fca6ea1SDimitry Andric         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
7600fca6ea1SDimitry Andric                   /*UpperCase=*/true, /*InsertSeparators=*/true);
761bdd1243dSDimitry Andric     auto Loc = E->getExprLoc();
7625f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
7635f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
764bdd1243dSDimitry Andric     return true;
765bdd1243dSDimitry Andric   }
766bdd1243dSDimitry Andric 
767bdd1243dSDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
768bdd1243dSDimitry Andric   return S.noteUndefinedBehavior();
769bdd1243dSDimitry Andric }
770bdd1243dSDimitry Andric 
771bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
772bdd1243dSDimitry Andric /// 2) Load the value from the pointer
773bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
774bdd1243dSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack.
775bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
776bdd1243dSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC) {
777bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
7780fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
77906c3fb27SDimitry Andric     return false;
78006c3fb27SDimitry Andric 
781bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
782bdd1243dSDimitry Andric }
783bdd1243dSDimitry Andric 
784bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
785bdd1243dSDimitry Andric /// 2) Load the value from the pointer
786bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
787bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
788bdd1243dSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC) {
789bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
7900fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
79106c3fb27SDimitry Andric     return false;
79206c3fb27SDimitry Andric 
793bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
794bdd1243dSDimitry Andric }
795bdd1243dSDimitry Andric 
796bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
797bdd1243dSDimitry Andric /// 2) Load the value from the pointer
798bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
799bdd1243dSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack.
800bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
801bdd1243dSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC) {
802bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8030fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
80406c3fb27SDimitry Andric     return false;
80506c3fb27SDimitry Andric 
806bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
807bdd1243dSDimitry Andric }
808bdd1243dSDimitry Andric 
809bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
810bdd1243dSDimitry Andric /// 2) Load the value from the pointer
811bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
812bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
813bdd1243dSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC) {
814bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8150fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
81606c3fb27SDimitry Andric     return false;
81706c3fb27SDimitry Andric 
818bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
819bdd1243dSDimitry Andric }
820bdd1243dSDimitry Andric 
82106c3fb27SDimitry Andric template <IncDecOp Op, PushVal DoPush>
82206c3fb27SDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
82306c3fb27SDimitry Andric                        llvm::RoundingMode RM) {
82406c3fb27SDimitry Andric   Floating Value = Ptr.deref<Floating>();
82506c3fb27SDimitry Andric   Floating Result;
82606c3fb27SDimitry Andric 
82706c3fb27SDimitry Andric   if constexpr (DoPush == PushVal::Yes)
82806c3fb27SDimitry Andric     S.Stk.push<Floating>(Value);
82906c3fb27SDimitry Andric 
83006c3fb27SDimitry Andric   llvm::APFloat::opStatus Status;
83106c3fb27SDimitry Andric   if constexpr (Op == IncDecOp::Inc)
83206c3fb27SDimitry Andric     Status = Floating::increment(Value, RM, &Result);
83306c3fb27SDimitry Andric   else
83406c3fb27SDimitry Andric     Status = Floating::decrement(Value, RM, &Result);
83506c3fb27SDimitry Andric 
83606c3fb27SDimitry Andric   Ptr.deref<Floating>() = Result;
83706c3fb27SDimitry Andric 
8385f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
83906c3fb27SDimitry Andric }
84006c3fb27SDimitry Andric 
84106c3fb27SDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
84206c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8430fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
84406c3fb27SDimitry Andric     return false;
84506c3fb27SDimitry Andric 
84606c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
84706c3fb27SDimitry Andric }
84806c3fb27SDimitry Andric 
84906c3fb27SDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
85006c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8510fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
85206c3fb27SDimitry Andric     return false;
85306c3fb27SDimitry Andric 
85406c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
85506c3fb27SDimitry Andric }
85606c3fb27SDimitry Andric 
85706c3fb27SDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
85806c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8590fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
86006c3fb27SDimitry Andric     return false;
86106c3fb27SDimitry Andric 
86206c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
86306c3fb27SDimitry Andric }
86406c3fb27SDimitry Andric 
86506c3fb27SDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
86606c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
8670fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
86806c3fb27SDimitry Andric     return false;
86906c3fb27SDimitry Andric 
87006c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
87106c3fb27SDimitry Andric }
87206c3fb27SDimitry Andric 
873bdd1243dSDimitry Andric /// 1) Pops the value from the stack.
874bdd1243dSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V).
875bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
876bdd1243dSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) {
877bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
878bdd1243dSDimitry Andric   T Result;
879bdd1243dSDimitry Andric   if (!T::comp(Val, &Result)) {
880bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
881bdd1243dSDimitry Andric     return true;
882bdd1243dSDimitry Andric   }
883bdd1243dSDimitry Andric 
884bdd1243dSDimitry Andric   return false;
885bdd1243dSDimitry Andric }
886bdd1243dSDimitry Andric 
887a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
888a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE
889a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
890a7dea167SDimitry Andric 
891a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
892a7dea167SDimitry Andric 
893a7dea167SDimitry Andric template <typename T>
894a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
8950fca6ea1SDimitry Andric   assert((!std::is_same_v<T, MemberPointer>) &&
8960fca6ea1SDimitry Andric          "Non-equality comparisons on member pointer types should already be "
8970fca6ea1SDimitry Andric          "rejected in Sema.");
898a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
899a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
900a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
901a7dea167SDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
902a7dea167SDimitry Andric   return true;
903a7dea167SDimitry Andric }
904a7dea167SDimitry Andric 
905a7dea167SDimitry Andric template <typename T>
906a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
907a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
908a7dea167SDimitry Andric }
909a7dea167SDimitry Andric 
91006c3fb27SDimitry Andric /// Function pointers cannot be compared in an ordered way.
91106c3fb27SDimitry Andric template <>
91206c3fb27SDimitry Andric inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
91306c3fb27SDimitry Andric                                        CompareFn Fn) {
91406c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
91506c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
91606c3fb27SDimitry Andric 
91706c3fb27SDimitry Andric   const SourceInfo &Loc = S.Current->getSource(OpPC);
91806c3fb27SDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
91906c3fb27SDimitry Andric       << LHS.toDiagnosticString(S.getCtx())
92006c3fb27SDimitry Andric       << RHS.toDiagnosticString(S.getCtx());
92106c3fb27SDimitry Andric   return false;
92206c3fb27SDimitry Andric }
92306c3fb27SDimitry Andric 
92406c3fb27SDimitry Andric template <>
92506c3fb27SDimitry Andric inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
92606c3fb27SDimitry Andric                                          CompareFn Fn) {
92706c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
92806c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
9290fca6ea1SDimitry Andric 
9300fca6ea1SDimitry Andric   // We cannot compare against weak declarations at compile time.
9310fca6ea1SDimitry Andric   for (const auto &FP : {LHS, RHS}) {
9320fca6ea1SDimitry Andric     if (FP.isWeak()) {
9330fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
9340fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
9350fca6ea1SDimitry Andric           << FP.toDiagnosticString(S.getCtx());
9360fca6ea1SDimitry Andric       return false;
9370fca6ea1SDimitry Andric     }
9380fca6ea1SDimitry Andric   }
9390fca6ea1SDimitry Andric 
94006c3fb27SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
94106c3fb27SDimitry Andric   return true;
94206c3fb27SDimitry Andric }
94306c3fb27SDimitry Andric 
944a7dea167SDimitry Andric template <>
945a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
946a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
947a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
948a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
949a7dea167SDimitry Andric 
950a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
951a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
9525f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
9535f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
9545f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
955a7dea167SDimitry Andric     return false;
956a7dea167SDimitry Andric   } else {
957a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
958a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
959a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
960a7dea167SDimitry Andric     return true;
961a7dea167SDimitry Andric   }
962a7dea167SDimitry Andric }
963a7dea167SDimitry Andric 
964a7dea167SDimitry Andric template <>
965a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
966a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
967a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
968a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
969a7dea167SDimitry Andric 
970480093f4SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
971a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
972a7dea167SDimitry Andric     return true;
973a7dea167SDimitry Andric   }
974a7dea167SDimitry Andric 
9750fca6ea1SDimitry Andric   // Reject comparisons to weak pointers.
9760fca6ea1SDimitry Andric   for (const auto &P : {LHS, RHS}) {
9770fca6ea1SDimitry Andric     if (P.isZero())
9780fca6ea1SDimitry Andric       continue;
9790fca6ea1SDimitry Andric     if (P.isWeak()) {
9800fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
9810fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
9820fca6ea1SDimitry Andric           << P.toDiagnosticString(S.getCtx());
9830fca6ea1SDimitry Andric       return false;
9840fca6ea1SDimitry Andric     }
9850fca6ea1SDimitry Andric   }
9860fca6ea1SDimitry Andric 
987a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
9880fca6ea1SDimitry Andric     if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
9890fca6ea1SDimitry Andric         RHS.getOffset() == 0) {
9900fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
9910fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
9920fca6ea1SDimitry Andric           << LHS.toDiagnosticString(S.getCtx());
9930fca6ea1SDimitry Andric       return false;
9940fca6ea1SDimitry Andric     } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
9950fca6ea1SDimitry Andric                LHS.getOffset() == 0) {
9960fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
9970fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
9980fca6ea1SDimitry Andric           << RHS.toDiagnosticString(S.getCtx());
9990fca6ea1SDimitry Andric       return false;
10000fca6ea1SDimitry Andric     }
10010fca6ea1SDimitry Andric 
1002a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1003a7dea167SDimitry Andric     return true;
1004a7dea167SDimitry Andric   } else {
1005a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
1006a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
1007bdd1243dSDimitry Andric 
1008bdd1243dSDimitry Andric     // In our Pointer class, a pointer to an array and a pointer to the first
1009bdd1243dSDimitry Andric     // element in the same array are NOT equal. They have the same Base value,
1010bdd1243dSDimitry Andric     // but a different Offset. This is a pretty rare case, so we fix this here
1011bdd1243dSDimitry Andric     // by comparing pointers to the first elements.
10120fca6ea1SDimitry Andric     if (!LHS.isZero() && LHS.isArrayRoot())
1013bdd1243dSDimitry Andric       VL = LHS.atIndex(0).getByteOffset();
10140fca6ea1SDimitry Andric     if (!RHS.isZero() && RHS.isArrayRoot())
1015bdd1243dSDimitry Andric       VR = RHS.atIndex(0).getByteOffset();
1016bdd1243dSDimitry Andric 
1017a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1018a7dea167SDimitry Andric     return true;
1019a7dea167SDimitry Andric   }
1020a7dea167SDimitry Andric }
1021a7dea167SDimitry Andric 
10220fca6ea1SDimitry Andric template <>
10230fca6ea1SDimitry Andric inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
10240fca6ea1SDimitry Andric                                        CompareFn Fn) {
10250fca6ea1SDimitry Andric   const auto &RHS = S.Stk.pop<MemberPointer>();
10260fca6ea1SDimitry Andric   const auto &LHS = S.Stk.pop<MemberPointer>();
10270fca6ea1SDimitry Andric 
10280fca6ea1SDimitry Andric   // If either operand is a pointer to a weak function, the comparison is not
10290fca6ea1SDimitry Andric   // constant.
10300fca6ea1SDimitry Andric   for (const auto &MP : {LHS, RHS}) {
10310fca6ea1SDimitry Andric     if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
10320fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
10330fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
10340fca6ea1SDimitry Andric       return false;
10350fca6ea1SDimitry Andric     }
10360fca6ea1SDimitry Andric   }
10370fca6ea1SDimitry Andric 
10380fca6ea1SDimitry Andric   // C++11 [expr.eq]p2:
10390fca6ea1SDimitry Andric   //   If both operands are null, they compare equal. Otherwise if only one is
10400fca6ea1SDimitry Andric   //   null, they compare unequal.
10410fca6ea1SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
10420fca6ea1SDimitry Andric     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
10430fca6ea1SDimitry Andric     return true;
10440fca6ea1SDimitry Andric   }
10450fca6ea1SDimitry Andric   if (LHS.isZero() || RHS.isZero()) {
10460fca6ea1SDimitry Andric     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
10470fca6ea1SDimitry Andric     return true;
10480fca6ea1SDimitry Andric   }
10490fca6ea1SDimitry Andric 
10500fca6ea1SDimitry Andric   // We cannot compare against virtual declarations at compile time.
10510fca6ea1SDimitry Andric   for (const auto &MP : {LHS, RHS}) {
10520fca6ea1SDimitry Andric     if (const CXXMethodDecl *MD = MP.getMemberFunction();
10530fca6ea1SDimitry Andric         MD && MD->isVirtual()) {
10540fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
10550fca6ea1SDimitry Andric       S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
10560fca6ea1SDimitry Andric     }
10570fca6ea1SDimitry Andric   }
10580fca6ea1SDimitry Andric 
10590fca6ea1SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
10600fca6ea1SDimitry Andric   return true;
10610fca6ea1SDimitry Andric }
10620fca6ea1SDimitry Andric 
1063a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1064a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
1065a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1066a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Equal;
1067a7dea167SDimitry Andric   });
1068a7dea167SDimitry Andric }
1069a7dea167SDimitry Andric 
1070a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
10715f757f3fSDimitry Andric bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
10725f757f3fSDimitry Andric   const T &RHS = S.Stk.pop<T>();
10735f757f3fSDimitry Andric   const T &LHS = S.Stk.pop<T>();
10745f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
10755f757f3fSDimitry Andric 
10765f757f3fSDimitry Andric   ComparisonCategoryResult CmpResult = LHS.compare(RHS);
10775f757f3fSDimitry Andric   if (CmpResult == ComparisonCategoryResult::Unordered) {
10785f757f3fSDimitry Andric     // This should only happen with pointers.
10795f757f3fSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
10805f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
10815f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
10825f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
10835f757f3fSDimitry Andric     return false;
10845f757f3fSDimitry Andric   }
10855f757f3fSDimitry Andric 
10865f757f3fSDimitry Andric   assert(CmpInfo);
10870fca6ea1SDimitry Andric   const auto *CmpValueInfo =
10880fca6ea1SDimitry Andric       CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
10895f757f3fSDimitry Andric   assert(CmpValueInfo);
10905f757f3fSDimitry Andric   assert(CmpValueInfo->hasValidIntValue());
10910fca6ea1SDimitry Andric   return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
10925f757f3fSDimitry Andric }
10935f757f3fSDimitry Andric 
10945f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1095a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
1096a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1097a7dea167SDimitry Andric     return R != ComparisonCategoryResult::Equal;
1098a7dea167SDimitry Andric   });
1099a7dea167SDimitry Andric }
1100a7dea167SDimitry Andric 
1101a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1102a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
1103a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1104a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less;
1105a7dea167SDimitry Andric   });
1106a7dea167SDimitry Andric }
1107a7dea167SDimitry Andric 
1108a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1109a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
1110a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1111a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less ||
1112a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
1113a7dea167SDimitry Andric   });
1114a7dea167SDimitry Andric }
1115a7dea167SDimitry Andric 
1116a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1117a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
1118a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1119a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater;
1120a7dea167SDimitry Andric   });
1121a7dea167SDimitry Andric }
1122a7dea167SDimitry Andric 
1123a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1124a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
1125a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1126a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater ||
1127a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
1128a7dea167SDimitry Andric   });
1129a7dea167SDimitry Andric }
1130a7dea167SDimitry Andric 
1131a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1132a7dea167SDimitry Andric // InRange
1133a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1134a7dea167SDimitry Andric 
1135a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1136a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) {
1137a7dea167SDimitry Andric   const T RHS = S.Stk.pop<T>();
1138a7dea167SDimitry Andric   const T LHS = S.Stk.pop<T>();
1139a7dea167SDimitry Andric   const T Value = S.Stk.pop<T>();
1140a7dea167SDimitry Andric 
1141a7dea167SDimitry Andric   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1142a7dea167SDimitry Andric   return true;
1143a7dea167SDimitry Andric }
1144a7dea167SDimitry Andric 
1145a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1146a7dea167SDimitry Andric // Dup, Pop, Test
1147a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1148a7dea167SDimitry Andric 
1149a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1150a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
1151a7dea167SDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
1152a7dea167SDimitry Andric   return true;
1153a7dea167SDimitry Andric }
1154a7dea167SDimitry Andric 
1155a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1156a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
1157a7dea167SDimitry Andric   S.Stk.pop<T>();
1158a7dea167SDimitry Andric   return true;
1159a7dea167SDimitry Andric }
1160a7dea167SDimitry Andric 
1161a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1162a7dea167SDimitry Andric // Const
1163a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1164a7dea167SDimitry Andric 
1165a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1166a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1167a7dea167SDimitry Andric   S.Stk.push<T>(Arg);
1168a7dea167SDimitry Andric   return true;
1169a7dea167SDimitry Andric }
1170a7dea167SDimitry Andric 
1171a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1172a7dea167SDimitry Andric // Get/Set Local/Param/Global/This
1173a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1174a7dea167SDimitry Andric 
1175a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1176a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1177bdd1243dSDimitry Andric   const Pointer &Ptr = S.Current->getLocalPointer(I);
1178bdd1243dSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1179bdd1243dSDimitry Andric     return false;
1180bdd1243dSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1181a7dea167SDimitry Andric   return true;
1182a7dea167SDimitry Andric }
1183a7dea167SDimitry Andric 
118406c3fb27SDimitry Andric /// 1) Pops the value from the stack.
118506c3fb27SDimitry Andric /// 2) Writes the value to the local variable with the
118606c3fb27SDimitry Andric ///    given offset.
1187a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1188a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1189a7dea167SDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
1190a7dea167SDimitry Andric   return true;
1191a7dea167SDimitry Andric }
1192a7dea167SDimitry Andric 
1193a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1194a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1195a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1196a7dea167SDimitry Andric     return false;
1197a7dea167SDimitry Andric   }
1198a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
1199a7dea167SDimitry Andric   return true;
1200a7dea167SDimitry Andric }
1201a7dea167SDimitry Andric 
1202a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1203a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1204a7dea167SDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
1205a7dea167SDimitry Andric   return true;
1206a7dea167SDimitry Andric }
1207a7dea167SDimitry Andric 
1208bdd1243dSDimitry Andric /// 1) Peeks a pointer on the stack
1209bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
1210a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1211a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1212a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
1213a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1214a7dea167SDimitry Andric       return false;
1215a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1216a7dea167SDimitry Andric     return false;
1217a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
1218a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1219a7dea167SDimitry Andric     return false;
1220a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1221a7dea167SDimitry Andric   return true;
1222a7dea167SDimitry Andric }
1223a7dea167SDimitry Andric 
1224a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1225a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1226a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1227a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
1228a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1229a7dea167SDimitry Andric     return false;
1230a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1231a7dea167SDimitry Andric     return false;
1232a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
1233a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
1234a7dea167SDimitry Andric     return false;
123506c3fb27SDimitry Andric   Field.initialize();
1236a7dea167SDimitry Andric   Field.deref<T>() = Value;
1237a7dea167SDimitry Andric   return true;
1238a7dea167SDimitry Andric }
1239a7dea167SDimitry Andric 
1240bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
1241bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
1242a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1243a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1244a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
1245a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1246a7dea167SDimitry Andric     return false;
1247a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1248a7dea167SDimitry Andric     return false;
1249a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
1250a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1251a7dea167SDimitry Andric     return false;
1252a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1253a7dea167SDimitry Andric   return true;
1254a7dea167SDimitry Andric }
1255a7dea167SDimitry Andric 
1256a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1257a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1258a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1259a7dea167SDimitry Andric     return false;
1260a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1261a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1262a7dea167SDimitry Andric     return false;
1263a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1264a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1265a7dea167SDimitry Andric     return false;
1266a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1267a7dea167SDimitry Andric   return true;
1268a7dea167SDimitry Andric }
1269a7dea167SDimitry Andric 
1270a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1271a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1272a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1273a7dea167SDimitry Andric     return false;
1274a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1275a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1276a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1277a7dea167SDimitry Andric     return false;
1278a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1279a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
1280a7dea167SDimitry Andric     return false;
1281a7dea167SDimitry Andric   Field.deref<T>() = Value;
1282a7dea167SDimitry Andric   return true;
1283a7dea167SDimitry Andric }
1284a7dea167SDimitry Andric 
1285a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1286a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
12870fca6ea1SDimitry Andric   const Pointer &Ptr = S.P.getPtrGlobal(I);
12880fca6ea1SDimitry Andric   if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
12890fca6ea1SDimitry Andric     return false;
12900fca6ea1SDimitry Andric   if (Ptr.isExtern())
12910fca6ea1SDimitry Andric     return false;
12927a6dacacSDimitry Andric 
12930fca6ea1SDimitry Andric   // If a global variable is uninitialized, that means the initializer we've
12940fca6ea1SDimitry Andric   // compiled for it wasn't a constant expression. Diagnose that.
12950fca6ea1SDimitry Andric   if (!CheckGlobalInitialized(S, OpPC, Ptr))
12967a6dacacSDimitry Andric     return false;
12970fca6ea1SDimitry Andric 
12980fca6ea1SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1299a7dea167SDimitry Andric   return true;
1300a7dea167SDimitry Andric }
1301a7dea167SDimitry Andric 
13027a6dacacSDimitry Andric /// Same as GetGlobal, but without the checks.
13037a6dacacSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
13047a6dacacSDimitry Andric bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
13050fca6ea1SDimitry Andric   const Pointer &Ptr = S.P.getPtrGlobal(I);
13060fca6ea1SDimitry Andric   if (!Ptr.isInitialized())
13070fca6ea1SDimitry Andric     return false;
13080fca6ea1SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
13097a6dacacSDimitry Andric   return true;
13107a6dacacSDimitry Andric }
13117a6dacacSDimitry Andric 
1312a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1313a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1314a7dea167SDimitry Andric   // TODO: emit warning.
1315a7dea167SDimitry Andric   return false;
1316a7dea167SDimitry Andric }
1317a7dea167SDimitry Andric 
1318a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1319a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
13200fca6ea1SDimitry Andric   const Pointer &P = S.P.getGlobal(I);
13210fca6ea1SDimitry Andric   P.deref<T>() = S.Stk.pop<T>();
13220fca6ea1SDimitry Andric   P.initialize();
1323a7dea167SDimitry Andric   return true;
1324a7dea167SDimitry Andric }
1325a7dea167SDimitry Andric 
132606c3fb27SDimitry Andric /// 1) Converts the value on top of the stack to an APValue
132706c3fb27SDimitry Andric /// 2) Sets that APValue on \Temp
13280fca6ea1SDimitry Andric /// 3) Initializes global with index \I with that
132906c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
133006c3fb27SDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
133106c3fb27SDimitry Andric                     const LifetimeExtendedTemporaryDecl *Temp) {
13320fca6ea1SDimitry Andric   const Pointer &Ptr = S.P.getGlobal(I);
13330fca6ea1SDimitry Andric 
133406c3fb27SDimitry Andric   const T Value = S.Stk.peek<T>();
13350fca6ea1SDimitry Andric   APValue APV = Value.toAPValue(S.getCtx());
133606c3fb27SDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
133706c3fb27SDimitry Andric   *Cached = APV;
133806c3fb27SDimitry Andric 
13390fca6ea1SDimitry Andric   assert(Ptr.getDeclDesc()->asExpr());
13400fca6ea1SDimitry Andric 
13410fca6ea1SDimitry Andric   S.SeenGlobalTemporaries.push_back(
13420fca6ea1SDimitry Andric       std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
13430fca6ea1SDimitry Andric 
13440fca6ea1SDimitry Andric   Ptr.deref<T>() = S.Stk.pop<T>();
13450fca6ea1SDimitry Andric   Ptr.initialize();
134606c3fb27SDimitry Andric   return true;
134706c3fb27SDimitry Andric }
134806c3fb27SDimitry Andric 
13495f757f3fSDimitry Andric /// 1) Converts the value on top of the stack to an APValue
13505f757f3fSDimitry Andric /// 2) Sets that APValue on \Temp
13515f757f3fSDimitry Andric /// 3) Initialized global with index \I with that
13525f757f3fSDimitry Andric inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
13535f757f3fSDimitry Andric                                const LifetimeExtendedTemporaryDecl *Temp) {
13545f757f3fSDimitry Andric   assert(Temp);
13555f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
13565f757f3fSDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
13575f757f3fSDimitry Andric 
13580fca6ea1SDimitry Andric   S.SeenGlobalTemporaries.push_back(
13590fca6ea1SDimitry Andric       std::make_pair(P.getDeclDesc()->asExpr(), Temp));
13600fca6ea1SDimitry Andric 
13610fca6ea1SDimitry Andric   if (std::optional<APValue> APV =
13620fca6ea1SDimitry Andric           P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
13637a6dacacSDimitry Andric     *Cached = *APV;
13645f757f3fSDimitry Andric     return true;
13655f757f3fSDimitry Andric   }
13665f757f3fSDimitry Andric 
13677a6dacacSDimitry Andric   return false;
13687a6dacacSDimitry Andric }
13697a6dacacSDimitry Andric 
1370a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1371a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1372a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1373a7dea167SDimitry Andric     return false;
1374a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1375a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1376a7dea167SDimitry Andric     return false;
1377a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1378a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1379a7dea167SDimitry Andric   Field.initialize();
1380a7dea167SDimitry Andric   return true;
1381a7dea167SDimitry Andric }
1382a7dea167SDimitry Andric 
13837a6dacacSDimitry Andric // FIXME: The Field pointer here is too much IMO and we could instead just
13847a6dacacSDimitry Andric // pass an Offset + BitWidth pair.
1385a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
13867a6dacacSDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
13877a6dacacSDimitry Andric                       uint32_t FieldOffset) {
13885f757f3fSDimitry Andric   assert(F->isBitField());
1389a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1390a7dea167SDimitry Andric     return false;
1391a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1392a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1393a7dea167SDimitry Andric     return false;
13947a6dacacSDimitry Andric   const Pointer &Field = This.atField(FieldOffset);
1395a7dea167SDimitry Andric   const auto &Value = S.Stk.pop<T>();
1396a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1397a7dea167SDimitry Andric   Field.initialize();
1398a7dea167SDimitry Andric   return true;
1399a7dea167SDimitry Andric }
1400a7dea167SDimitry Andric 
1401a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1402a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1403a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1404a7dea167SDimitry Andric     return false;
1405a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1406a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1407a7dea167SDimitry Andric     return false;
1408a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1409a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1410a7dea167SDimitry Andric   Field.activate();
1411a7dea167SDimitry Andric   Field.initialize();
1412a7dea167SDimitry Andric   return true;
1413a7dea167SDimitry Andric }
1414a7dea167SDimitry Andric 
1415bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1416bdd1243dSDimitry Andric /// 2) Peeks a pointer from the stack
1417bdd1243dSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack
1418a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1419a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1420a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1421bdd1243dSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1422a7dea167SDimitry Andric   Field.deref<T>() = Value;
1423a7dea167SDimitry Andric   Field.activate();
1424a7dea167SDimitry Andric   Field.initialize();
1425a7dea167SDimitry Andric   return true;
1426a7dea167SDimitry Andric }
1427a7dea167SDimitry Andric 
1428a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1429a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
14305f757f3fSDimitry Andric   assert(F->isBitField());
1431a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
14325f757f3fSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1433a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1434a7dea167SDimitry Andric   Field.activate();
1435a7dea167SDimitry Andric   Field.initialize();
1436a7dea167SDimitry Andric   return true;
1437a7dea167SDimitry Andric }
1438a7dea167SDimitry Andric 
1439a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1440a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1441a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1442a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1443a7dea167SDimitry Andric   const Pointer &Field = Ptr.atField(I);
1444a7dea167SDimitry Andric   Field.deref<T>() = Value;
1445a7dea167SDimitry Andric   Field.activate();
1446a7dea167SDimitry Andric   Field.initialize();
1447a7dea167SDimitry Andric   return true;
1448a7dea167SDimitry Andric }
1449a7dea167SDimitry Andric 
1450a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1451a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This
1452a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1453a7dea167SDimitry Andric 
1454a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1455a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1456a7dea167SDimitry Andric   return true;
1457a7dea167SDimitry Andric }
1458a7dea167SDimitry Andric 
1459a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1460a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1461a7dea167SDimitry Andric     return false;
1462a7dea167SDimitry Andric   }
1463a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1464a7dea167SDimitry Andric   return true;
1465a7dea167SDimitry Andric }
1466a7dea167SDimitry Andric 
1467a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1468a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1469a7dea167SDimitry Andric   return true;
1470a7dea167SDimitry Andric }
1471a7dea167SDimitry Andric 
14720fca6ea1SDimitry Andric /// 1) Peeks a Pointer
1473bdd1243dSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack
1474a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
14750fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
14760fca6ea1SDimitry Andric 
14770fca6ea1SDimitry Andric   if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
14780fca6ea1SDimitry Andric       !CheckNull(S, OpPC, Ptr, CSK_Field))
1479a7dea167SDimitry Andric     return false;
14800fca6ea1SDimitry Andric 
1481a7dea167SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
1482a7dea167SDimitry Andric     return false;
1483a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1484a7dea167SDimitry Andric     return false;
14850fca6ea1SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
14860fca6ea1SDimitry Andric     return false;
14875f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
14885f757f3fSDimitry Andric     return false;
14895f757f3fSDimitry Andric 
14900fca6ea1SDimitry Andric   if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
14910fca6ea1SDimitry Andric     return false;
14920fca6ea1SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
14930fca6ea1SDimitry Andric   return true;
14940fca6ea1SDimitry Andric }
14950fca6ea1SDimitry Andric 
14960fca6ea1SDimitry Andric inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
14970fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
14980fca6ea1SDimitry Andric 
14990fca6ea1SDimitry Andric   if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
15000fca6ea1SDimitry Andric       !CheckNull(S, OpPC, Ptr, CSK_Field))
15010fca6ea1SDimitry Andric     return false;
15020fca6ea1SDimitry Andric 
15030fca6ea1SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
15040fca6ea1SDimitry Andric     return false;
15050fca6ea1SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
15060fca6ea1SDimitry Andric     return false;
15070fca6ea1SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
15080fca6ea1SDimitry Andric     return false;
15090fca6ea1SDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
15100fca6ea1SDimitry Andric     return false;
15110fca6ea1SDimitry Andric 
15120fca6ea1SDimitry Andric   if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
15130fca6ea1SDimitry Andric     return false;
15140fca6ea1SDimitry Andric 
1515a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1516a7dea167SDimitry Andric   return true;
1517a7dea167SDimitry Andric }
1518a7dea167SDimitry Andric 
1519a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1520a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1521a7dea167SDimitry Andric     return false;
1522a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1523a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1524a7dea167SDimitry Andric     return false;
1525a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1526a7dea167SDimitry Andric   return true;
1527a7dea167SDimitry Andric }
1528a7dea167SDimitry Andric 
1529a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1530a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1531a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1532a7dea167SDimitry Andric     return false;
1533a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1534a7dea167SDimitry Andric     return false;
1535a7dea167SDimitry Andric   Pointer Field = Ptr.atField(Off);
1536a7dea167SDimitry Andric   Ptr.deactivate();
1537a7dea167SDimitry Andric   Field.activate();
1538a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1539a7dea167SDimitry Andric   return true;
1540a7dea167SDimitry Andric }
1541a7dea167SDimitry Andric 
1542a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1543a7dea167SDimitry Andric  if (S.checkingPotentialConstantExpression())
1544a7dea167SDimitry Andric     return false;
1545a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1546a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1547a7dea167SDimitry Andric     return false;
1548a7dea167SDimitry Andric   Pointer Field = This.atField(Off);
1549a7dea167SDimitry Andric   This.deactivate();
1550a7dea167SDimitry Andric   Field.activate();
1551a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1552a7dea167SDimitry Andric   return true;
1553a7dea167SDimitry Andric }
1554a7dea167SDimitry Andric 
15555f757f3fSDimitry Andric inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
15565f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
15575f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
15585f757f3fSDimitry Andric     return false;
15595f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
15605f757f3fSDimitry Andric     return false;
15610fca6ea1SDimitry Andric   if (!CheckDowncast(S, OpPC, Ptr, Off))
15620fca6ea1SDimitry Andric     return false;
15630fca6ea1SDimitry Andric 
15645f757f3fSDimitry Andric   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
15655f757f3fSDimitry Andric   return true;
15665f757f3fSDimitry Andric }
15675f757f3fSDimitry Andric 
1568a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
156906c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
157006c3fb27SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
157106c3fb27SDimitry Andric     return false;
15725f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
15735f757f3fSDimitry Andric     return false;
157406c3fb27SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
157506c3fb27SDimitry Andric   return true;
157606c3fb27SDimitry Andric }
157706c3fb27SDimitry Andric 
157806c3fb27SDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1579a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1580a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1581a7dea167SDimitry Andric     return false;
15825f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
15835f757f3fSDimitry Andric     return false;
1584a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1585a7dea167SDimitry Andric   return true;
1586a7dea167SDimitry Andric }
1587a7dea167SDimitry Andric 
15880fca6ea1SDimitry Andric inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
15890fca6ea1SDimitry Andric   const auto &Ptr = S.Stk.pop<MemberPointer>();
15900fca6ea1SDimitry Andric   S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
15910fca6ea1SDimitry Andric   return true;
15920fca6ea1SDimitry Andric }
15930fca6ea1SDimitry Andric 
1594a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1595a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1596a7dea167SDimitry Andric     return false;
1597a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1598a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1599a7dea167SDimitry Andric     return false;
1600a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1601a7dea167SDimitry Andric   return true;
1602a7dea167SDimitry Andric }
1603a7dea167SDimitry Andric 
16040fca6ea1SDimitry Andric inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
16055f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
16060fca6ea1SDimitry Andric   if (Ptr.canBeInitialized()) {
16075f757f3fSDimitry Andric     Ptr.initialize();
16080fca6ea1SDimitry Andric     Ptr.activate();
16090fca6ea1SDimitry Andric   }
16100fca6ea1SDimitry Andric   return true;
16110fca6ea1SDimitry Andric }
16120fca6ea1SDimitry Andric 
16130fca6ea1SDimitry Andric inline bool FinishInit(InterpState &S, CodePtr OpPC) {
16140fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
16150fca6ea1SDimitry Andric   if (Ptr.canBeInitialized()) {
16160fca6ea1SDimitry Andric     Ptr.initialize();
16170fca6ea1SDimitry Andric     Ptr.activate();
16180fca6ea1SDimitry Andric   }
16190fca6ea1SDimitry Andric   return true;
16200fca6ea1SDimitry Andric }
16210fca6ea1SDimitry Andric 
16220fca6ea1SDimitry Andric inline bool Dump(InterpState &S, CodePtr OpPC) {
16230fca6ea1SDimitry Andric   S.Stk.dump();
16245f757f3fSDimitry Andric   return true;
16255f757f3fSDimitry Andric }
16265f757f3fSDimitry Andric 
1627a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1628a7dea167SDimitry Andric                            const Pointer &Ptr) {
1629a7dea167SDimitry Andric   Pointer Base = Ptr;
1630a7dea167SDimitry Andric   while (Base.isBaseClass())
1631a7dea167SDimitry Andric     Base = Base.getBase();
1632a7dea167SDimitry Andric 
16330fca6ea1SDimitry Andric   const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
16340fca6ea1SDimitry Andric   S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1635a7dea167SDimitry Andric   return true;
1636a7dea167SDimitry Andric }
1637a7dea167SDimitry Andric 
16380fca6ea1SDimitry Andric inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
16390fca6ea1SDimitry Andric                               const RecordDecl *D) {
16400fca6ea1SDimitry Andric   assert(D);
1641a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1642a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1643a7dea167SDimitry Andric     return false;
1644a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
1645a7dea167SDimitry Andric }
1646a7dea167SDimitry Andric 
1647a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1648a7dea167SDimitry Andric                                const RecordDecl *D) {
16490fca6ea1SDimitry Andric   assert(D);
1650a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1651a7dea167SDimitry Andric     return false;
1652a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1653a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1654a7dea167SDimitry Andric     return false;
1655a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1656a7dea167SDimitry Andric }
1657a7dea167SDimitry Andric 
1658a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1659a7dea167SDimitry Andric // Load, Store, Init
1660a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1661a7dea167SDimitry Andric 
1662a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1663a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
1664a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1665a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1666a7dea167SDimitry Andric     return false;
16670fca6ea1SDimitry Andric   if (!Ptr.isBlockPointer())
16680fca6ea1SDimitry Andric     return false;
1669a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1670a7dea167SDimitry Andric   return true;
1671a7dea167SDimitry Andric }
1672a7dea167SDimitry Andric 
1673a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1674a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
1675a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1676a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1677a7dea167SDimitry Andric     return false;
16780fca6ea1SDimitry Andric   if (!Ptr.isBlockPointer())
16790fca6ea1SDimitry Andric     return false;
1680a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1681a7dea167SDimitry Andric   return true;
1682a7dea167SDimitry Andric }
1683a7dea167SDimitry Andric 
1684a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1685a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
1686a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1687a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1688a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1689a7dea167SDimitry Andric     return false;
16900fca6ea1SDimitry Andric   if (Ptr.canBeInitialized())
1691bdd1243dSDimitry Andric     Ptr.initialize();
1692a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1693a7dea167SDimitry Andric   return true;
1694a7dea167SDimitry Andric }
1695a7dea167SDimitry Andric 
1696a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1697a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
1698a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1699a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1700a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1701a7dea167SDimitry Andric     return false;
17020fca6ea1SDimitry Andric   if (Ptr.canBeInitialized())
1703bdd1243dSDimitry Andric     Ptr.initialize();
1704a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1705a7dea167SDimitry Andric   return true;
1706a7dea167SDimitry Andric }
1707a7dea167SDimitry Andric 
1708a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1709a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
1710a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1711a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1712a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1713a7dea167SDimitry Andric     return false;
17140fca6ea1SDimitry Andric   if (Ptr.canBeInitialized())
1715bdd1243dSDimitry Andric     Ptr.initialize();
17165f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1717a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
17185f757f3fSDimitry Andric   else
1719a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1720a7dea167SDimitry Andric   return true;
1721a7dea167SDimitry Andric }
1722a7dea167SDimitry Andric 
1723a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1724a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1725a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1726a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1727a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1728a7dea167SDimitry Andric     return false;
17290fca6ea1SDimitry Andric   if (Ptr.canBeInitialized())
1730bdd1243dSDimitry Andric     Ptr.initialize();
17315f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1732a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
17335f757f3fSDimitry Andric   else
1734a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1735a7dea167SDimitry Andric   return true;
1736a7dea167SDimitry Andric }
1737a7dea167SDimitry Andric 
1738a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
17390fca6ea1SDimitry Andric bool Init(InterpState &S, CodePtr OpPC) {
17400fca6ea1SDimitry Andric   const T &Value = S.Stk.pop<T>();
17410fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
17420fca6ea1SDimitry Andric   if (!CheckInit(S, OpPC, Ptr)) {
17430fca6ea1SDimitry Andric     assert(false);
17440fca6ea1SDimitry Andric     return false;
17450fca6ea1SDimitry Andric   }
17460fca6ea1SDimitry Andric   Ptr.initialize();
17470fca6ea1SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
17480fca6ea1SDimitry Andric   return true;
17490fca6ea1SDimitry Andric }
17500fca6ea1SDimitry Andric 
17510fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1752a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
1753a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1754a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1755a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1756a7dea167SDimitry Andric     return false;
1757a7dea167SDimitry Andric   Ptr.initialize();
1758a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1759a7dea167SDimitry Andric   return true;
1760a7dea167SDimitry Andric }
1761a7dea167SDimitry Andric 
1762bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1763bdd1243dSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx
1764bdd1243dSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1765a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1766a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1767a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1768a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
17690fca6ea1SDimitry Andric   if (Ptr.isUnknownSizeArray())
17700fca6ea1SDimitry Andric     return false;
1771a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1772a7dea167SDimitry Andric     return false;
1773a7dea167SDimitry Andric   Ptr.initialize();
1774a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1775a7dea167SDimitry Andric   return true;
1776a7dea167SDimitry Andric }
1777a7dea167SDimitry Andric 
1778bdd1243dSDimitry Andric /// The same as InitElem, but pops the pointer as well.
1779a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1780a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1781a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1782a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
17830fca6ea1SDimitry Andric   if (Ptr.isUnknownSizeArray())
17840fca6ea1SDimitry Andric     return false;
1785a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1786a7dea167SDimitry Andric     return false;
1787a7dea167SDimitry Andric   Ptr.initialize();
1788a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1789a7dea167SDimitry Andric   return true;
1790a7dea167SDimitry Andric }
1791a7dea167SDimitry Andric 
17920fca6ea1SDimitry Andric inline bool Memcpy(InterpState &S, CodePtr OpPC) {
17930fca6ea1SDimitry Andric   const Pointer &Src = S.Stk.pop<Pointer>();
17940fca6ea1SDimitry Andric   Pointer &Dest = S.Stk.peek<Pointer>();
17950fca6ea1SDimitry Andric 
17960fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Src))
17970fca6ea1SDimitry Andric     return false;
17980fca6ea1SDimitry Andric 
17990fca6ea1SDimitry Andric   return DoMemcpy(S, OpPC, Src, Dest);
18000fca6ea1SDimitry Andric }
18010fca6ea1SDimitry Andric 
18020fca6ea1SDimitry Andric inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
18030fca6ea1SDimitry Andric   const auto &Member = S.Stk.pop<MemberPointer>();
18040fca6ea1SDimitry Andric   const auto &Base = S.Stk.pop<Pointer>();
18050fca6ea1SDimitry Andric 
18060fca6ea1SDimitry Andric   S.Stk.push<MemberPointer>(Member.takeInstance(Base));
18070fca6ea1SDimitry Andric   return true;
18080fca6ea1SDimitry Andric }
18090fca6ea1SDimitry Andric 
18100fca6ea1SDimitry Andric inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
18110fca6ea1SDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
18120fca6ea1SDimitry Andric 
18130fca6ea1SDimitry Andric   if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
18140fca6ea1SDimitry Andric     S.Stk.push<Pointer>(*Ptr);
18150fca6ea1SDimitry Andric     return true;
18160fca6ea1SDimitry Andric   }
18170fca6ea1SDimitry Andric   return false;
18180fca6ea1SDimitry Andric }
18190fca6ea1SDimitry Andric 
1820a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1821a7dea167SDimitry Andric // AddOffset, SubOffset
1822a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1823a7dea167SDimitry Andric 
182406c3fb27SDimitry Andric template <class T, ArithOp Op>
182506c3fb27SDimitry Andric bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
182606c3fb27SDimitry Andric                   const Pointer &Ptr) {
1827bdd1243dSDimitry Andric   // A zero offset does not change the pointer.
1828a7dea167SDimitry Andric   if (Offset.isZero()) {
1829bdd1243dSDimitry Andric     S.Stk.push<Pointer>(Ptr);
1830a7dea167SDimitry Andric     return true;
1831a7dea167SDimitry Andric   }
1832bdd1243dSDimitry Andric 
18330fca6ea1SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
18340fca6ea1SDimitry Andric     // The CheckNull will have emitted a note already, but we only
18350fca6ea1SDimitry Andric     // abort in C++, since this is fine in C.
18360fca6ea1SDimitry Andric     if (S.getLangOpts().CPlusPlus)
1837bdd1243dSDimitry Andric       return false;
18380fca6ea1SDimitry Andric   }
1839bdd1243dSDimitry Andric 
1840a7dea167SDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
1841a7dea167SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1842a7dea167SDimitry Andric     return false;
1843a7dea167SDimitry Andric 
18440fca6ea1SDimitry Andric   uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
18450fca6ea1SDimitry Andric   uint64_t Index;
18460fca6ea1SDimitry Andric   if (Ptr.isOnePastEnd())
18470fca6ea1SDimitry Andric     Index = MaxIndex;
18480fca6ea1SDimitry Andric   else
18490fca6ea1SDimitry Andric     Index = Ptr.getIndex();
1850a7dea167SDimitry Andric 
18515f757f3fSDimitry Andric   bool Invalid = false;
1852a7dea167SDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
18535f757f3fSDimitry Andric   auto DiagInvalidOffset = [&]() -> void {
1854a7dea167SDimitry Andric     const unsigned Bits = Offset.bitWidth();
18550fca6ea1SDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
18560fca6ea1SDimitry Andric     APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
18570fca6ea1SDimitry Andric                    /*IsUnsigned=*/false);
185806c3fb27SDimitry Andric     APSInt NewIndex =
185906c3fb27SDimitry Andric         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1860a7dea167SDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
18610fca6ea1SDimitry Andric         << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
18625f757f3fSDimitry Andric     Invalid = true;
1863a7dea167SDimitry Andric   };
1864a7dea167SDimitry Andric 
18650fca6ea1SDimitry Andric   if (Ptr.isBlockPointer()) {
18660fca6ea1SDimitry Andric     uint64_t IOffset = static_cast<uint64_t>(Offset);
18670fca6ea1SDimitry Andric     uint64_t MaxOffset = MaxIndex - Index;
18680fca6ea1SDimitry Andric 
186906c3fb27SDimitry Andric     if constexpr (Op == ArithOp::Add) {
1870a7dea167SDimitry Andric       // If the new offset would be negative, bail out.
18710fca6ea1SDimitry Andric       if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
18725f757f3fSDimitry Andric         DiagInvalidOffset();
1873a7dea167SDimitry Andric 
1874a7dea167SDimitry Andric       // If the new offset would be out of bounds, bail out.
18750fca6ea1SDimitry Andric       if (Offset.isPositive() && IOffset > MaxOffset)
18765f757f3fSDimitry Andric         DiagInvalidOffset();
1877bdd1243dSDimitry Andric     } else {
1878bdd1243dSDimitry Andric       // If the new offset would be negative, bail out.
18790fca6ea1SDimitry Andric       if (Offset.isPositive() && Index < IOffset)
18805f757f3fSDimitry Andric         DiagInvalidOffset();
1881a7dea167SDimitry Andric 
1882bdd1243dSDimitry Andric       // If the new offset would be out of bounds, bail out.
18830fca6ea1SDimitry Andric       if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
18845f757f3fSDimitry Andric         DiagInvalidOffset();
1885bdd1243dSDimitry Andric     }
18860fca6ea1SDimitry Andric   }
1887bdd1243dSDimitry Andric 
18880fca6ea1SDimitry Andric   if (Invalid && S.getLangOpts().CPlusPlus)
18895f757f3fSDimitry Andric     return false;
18905f757f3fSDimitry Andric 
1891a7dea167SDimitry Andric   // Offset is valid - compute it on unsigned.
1892a7dea167SDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
1893a7dea167SDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
1894bdd1243dSDimitry Andric   int64_t Result;
189506c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add)
1896bdd1243dSDimitry Andric     Result = WideIndex + WideOffset;
1897bdd1243dSDimitry Andric   else
1898bdd1243dSDimitry Andric     Result = WideIndex - WideOffset;
1899bdd1243dSDimitry Andric 
19000fca6ea1SDimitry Andric   // When the pointer is one-past-end, going back to index 0 is the only
19010fca6ea1SDimitry Andric   // useful thing we can do. Any other index has been diagnosed before and
19020fca6ea1SDimitry Andric   // we don't get here.
19030fca6ea1SDimitry Andric   if (Result == 0 && Ptr.isOnePastEnd()) {
19040fca6ea1SDimitry Andric     S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
19050fca6ea1SDimitry Andric                         Ptr.asBlockPointer().Base);
19060fca6ea1SDimitry Andric     return true;
19070fca6ea1SDimitry Andric   }
19080fca6ea1SDimitry Andric 
19090fca6ea1SDimitry Andric   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1910a7dea167SDimitry Andric   return true;
1911a7dea167SDimitry Andric }
1912a7dea167SDimitry Andric 
1913a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1914a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
191506c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
191606c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
191706c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1918a7dea167SDimitry Andric }
1919a7dea167SDimitry Andric 
1920a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1921a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
192206c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
192306c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
192406c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
192506c3fb27SDimitry Andric }
192606c3fb27SDimitry Andric 
192706c3fb27SDimitry Andric template <ArithOp Op>
19285f757f3fSDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
19295f757f3fSDimitry Andric                                    const Pointer &Ptr) {
19300fca6ea1SDimitry Andric   if (Ptr.isDummy())
19310fca6ea1SDimitry Andric     return false;
19320fca6ea1SDimitry Andric 
193306c3fb27SDimitry Andric   using OneT = Integral<8, false>;
19345f757f3fSDimitry Andric 
19355f757f3fSDimitry Andric   const Pointer &P = Ptr.deref<Pointer>();
19365f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
19375f757f3fSDimitry Andric     return false;
193806c3fb27SDimitry Andric 
193906c3fb27SDimitry Andric   // Get the current value on the stack.
19405f757f3fSDimitry Andric   S.Stk.push<Pointer>(P);
194106c3fb27SDimitry Andric 
194206c3fb27SDimitry Andric   // Now the current Ptr again and a constant 1.
194306c3fb27SDimitry Andric   OneT One = OneT::from(1);
194406c3fb27SDimitry Andric   if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
194506c3fb27SDimitry Andric     return false;
194606c3fb27SDimitry Andric 
194706c3fb27SDimitry Andric   // Store the new value.
194806c3fb27SDimitry Andric   Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
194906c3fb27SDimitry Andric   return true;
195006c3fb27SDimitry Andric }
195106c3fb27SDimitry Andric 
195206c3fb27SDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
19535f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
19545f757f3fSDimitry Andric 
19555f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
19565f757f3fSDimitry Andric     return false;
19575f757f3fSDimitry Andric 
19585f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
195906c3fb27SDimitry Andric }
196006c3fb27SDimitry Andric 
196106c3fb27SDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
19625f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
19635f757f3fSDimitry Andric 
19645f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
19655f757f3fSDimitry Andric     return false;
19665f757f3fSDimitry Andric 
19675f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1968a7dea167SDimitry Andric }
1969a7dea167SDimitry Andric 
1970bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack.
1971bdd1243dSDimitry Andric /// 2) Pops another Pointer from the stack.
1972bdd1243dSDimitry Andric /// 3) Pushes the different of the indices of the two pointers on the stack.
1973bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1974bdd1243dSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1975bdd1243dSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1976bdd1243dSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1977bdd1243dSDimitry Andric 
19780fca6ea1SDimitry Andric   if (RHS.isZero()) {
19790fca6ea1SDimitry Andric     S.Stk.push<T>(T::from(LHS.getIndex()));
19800fca6ea1SDimitry Andric     return true;
19810fca6ea1SDimitry Andric   }
19820fca6ea1SDimitry Andric 
19835f757f3fSDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1984bdd1243dSDimitry Andric     // TODO: Diagnose.
1985bdd1243dSDimitry Andric     return false;
1986bdd1243dSDimitry Andric   }
1987bdd1243dSDimitry Andric 
19880fca6ea1SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
19890fca6ea1SDimitry Andric     S.Stk.push<T>();
19900fca6ea1SDimitry Andric     return true;
19910fca6ea1SDimitry Andric   }
19920fca6ea1SDimitry Andric 
19930fca6ea1SDimitry Andric   T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
19940fca6ea1SDimitry Andric                                : T::from(LHS.getIndex());
19950fca6ea1SDimitry Andric   T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
19960fca6ea1SDimitry Andric                                : T::from(RHS.getIndex());
1997bdd1243dSDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1998bdd1243dSDimitry Andric }
1999a7dea167SDimitry Andric 
2000a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2001a7dea167SDimitry Andric // Destroy
2002a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2003a7dea167SDimitry Andric 
2004a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2005a7dea167SDimitry Andric   S.Current->destroy(I);
2006a7dea167SDimitry Andric   return true;
2007a7dea167SDimitry Andric }
2008a7dea167SDimitry Andric 
2009a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2010a7dea167SDimitry Andric // Cast, CastFP
2011a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2012a7dea167SDimitry Andric 
2013a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2014a7dea167SDimitry Andric   using T = typename PrimConv<TIn>::T;
2015a7dea167SDimitry Andric   using U = typename PrimConv<TOut>::T;
2016a7dea167SDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2017a7dea167SDimitry Andric   return true;
2018a7dea167SDimitry Andric }
2019a7dea167SDimitry Andric 
202006c3fb27SDimitry Andric /// 1) Pops a Floating from the stack.
202106c3fb27SDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics.
202206c3fb27SDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
202306c3fb27SDimitry Andric             llvm::RoundingMode RM) {
202406c3fb27SDimitry Andric   Floating F = S.Stk.pop<Floating>();
202506c3fb27SDimitry Andric   Floating Result = F.toSemantics(Sem, RM);
202606c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
202706c3fb27SDimitry Andric   return true;
202806c3fb27SDimitry Andric }
202906c3fb27SDimitry Andric 
20305f757f3fSDimitry Andric /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
20315f757f3fSDimitry Andric /// to know what bitwidth the result should be.
20325f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
20335f757f3fSDimitry Andric bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
20345f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(
20355f757f3fSDimitry Andric       IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
20365f757f3fSDimitry Andric   return true;
20375f757f3fSDimitry Andric }
20385f757f3fSDimitry Andric 
20395f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
20405f757f3fSDimitry Andric bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
20415f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(
20425f757f3fSDimitry Andric       IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
20435f757f3fSDimitry Andric   return true;
20445f757f3fSDimitry Andric }
20455f757f3fSDimitry Andric 
204606c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
204706c3fb27SDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
204806c3fb27SDimitry Andric                           const llvm::fltSemantics *Sem,
204906c3fb27SDimitry Andric                           llvm::RoundingMode RM) {
205006c3fb27SDimitry Andric   const T &From = S.Stk.pop<T>();
205106c3fb27SDimitry Andric   APSInt FromAP = From.toAPSInt();
205206c3fb27SDimitry Andric   Floating Result;
205306c3fb27SDimitry Andric 
205406c3fb27SDimitry Andric   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
205506c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
205606c3fb27SDimitry Andric 
20575f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
205806c3fb27SDimitry Andric }
205906c3fb27SDimitry Andric 
206006c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
206106c3fb27SDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
206206c3fb27SDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
206306c3fb27SDimitry Andric 
206406c3fb27SDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
206506c3fb27SDimitry Andric     S.Stk.push<T>(T(F.isNonZero()));
206606c3fb27SDimitry Andric     return true;
206706c3fb27SDimitry Andric   } else {
20685f757f3fSDimitry Andric     APSInt Result(std::max(8u, T::bitWidth()),
206906c3fb27SDimitry Andric                   /*IsUnsigned=*/!T::isSigned());
207006c3fb27SDimitry Andric     auto Status = F.convertToInteger(Result);
207106c3fb27SDimitry Andric 
207206c3fb27SDimitry Andric     // Float-to-Integral overflow check.
20730fca6ea1SDimitry Andric     if ((Status & APFloat::opStatus::opInvalidOp)) {
207406c3fb27SDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
207506c3fb27SDimitry Andric       QualType Type = E->getType();
207606c3fb27SDimitry Andric 
207706c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
20785f757f3fSDimitry Andric       if (S.noteUndefinedBehavior()) {
20795f757f3fSDimitry Andric         S.Stk.push<T>(T(Result));
20805f757f3fSDimitry Andric         return true;
20815f757f3fSDimitry Andric       }
20825f757f3fSDimitry Andric       return false;
20835f757f3fSDimitry Andric     }
20845f757f3fSDimitry Andric 
20855f757f3fSDimitry Andric     S.Stk.push<T>(T(Result));
20865f757f3fSDimitry Andric     return CheckFloatResult(S, OpPC, F, Status);
20875f757f3fSDimitry Andric   }
20885f757f3fSDimitry Andric }
20895f757f3fSDimitry Andric 
20905f757f3fSDimitry Andric static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
20915f757f3fSDimitry Andric                                           uint32_t BitWidth) {
20925f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
20935f757f3fSDimitry Andric 
20945f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/true);
20955f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
20965f757f3fSDimitry Andric 
20975f757f3fSDimitry Andric   // Float-to-Integral overflow check.
20985f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
20995f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
21005f757f3fSDimitry Andric     QualType Type = E->getType();
21015f757f3fSDimitry Andric 
21025f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
210306c3fb27SDimitry Andric     return S.noteUndefinedBehavior();
210406c3fb27SDimitry Andric   }
210506c3fb27SDimitry Andric 
21065f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
21075f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
210806c3fb27SDimitry Andric }
21095f757f3fSDimitry Andric 
21105f757f3fSDimitry Andric static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
21115f757f3fSDimitry Andric                                            uint32_t BitWidth) {
21125f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
21135f757f3fSDimitry Andric 
21145f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/false);
21155f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
21165f757f3fSDimitry Andric 
21175f757f3fSDimitry Andric   // Float-to-Integral overflow check.
21185f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
21195f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
21205f757f3fSDimitry Andric     QualType Type = E->getType();
21215f757f3fSDimitry Andric 
21225f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
21235f757f3fSDimitry Andric     return S.noteUndefinedBehavior();
21245f757f3fSDimitry Andric   }
21255f757f3fSDimitry Andric 
21265f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
21275f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
21285f757f3fSDimitry Andric }
21295f757f3fSDimitry Andric 
21305f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
21315f757f3fSDimitry Andric bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
21325f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
21335f757f3fSDimitry Andric 
21340fca6ea1SDimitry Andric   if (Ptr.isDummy())
21355f757f3fSDimitry Andric     return false;
21365f757f3fSDimitry Andric 
21370fca6ea1SDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
21380fca6ea1SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_invalid_cast)
21390fca6ea1SDimitry Andric       << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
21400fca6ea1SDimitry Andric 
21415f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
21425f757f3fSDimitry Andric   return true;
214306c3fb27SDimitry Andric }
214406c3fb27SDimitry Andric 
21450fca6ea1SDimitry Andric static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
21460fca6ea1SDimitry Andric                                          uint32_t BitWidth) {
21470fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
21480fca6ea1SDimitry Andric 
21490fca6ea1SDimitry Andric   if (Ptr.isDummy())
21500fca6ea1SDimitry Andric     return false;
21510fca6ea1SDimitry Andric 
21520fca6ea1SDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
21530fca6ea1SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_invalid_cast)
21540fca6ea1SDimitry Andric       << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
21550fca6ea1SDimitry Andric 
21560fca6ea1SDimitry Andric   S.Stk.push<IntegralAP<false>>(
21570fca6ea1SDimitry Andric       IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
21580fca6ea1SDimitry Andric   return true;
21590fca6ea1SDimitry Andric }
21600fca6ea1SDimitry Andric 
21610fca6ea1SDimitry Andric static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
21620fca6ea1SDimitry Andric                                           uint32_t BitWidth) {
21630fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
21640fca6ea1SDimitry Andric 
21650fca6ea1SDimitry Andric   if (Ptr.isDummy())
21660fca6ea1SDimitry Andric     return false;
21670fca6ea1SDimitry Andric 
21680fca6ea1SDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
21690fca6ea1SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_invalid_cast)
21700fca6ea1SDimitry Andric       << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
21710fca6ea1SDimitry Andric 
21720fca6ea1SDimitry Andric   S.Stk.push<IntegralAP<true>>(
21730fca6ea1SDimitry Andric       IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
21740fca6ea1SDimitry Andric   return true;
21750fca6ea1SDimitry Andric }
21760fca6ea1SDimitry Andric 
21770fca6ea1SDimitry Andric static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
21780fca6ea1SDimitry Andric   const auto &Ptr = S.Stk.peek<Pointer>();
21790fca6ea1SDimitry Andric 
21800fca6ea1SDimitry Andric   if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
21810fca6ea1SDimitry Andric     bool HasValidResult = !Ptr.isZero();
21820fca6ea1SDimitry Andric 
21830fca6ea1SDimitry Andric     if (HasValidResult) {
21840fca6ea1SDimitry Andric       // FIXME: note_constexpr_invalid_void_star_cast
21850fca6ea1SDimitry Andric     } else if (!S.getLangOpts().CPlusPlus26) {
21860fca6ea1SDimitry Andric       const SourceInfo &E = S.Current->getSource(OpPC);
21870fca6ea1SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_invalid_cast)
21880fca6ea1SDimitry Andric           << 3 << "'void *'" << S.Current->getRange(OpPC);
21890fca6ea1SDimitry Andric     }
21900fca6ea1SDimitry Andric   } else {
21910fca6ea1SDimitry Andric     const SourceInfo &E = S.Current->getSource(OpPC);
21920fca6ea1SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_invalid_cast)
21930fca6ea1SDimitry Andric         << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
21940fca6ea1SDimitry Andric   }
21950fca6ea1SDimitry Andric 
21960fca6ea1SDimitry Andric   return true;
21970fca6ea1SDimitry Andric }
21980fca6ea1SDimitry Andric 
2199a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2200a7dea167SDimitry Andric // Zero, Nullptr
2201a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2202a7dea167SDimitry Andric 
2203a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
2204a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
2205a7dea167SDimitry Andric   S.Stk.push<T>(T::zero());
2206a7dea167SDimitry Andric   return true;
2207a7dea167SDimitry Andric }
2208a7dea167SDimitry Andric 
22095f757f3fSDimitry Andric static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
22105f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
22115f757f3fSDimitry Andric   return true;
22125f757f3fSDimitry Andric }
22135f757f3fSDimitry Andric 
22145f757f3fSDimitry Andric static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
22155f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
22165f757f3fSDimitry Andric   return true;
22175f757f3fSDimitry Andric }
22185f757f3fSDimitry Andric 
2219a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
22200fca6ea1SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
22210fca6ea1SDimitry Andric   // Note: Desc can be null.
22220fca6ea1SDimitry Andric   S.Stk.push<T>(0, Desc);
2223a7dea167SDimitry Andric   return true;
2224a7dea167SDimitry Andric }
2225a7dea167SDimitry Andric 
2226a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2227a7dea167SDimitry Andric // This, ImplicitThis
2228a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2229a7dea167SDimitry Andric 
2230a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
2231a7dea167SDimitry Andric   // Cannot read 'this' in this mode.
2232a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
2233a7dea167SDimitry Andric     return false;
2234a7dea167SDimitry Andric   }
2235a7dea167SDimitry Andric 
2236a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
2237a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
2238a7dea167SDimitry Andric     return false;
2239a7dea167SDimitry Andric 
22400fca6ea1SDimitry Andric   // Ensure the This pointer has been cast to the correct base.
22410fca6ea1SDimitry Andric   if (!This.isDummy()) {
22420fca6ea1SDimitry Andric     assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
22430fca6ea1SDimitry Andric     assert(This.getRecord());
22440fca6ea1SDimitry Andric     assert(
22450fca6ea1SDimitry Andric         This.getRecord()->getDecl() ==
22460fca6ea1SDimitry Andric         cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
22470fca6ea1SDimitry Andric   }
22480fca6ea1SDimitry Andric 
2249a7dea167SDimitry Andric   S.Stk.push<Pointer>(This);
2250a7dea167SDimitry Andric   return true;
2251a7dea167SDimitry Andric }
2252a7dea167SDimitry Andric 
2253bdd1243dSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2254bdd1243dSDimitry Andric   assert(S.Current->getFunction()->hasRVO());
225506c3fb27SDimitry Andric   if (S.checkingPotentialConstantExpression())
225606c3fb27SDimitry Andric     return false;
2257bdd1243dSDimitry Andric   S.Stk.push<Pointer>(S.Current->getRVOPtr());
2258bdd1243dSDimitry Andric   return true;
2259bdd1243dSDimitry Andric }
2260bdd1243dSDimitry Andric 
2261a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2262a7dea167SDimitry Andric // Shr, Shl
2263a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
22640fca6ea1SDimitry Andric enum class ShiftDir { Left, Right };
22650fca6ea1SDimitry Andric 
22660fca6ea1SDimitry Andric template <class LT, class RT, ShiftDir Dir>
22670fca6ea1SDimitry Andric inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
22680fca6ea1SDimitry Andric   const unsigned Bits = LHS.bitWidth();
22690fca6ea1SDimitry Andric 
22700fca6ea1SDimitry Andric   // OpenCL 6.3j: shift values are effectively % word size of LHS.
22710fca6ea1SDimitry Andric   if (S.getLangOpts().OpenCL)
22720fca6ea1SDimitry Andric     RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
22730fca6ea1SDimitry Andric                RHS.bitWidth(), &RHS);
22740fca6ea1SDimitry Andric 
22750fca6ea1SDimitry Andric   if (RHS.isNegative()) {
22760fca6ea1SDimitry Andric     // During constant-folding, a negative shift is an opposite shift. Such a
22770fca6ea1SDimitry Andric     // shift is not a constant expression.
22780fca6ea1SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
22790fca6ea1SDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2280*36b606aeSDimitry Andric     if (!S.noteUndefinedBehavior())
22810fca6ea1SDimitry Andric       return false;
22820fca6ea1SDimitry Andric     RHS = -RHS;
22830fca6ea1SDimitry Andric     return DoShift < LT, RT,
22840fca6ea1SDimitry Andric            Dir == ShiftDir::Left ? ShiftDir::Right
22850fca6ea1SDimitry Andric                                  : ShiftDir::Left > (S, OpPC, LHS, RHS);
22860fca6ea1SDimitry Andric   }
22870fca6ea1SDimitry Andric 
22880fca6ea1SDimitry Andric   if constexpr (Dir == ShiftDir::Left) {
22890fca6ea1SDimitry Andric     if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
22900fca6ea1SDimitry Andric       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
22910fca6ea1SDimitry Andric       // operand, and must not overflow the corresponding unsigned type.
22920fca6ea1SDimitry Andric       // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
22930fca6ea1SDimitry Andric       // E1 x 2^E2 module 2^N.
22940fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
22950fca6ea1SDimitry Andric       S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2296*36b606aeSDimitry Andric       if (!S.noteUndefinedBehavior())
22970fca6ea1SDimitry Andric         return false;
22980fca6ea1SDimitry Andric     }
22990fca6ea1SDimitry Andric   }
23000fca6ea1SDimitry Andric 
23010fca6ea1SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
23020fca6ea1SDimitry Andric     return false;
23030fca6ea1SDimitry Andric 
23040fca6ea1SDimitry Andric   // Limit the shift amount to Bits - 1. If this happened,
23050fca6ea1SDimitry Andric   // it has already been diagnosed by CheckShift() above,
23060fca6ea1SDimitry Andric   // but we still need to handle it.
23070fca6ea1SDimitry Andric   typename LT::AsUnsigned R;
23080fca6ea1SDimitry Andric   if constexpr (Dir == ShiftDir::Left) {
23090fca6ea1SDimitry Andric     if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
23100fca6ea1SDimitry Andric       LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
23110fca6ea1SDimitry Andric                                 LT::AsUnsigned::from(Bits - 1), Bits, &R);
23120fca6ea1SDimitry Andric     else
23130fca6ea1SDimitry Andric       LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
23140fca6ea1SDimitry Andric                                 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
23150fca6ea1SDimitry Andric   } else {
23160fca6ea1SDimitry Andric     if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
23170fca6ea1SDimitry Andric       LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
23180fca6ea1SDimitry Andric                                  LT::AsUnsigned::from(Bits - 1), Bits, &R);
23190fca6ea1SDimitry Andric     else
23200fca6ea1SDimitry Andric       LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
23210fca6ea1SDimitry Andric                                  LT::AsUnsigned::from(RHS, Bits), Bits, &R);
23220fca6ea1SDimitry Andric   }
23230fca6ea1SDimitry Andric 
23240fca6ea1SDimitry Andric   S.Stk.push<LT>(LT::from(R));
23250fca6ea1SDimitry Andric   return true;
23260fca6ea1SDimitry Andric }
2327a7dea167SDimitry Andric 
2328bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
2329a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
2330bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
2331bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
23320fca6ea1SDimitry Andric   auto RHS = S.Stk.pop<RT>();
23330fca6ea1SDimitry Andric   auto LHS = S.Stk.pop<LT>();
2334a7dea167SDimitry Andric 
23350fca6ea1SDimitry Andric   return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2336a7dea167SDimitry Andric }
2337a7dea167SDimitry Andric 
2338bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
2339a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
2340bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
2341bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
23420fca6ea1SDimitry Andric   auto RHS = S.Stk.pop<RT>();
23430fca6ea1SDimitry Andric   auto LHS = S.Stk.pop<LT>();
2344a7dea167SDimitry Andric 
23450fca6ea1SDimitry Andric   return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2346a7dea167SDimitry Andric }
2347a7dea167SDimitry Andric 
2348a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2349a7dea167SDimitry Andric // NoRet
2350a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2351a7dea167SDimitry Andric 
2352a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
2353a7dea167SDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2354a7dea167SDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2355a7dea167SDimitry Andric   return false;
2356a7dea167SDimitry Andric }
2357a7dea167SDimitry Andric 
2358a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2359a7dea167SDimitry Andric // NarrowPtr, ExpandPtr
2360a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
2361a7dea167SDimitry Andric 
2362a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2363a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2364a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
2365a7dea167SDimitry Andric   return true;
2366a7dea167SDimitry Andric }
2367a7dea167SDimitry Andric 
2368a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2369a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2370a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.expand());
2371a7dea167SDimitry Andric   return true;
2372a7dea167SDimitry Andric }
2373a7dea167SDimitry Andric 
237406c3fb27SDimitry Andric // 1) Pops an integral value from the stack
237506c3fb27SDimitry Andric // 2) Peeks a pointer
237606c3fb27SDimitry Andric // 3) Pushes a new pointer that's a narrowed array
237706c3fb27SDimitry Andric //   element of the peeked pointer with the value
237806c3fb27SDimitry Andric //   from 1) added as offset.
237906c3fb27SDimitry Andric //
238006c3fb27SDimitry Andric // This leaves the original pointer on the stack and pushes a new one
238106c3fb27SDimitry Andric // with the offset applied and narrowed.
238206c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
238306c3fb27SDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
238406c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
238506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
238606c3fb27SDimitry Andric 
23870fca6ea1SDimitry Andric   if (!Ptr.isZero()) {
23880fca6ea1SDimitry Andric     if (!CheckArray(S, OpPC, Ptr))
23890fca6ea1SDimitry Andric       return false;
23900fca6ea1SDimitry Andric   }
23910fca6ea1SDimitry Andric 
239206c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
239306c3fb27SDimitry Andric     return false;
239406c3fb27SDimitry Andric 
239506c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
239606c3fb27SDimitry Andric }
239706c3fb27SDimitry Andric 
23980fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
23990fca6ea1SDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
24000fca6ea1SDimitry Andric   const T &Offset = S.Stk.pop<T>();
24010fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
24020fca6ea1SDimitry Andric 
24030fca6ea1SDimitry Andric   if (!Ptr.isZero()) {
24040fca6ea1SDimitry Andric     if (!CheckArray(S, OpPC, Ptr))
24050fca6ea1SDimitry Andric       return false;
24060fca6ea1SDimitry Andric   }
24070fca6ea1SDimitry Andric 
24080fca6ea1SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
24090fca6ea1SDimitry Andric     return false;
24100fca6ea1SDimitry Andric 
24110fca6ea1SDimitry Andric   return NarrowPtr(S, OpPC);
24120fca6ea1SDimitry Andric }
24130fca6ea1SDimitry Andric 
24140fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
24150fca6ea1SDimitry Andric inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
24160fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
24170fca6ea1SDimitry Andric 
24180fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
24190fca6ea1SDimitry Andric     return false;
24200fca6ea1SDimitry Andric 
24210fca6ea1SDimitry Andric   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
24220fca6ea1SDimitry Andric   return true;
24230fca6ea1SDimitry Andric }
24240fca6ea1SDimitry Andric 
24250fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
24260fca6ea1SDimitry Andric inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
24270fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
24280fca6ea1SDimitry Andric 
24290fca6ea1SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
24300fca6ea1SDimitry Andric     return false;
24310fca6ea1SDimitry Andric 
24320fca6ea1SDimitry Andric   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
24330fca6ea1SDimitry Andric   return true;
24340fca6ea1SDimitry Andric }
24350fca6ea1SDimitry Andric 
24360fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
24370fca6ea1SDimitry Andric inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) {
24380fca6ea1SDimitry Andric   const auto &SrcPtr = S.Stk.pop<Pointer>();
24390fca6ea1SDimitry Andric   const auto &DestPtr = S.Stk.peek<Pointer>();
24400fca6ea1SDimitry Andric 
24410fca6ea1SDimitry Andric   for (uint32_t I = 0; I != Size; ++I) {
24420fca6ea1SDimitry Andric     const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
24430fca6ea1SDimitry Andric 
24440fca6ea1SDimitry Andric     if (!CheckLoad(S, OpPC, SP))
24450fca6ea1SDimitry Andric       return false;
24460fca6ea1SDimitry Andric 
24470fca6ea1SDimitry Andric     const Pointer &DP = DestPtr.atIndex(DestIndex + I);
24480fca6ea1SDimitry Andric     DP.deref<T>() = SP.deref<T>();
24490fca6ea1SDimitry Andric     DP.initialize();
24500fca6ea1SDimitry Andric   }
24510fca6ea1SDimitry Andric   return true;
24520fca6ea1SDimitry Andric }
24530fca6ea1SDimitry Andric 
24540fca6ea1SDimitry Andric /// Just takes a pointer and checks if it's an incomplete
24555f757f3fSDimitry Andric /// array type.
24565f757f3fSDimitry Andric inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
24575f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
24585f757f3fSDimitry Andric 
24590fca6ea1SDimitry Andric   if (Ptr.isZero()) {
24600fca6ea1SDimitry Andric     S.Stk.push<Pointer>(Ptr);
24610fca6ea1SDimitry Andric     return true;
24620fca6ea1SDimitry Andric   }
24630fca6ea1SDimitry Andric 
24640fca6ea1SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
24650fca6ea1SDimitry Andric     return false;
24660fca6ea1SDimitry Andric 
24670fca6ea1SDimitry Andric   if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
24685f757f3fSDimitry Andric     S.Stk.push<Pointer>(Ptr.atIndex(0));
24695f757f3fSDimitry Andric     return true;
24705f757f3fSDimitry Andric   }
24715f757f3fSDimitry Andric 
24725f757f3fSDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
24735f757f3fSDimitry Andric   S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
24745f757f3fSDimitry Andric 
24755f757f3fSDimitry Andric   return false;
24765f757f3fSDimitry Andric }
24775f757f3fSDimitry Andric 
24780fca6ea1SDimitry Andric inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
24790fca6ea1SDimitry Andric                     uint32_t VarArgSize) {
2480bdd1243dSDimitry Andric   if (Func->hasThisPointer()) {
24810fca6ea1SDimitry Andric     size_t ArgSize = Func->getArgSize() + VarArgSize;
24820fca6ea1SDimitry Andric     size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
248306c3fb27SDimitry Andric     const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
248406c3fb27SDimitry Andric 
24855f757f3fSDimitry Andric     // If the current function is a lambda static invoker and
24865f757f3fSDimitry Andric     // the function we're about to call is a lambda call operator,
24875f757f3fSDimitry Andric     // skip the CheckInvoke, since the ThisPtr is a null pointer
24885f757f3fSDimitry Andric     // anyway.
24895f757f3fSDimitry Andric     if (!(S.Current->getFunction() &&
24905f757f3fSDimitry Andric           S.Current->getFunction()->isLambdaStaticInvoker() &&
24915f757f3fSDimitry Andric           Func->isLambdaCallOperator())) {
249206c3fb27SDimitry Andric       if (!CheckInvoke(S, OpPC, ThisPtr))
2493bdd1243dSDimitry Andric         return false;
24945f757f3fSDimitry Andric     }
2495bdd1243dSDimitry Andric 
249606c3fb27SDimitry Andric     if (S.checkingPotentialConstantExpression())
249706c3fb27SDimitry Andric       return false;
249806c3fb27SDimitry Andric   }
249906c3fb27SDimitry Andric 
250006c3fb27SDimitry Andric   if (!CheckCallable(S, OpPC, Func))
250106c3fb27SDimitry Andric     return false;
250206c3fb27SDimitry Andric 
250306c3fb27SDimitry Andric   if (!CheckCallDepth(S, OpPC))
250406c3fb27SDimitry Andric     return false;
250506c3fb27SDimitry Andric 
25060fca6ea1SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
25070fca6ea1SDimitry Andric   InterpFrame *FrameBefore = S.Current;
25080fca6ea1SDimitry Andric   S.Current = NewFrame.get();
25090fca6ea1SDimitry Andric 
25100fca6ea1SDimitry Andric   APValue CallResult;
25110fca6ea1SDimitry Andric   // Note that we cannot assert(CallResult.hasValue()) here since
25120fca6ea1SDimitry Andric   // Ret() above only sets the APValue if the curent frame doesn't
25130fca6ea1SDimitry Andric   // have a caller set.
25140fca6ea1SDimitry Andric   if (Interpret(S, CallResult)) {
25150fca6ea1SDimitry Andric     NewFrame.release(); // Frame was delete'd already.
25160fca6ea1SDimitry Andric     assert(S.Current == FrameBefore);
25170fca6ea1SDimitry Andric     return true;
25180fca6ea1SDimitry Andric   }
25190fca6ea1SDimitry Andric 
25200fca6ea1SDimitry Andric   // Interpreting the function failed somehow. Reset to
25210fca6ea1SDimitry Andric   // previous state.
25220fca6ea1SDimitry Andric   S.Current = FrameBefore;
25230fca6ea1SDimitry Andric   return false;
25240fca6ea1SDimitry Andric 
25250fca6ea1SDimitry Andric   return false;
25260fca6ea1SDimitry Andric }
25270fca6ea1SDimitry Andric 
25280fca6ea1SDimitry Andric inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
25290fca6ea1SDimitry Andric                  uint32_t VarArgSize) {
25300fca6ea1SDimitry Andric   if (Func->hasThisPointer()) {
25310fca6ea1SDimitry Andric     size_t ArgSize = Func->getArgSize() + VarArgSize;
25320fca6ea1SDimitry Andric     size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
25330fca6ea1SDimitry Andric 
25340fca6ea1SDimitry Andric     const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
25350fca6ea1SDimitry Andric 
25360fca6ea1SDimitry Andric     // If the current function is a lambda static invoker and
25370fca6ea1SDimitry Andric     // the function we're about to call is a lambda call operator,
25380fca6ea1SDimitry Andric     // skip the CheckInvoke, since the ThisPtr is a null pointer
25390fca6ea1SDimitry Andric     // anyway.
25400fca6ea1SDimitry Andric     if (!(S.Current->getFunction() &&
25410fca6ea1SDimitry Andric           S.Current->getFunction()->isLambdaStaticInvoker() &&
25420fca6ea1SDimitry Andric           Func->isLambdaCallOperator())) {
25430fca6ea1SDimitry Andric       if (!CheckInvoke(S, OpPC, ThisPtr))
25440fca6ea1SDimitry Andric         return false;
25450fca6ea1SDimitry Andric     }
25460fca6ea1SDimitry Andric   }
25470fca6ea1SDimitry Andric 
25480fca6ea1SDimitry Andric   if (!CheckCallable(S, OpPC, Func))
25490fca6ea1SDimitry Andric     return false;
25500fca6ea1SDimitry Andric 
25510fca6ea1SDimitry Andric   if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
25520fca6ea1SDimitry Andric     return false;
25530fca6ea1SDimitry Andric 
25540fca6ea1SDimitry Andric   if (!CheckCallDepth(S, OpPC))
25550fca6ea1SDimitry Andric     return false;
25560fca6ea1SDimitry Andric 
25570fca6ea1SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2558bdd1243dSDimitry Andric   InterpFrame *FrameBefore = S.Current;
2559bdd1243dSDimitry Andric   S.Current = NewFrame.get();
2560bdd1243dSDimitry Andric 
2561bdd1243dSDimitry Andric   APValue CallResult;
2562bdd1243dSDimitry Andric   // Note that we cannot assert(CallResult.hasValue()) here since
2563bdd1243dSDimitry Andric   // Ret() above only sets the APValue if the curent frame doesn't
2564bdd1243dSDimitry Andric   // have a caller set.
2565bdd1243dSDimitry Andric   if (Interpret(S, CallResult)) {
2566bdd1243dSDimitry Andric     NewFrame.release(); // Frame was delete'd already.
2567bdd1243dSDimitry Andric     assert(S.Current == FrameBefore);
2568bdd1243dSDimitry Andric     return true;
2569bdd1243dSDimitry Andric   }
2570bdd1243dSDimitry Andric 
2571bdd1243dSDimitry Andric   // Interpreting the function failed somehow. Reset to
2572bdd1243dSDimitry Andric   // previous state.
2573bdd1243dSDimitry Andric   S.Current = FrameBefore;
2574bdd1243dSDimitry Andric   return false;
2575bdd1243dSDimitry Andric }
2576bdd1243dSDimitry Andric 
25770fca6ea1SDimitry Andric inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
25780fca6ea1SDimitry Andric                      uint32_t VarArgSize) {
257906c3fb27SDimitry Andric   assert(Func->hasThisPointer());
258006c3fb27SDimitry Andric   assert(Func->isVirtual());
25810fca6ea1SDimitry Andric   size_t ArgSize = Func->getArgSize() + VarArgSize;
25820fca6ea1SDimitry Andric   size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
258306c3fb27SDimitry Andric   Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
258406c3fb27SDimitry Andric 
25850fca6ea1SDimitry Andric   QualType DynamicType = ThisPtr.getDeclDesc()->getType();
25860fca6ea1SDimitry Andric   const CXXRecordDecl *DynamicDecl;
25870fca6ea1SDimitry Andric   if (DynamicType->isPointerType() || DynamicType->isReferenceType())
25880fca6ea1SDimitry Andric     DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
25890fca6ea1SDimitry Andric   else
25900fca6ea1SDimitry Andric     DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
259106c3fb27SDimitry Andric   const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
259206c3fb27SDimitry Andric   const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
259306c3fb27SDimitry Andric   const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
259406c3fb27SDimitry Andric       DynamicDecl, StaticDecl, InitialFunction);
259506c3fb27SDimitry Andric 
259606c3fb27SDimitry Andric   if (Overrider != InitialFunction) {
25975f757f3fSDimitry Andric     // DR1872: An instantiated virtual constexpr function can't be called in a
25985f757f3fSDimitry Andric     // constant expression (prior to C++20). We can still constant-fold such a
25995f757f3fSDimitry Andric     // call.
26005f757f3fSDimitry Andric     if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
26015f757f3fSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
26025f757f3fSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
26035f757f3fSDimitry Andric     }
26045f757f3fSDimitry Andric 
26055f757f3fSDimitry Andric     Func = S.getContext().getOrCreateFunction(Overrider);
260606c3fb27SDimitry Andric 
260706c3fb27SDimitry Andric     const CXXRecordDecl *ThisFieldDecl =
260806c3fb27SDimitry Andric         ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
260906c3fb27SDimitry Andric     if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
261006c3fb27SDimitry Andric       // If the function we call is further DOWN the hierarchy than the
261106c3fb27SDimitry Andric       // FieldDesc of our pointer, just get the DeclDesc instead, which
261206c3fb27SDimitry Andric       // is the furthest we might go up in the hierarchy.
261306c3fb27SDimitry Andric       ThisPtr = ThisPtr.getDeclPtr();
261406c3fb27SDimitry Andric     }
261506c3fb27SDimitry Andric   }
261606c3fb27SDimitry Andric 
26170fca6ea1SDimitry Andric   return Call(S, OpPC, Func, VarArgSize);
261806c3fb27SDimitry Andric }
261906c3fb27SDimitry Andric 
26205f757f3fSDimitry Andric inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
26215f757f3fSDimitry Andric                    const CallExpr *CE) {
262206c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
262306c3fb27SDimitry Andric 
262406c3fb27SDimitry Andric   InterpFrame *FrameBefore = S.Current;
262506c3fb27SDimitry Andric   S.Current = NewFrame.get();
262606c3fb27SDimitry Andric 
26275f757f3fSDimitry Andric   if (InterpretBuiltin(S, PC, Func, CE)) {
262806c3fb27SDimitry Andric     NewFrame.release();
262906c3fb27SDimitry Andric     return true;
263006c3fb27SDimitry Andric   }
263106c3fb27SDimitry Andric   S.Current = FrameBefore;
263206c3fb27SDimitry Andric   return false;
263306c3fb27SDimitry Andric }
263406c3fb27SDimitry Andric 
26350fca6ea1SDimitry Andric inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
26360fca6ea1SDimitry Andric                     const CallExpr *CE) {
263706c3fb27SDimitry Andric   const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
263806c3fb27SDimitry Andric 
263906c3fb27SDimitry Andric   const Function *F = FuncPtr.getFunction();
26400fca6ea1SDimitry Andric   if (!F) {
26410fca6ea1SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
26420fca6ea1SDimitry Andric     S.FFDiag(E, diag::note_constexpr_null_callee)
26430fca6ea1SDimitry Andric         << const_cast<Expr *>(E) << E->getSourceRange();
26440fca6ea1SDimitry Andric     return false;
26450fca6ea1SDimitry Andric   }
26460fca6ea1SDimitry Andric 
26470fca6ea1SDimitry Andric   if (!FuncPtr.isValid())
264806c3fb27SDimitry Andric     return false;
264906c3fb27SDimitry Andric 
26500fca6ea1SDimitry Andric   assert(F);
26515f757f3fSDimitry Andric 
26520fca6ea1SDimitry Andric   // This happens when the call expression has been cast to
26530fca6ea1SDimitry Andric   // something else, but we don't support that.
26540fca6ea1SDimitry Andric   if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
26550fca6ea1SDimitry Andric       S.Ctx.classify(CE->getType()))
26560fca6ea1SDimitry Andric     return false;
26570fca6ea1SDimitry Andric 
26580fca6ea1SDimitry Andric   // Check argument nullability state.
26590fca6ea1SDimitry Andric   if (F->hasNonNullAttr()) {
26600fca6ea1SDimitry Andric     if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
26610fca6ea1SDimitry Andric       return false;
26620fca6ea1SDimitry Andric   }
26630fca6ea1SDimitry Andric 
26640fca6ea1SDimitry Andric   assert(ArgSize >= F->getWrittenArgSize());
26650fca6ea1SDimitry Andric   uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
26660fca6ea1SDimitry Andric 
26670fca6ea1SDimitry Andric   // We need to do this explicitly here since we don't have the necessary
26680fca6ea1SDimitry Andric   // information to do it automatically.
26690fca6ea1SDimitry Andric   if (F->isThisPointerExplicit())
26700fca6ea1SDimitry Andric     VarArgSize -= align(primSize(PT_Ptr));
26710fca6ea1SDimitry Andric 
26720fca6ea1SDimitry Andric   if (F->isVirtual())
26730fca6ea1SDimitry Andric     return CallVirt(S, OpPC, F, VarArgSize);
26740fca6ea1SDimitry Andric 
26750fca6ea1SDimitry Andric   return Call(S, OpPC, F, VarArgSize);
267606c3fb27SDimitry Andric }
267706c3fb27SDimitry Andric 
267806c3fb27SDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
267906c3fb27SDimitry Andric   assert(Func);
268006c3fb27SDimitry Andric   S.Stk.push<FunctionPointer>(Func);
268106c3fb27SDimitry Andric   return true;
268206c3fb27SDimitry Andric }
268306c3fb27SDimitry Andric 
26840fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
26850fca6ea1SDimitry Andric inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
26860fca6ea1SDimitry Andric   const T &IntVal = S.Stk.pop<T>();
26870fca6ea1SDimitry Andric 
26880fca6ea1SDimitry Andric   S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
26890fca6ea1SDimitry Andric   return true;
26900fca6ea1SDimitry Andric }
26910fca6ea1SDimitry Andric 
26920fca6ea1SDimitry Andric inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
26930fca6ea1SDimitry Andric   S.Stk.push<MemberPointer>(D);
26940fca6ea1SDimitry Andric   return true;
26950fca6ea1SDimitry Andric }
26960fca6ea1SDimitry Andric 
26970fca6ea1SDimitry Andric inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
26980fca6ea1SDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
26990fca6ea1SDimitry Andric 
27000fca6ea1SDimitry Andric   S.Stk.push<Pointer>(MP.getBase());
27010fca6ea1SDimitry Andric   return true;
27020fca6ea1SDimitry Andric }
27030fca6ea1SDimitry Andric 
27040fca6ea1SDimitry Andric inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
27050fca6ea1SDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
27060fca6ea1SDimitry Andric 
27070fca6ea1SDimitry Andric   const auto *FD = cast<FunctionDecl>(MP.getDecl());
27080fca6ea1SDimitry Andric   const auto *Func = S.getContext().getOrCreateFunction(FD);
27090fca6ea1SDimitry Andric 
27100fca6ea1SDimitry Andric   S.Stk.push<FunctionPointer>(Func);
27110fca6ea1SDimitry Andric   return true;
27120fca6ea1SDimitry Andric }
27130fca6ea1SDimitry Andric 
27145f757f3fSDimitry Andric /// Just emit a diagnostic. The expression that caused emission of this
27155f757f3fSDimitry Andric /// op is not valid in a constant context.
27165f757f3fSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC) {
27175f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
27185f757f3fSDimitry Andric   S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
27195f757f3fSDimitry Andric       << S.Current->getRange(OpPC);
27205f757f3fSDimitry Andric   return false;
27215f757f3fSDimitry Andric }
27225f757f3fSDimitry Andric 
27230fca6ea1SDimitry Andric inline bool Unsupported(InterpState &S, CodePtr OpPC) {
27240fca6ea1SDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
27250fca6ea1SDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
27260fca6ea1SDimitry Andric       << S.Current->getRange(OpPC);
27270fca6ea1SDimitry Andric   return false;
27280fca6ea1SDimitry Andric }
27290fca6ea1SDimitry Andric 
27300fca6ea1SDimitry Andric /// Do nothing and just abort execution.
27310fca6ea1SDimitry Andric inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
27320fca6ea1SDimitry Andric 
27335f757f3fSDimitry Andric /// Same here, but only for casts.
27345f757f3fSDimitry Andric inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
27355f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
27360fca6ea1SDimitry Andric 
27370fca6ea1SDimitry Andric   // FIXME: Support diagnosing other invalid cast kinds.
27380fca6ea1SDimitry Andric   if (Kind == CastKind::Reinterpret)
27395f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
27405f757f3fSDimitry Andric         << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
27415f757f3fSDimitry Andric   return false;
27425f757f3fSDimitry Andric }
27435f757f3fSDimitry Andric 
27445f757f3fSDimitry Andric inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
27455f757f3fSDimitry Andric                            const DeclRefExpr *DR) {
27465f757f3fSDimitry Andric   assert(DR);
27475f757f3fSDimitry Andric   return CheckDeclRef(S, OpPC, DR);
27485f757f3fSDimitry Andric }
27495f757f3fSDimitry Andric 
27500fca6ea1SDimitry Andric inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
27510fca6ea1SDimitry Andric   if (S.inConstantContext()) {
27520fca6ea1SDimitry Andric     const SourceRange &ArgRange = S.Current->getRange(OpPC);
27530fca6ea1SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
27540fca6ea1SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
27550fca6ea1SDimitry Andric   }
27560fca6ea1SDimitry Andric   return false;
27570fca6ea1SDimitry Andric }
27580fca6ea1SDimitry Andric 
27590fca6ea1SDimitry Andric inline bool Assume(InterpState &S, CodePtr OpPC) {
27600fca6ea1SDimitry Andric   const auto Val = S.Stk.pop<Boolean>();
27610fca6ea1SDimitry Andric 
27620fca6ea1SDimitry Andric   if (Val)
27630fca6ea1SDimitry Andric     return true;
27640fca6ea1SDimitry Andric 
27650fca6ea1SDimitry Andric   // Else, diagnose.
27660fca6ea1SDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
27670fca6ea1SDimitry Andric   S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
27680fca6ea1SDimitry Andric   return false;
27690fca6ea1SDimitry Andric }
27700fca6ea1SDimitry Andric 
27715f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
27725f757f3fSDimitry Andric inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
27735f757f3fSDimitry Andric   llvm::SmallVector<int64_t> ArrayIndices;
27745f757f3fSDimitry Andric   for (size_t I = 0; I != E->getNumExpressions(); ++I)
27755f757f3fSDimitry Andric     ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
27765f757f3fSDimitry Andric 
27775f757f3fSDimitry Andric   int64_t Result;
27785f757f3fSDimitry Andric   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
27795f757f3fSDimitry Andric     return false;
27805f757f3fSDimitry Andric 
27815f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Result));
27825f757f3fSDimitry Andric 
27835f757f3fSDimitry Andric   return true;
27845f757f3fSDimitry Andric }
27855f757f3fSDimitry Andric 
27860fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
27870fca6ea1SDimitry Andric inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
27880fca6ea1SDimitry Andric   const T &Arg = S.Stk.peek<T>();
27890fca6ea1SDimitry Andric   if (!Arg.isZero())
27900fca6ea1SDimitry Andric     return true;
27910fca6ea1SDimitry Andric 
27920fca6ea1SDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
27930fca6ea1SDimitry Andric   S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
27940fca6ea1SDimitry Andric 
27950fca6ea1SDimitry Andric   return false;
27960fca6ea1SDimitry Andric }
27970fca6ea1SDimitry Andric 
27980fca6ea1SDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
27990fca6ea1SDimitry Andric                        const APSInt &Value);
28000fca6ea1SDimitry Andric 
28010fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
28020fca6ea1SDimitry Andric inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
28030fca6ea1SDimitry Andric   assert(ED);
28040fca6ea1SDimitry Andric   assert(!ED->isFixed());
28050fca6ea1SDimitry Andric   const APSInt Val = S.Stk.peek<T>().toAPSInt();
28060fca6ea1SDimitry Andric 
28070fca6ea1SDimitry Andric   if (S.inConstantContext())
28080fca6ea1SDimitry Andric     diagnoseEnumValue(S, OpPC, ED, Val);
28090fca6ea1SDimitry Andric   return true;
28100fca6ea1SDimitry Andric }
28110fca6ea1SDimitry Andric 
28120fca6ea1SDimitry Andric /// OldPtr -> Integer -> NewPtr.
28130fca6ea1SDimitry Andric template <PrimType TIn, PrimType TOut>
28140fca6ea1SDimitry Andric inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
28150fca6ea1SDimitry Andric   static_assert(isPtrType(TIn) && isPtrType(TOut));
28160fca6ea1SDimitry Andric   using FromT = typename PrimConv<TIn>::T;
28170fca6ea1SDimitry Andric   using ToT = typename PrimConv<TOut>::T;
28180fca6ea1SDimitry Andric 
28190fca6ea1SDimitry Andric   const FromT &OldPtr = S.Stk.pop<FromT>();
28200fca6ea1SDimitry Andric   S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
28210fca6ea1SDimitry Andric   return true;
28220fca6ea1SDimitry Andric }
28230fca6ea1SDimitry Andric 
28240fca6ea1SDimitry Andric inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
28250fca6ea1SDimitry Andric   // An expression E is a core constant expression unless the evaluation of E
28260fca6ea1SDimitry Andric   // would evaluate one of the following: [C++23] - a control flow that passes
28270fca6ea1SDimitry Andric   // through a declaration of a variable with static or thread storage duration
28280fca6ea1SDimitry Andric   // unless that variable is usable in constant expressions.
28290fca6ea1SDimitry Andric   assert(VD->isLocalVarDecl() &&
28300fca6ea1SDimitry Andric          VD->isStaticLocal()); // Checked before emitting this.
28310fca6ea1SDimitry Andric 
28320fca6ea1SDimitry Andric   if (VD == S.EvaluatingDecl)
28330fca6ea1SDimitry Andric     return true;
28340fca6ea1SDimitry Andric 
28350fca6ea1SDimitry Andric   if (!VD->isUsableInConstantExpressions(S.getCtx())) {
28360fca6ea1SDimitry Andric     S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
28370fca6ea1SDimitry Andric         << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
28380fca6ea1SDimitry Andric     return false;
28390fca6ea1SDimitry Andric   }
28400fca6ea1SDimitry Andric   return true;
28410fca6ea1SDimitry Andric }
28420fca6ea1SDimitry Andric 
28430fca6ea1SDimitry Andric inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
28440fca6ea1SDimitry Andric   assert(Desc);
28450fca6ea1SDimitry Andric 
28460fca6ea1SDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
28470fca6ea1SDimitry Andric     return false;
28480fca6ea1SDimitry Andric 
28490fca6ea1SDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
28500fca6ea1SDimitry Andric   Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
28510fca6ea1SDimitry Andric   assert(B);
28520fca6ea1SDimitry Andric 
28530fca6ea1SDimitry Andric   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
28540fca6ea1SDimitry Andric 
28550fca6ea1SDimitry Andric   return true;
28560fca6ea1SDimitry Andric }
28570fca6ea1SDimitry Andric 
28580fca6ea1SDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
28590fca6ea1SDimitry Andric inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
28600fca6ea1SDimitry Andric                    bool IsNoThrow) {
28610fca6ea1SDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
28620fca6ea1SDimitry Andric     return false;
28630fca6ea1SDimitry Andric 
28640fca6ea1SDimitry Andric   SizeT NumElements = S.Stk.pop<SizeT>();
28650fca6ea1SDimitry Andric   if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
28660fca6ea1SDimitry Andric     if (!IsNoThrow)
28670fca6ea1SDimitry Andric       return false;
28680fca6ea1SDimitry Andric 
28690fca6ea1SDimitry Andric     // If this failed and is nothrow, just return a null ptr.
28700fca6ea1SDimitry Andric     S.Stk.push<Pointer>(0, nullptr);
28710fca6ea1SDimitry Andric     return true;
28720fca6ea1SDimitry Andric   }
28730fca6ea1SDimitry Andric 
28740fca6ea1SDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
28750fca6ea1SDimitry Andric   Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
28760fca6ea1SDimitry Andric                                 S.Ctx.getEvalID());
28770fca6ea1SDimitry Andric   assert(B);
28780fca6ea1SDimitry Andric   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
28790fca6ea1SDimitry Andric 
28800fca6ea1SDimitry Andric   return true;
28810fca6ea1SDimitry Andric }
28820fca6ea1SDimitry Andric 
28830fca6ea1SDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
28840fca6ea1SDimitry Andric inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
28850fca6ea1SDimitry Andric                     bool IsNoThrow) {
28860fca6ea1SDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
28870fca6ea1SDimitry Andric     return false;
28880fca6ea1SDimitry Andric 
28890fca6ea1SDimitry Andric   SizeT NumElements = S.Stk.pop<SizeT>();
28900fca6ea1SDimitry Andric   if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
28910fca6ea1SDimitry Andric                       IsNoThrow)) {
28920fca6ea1SDimitry Andric     if (!IsNoThrow)
28930fca6ea1SDimitry Andric       return false;
28940fca6ea1SDimitry Andric 
28950fca6ea1SDimitry Andric     // If this failed and is nothrow, just return a null ptr.
28960fca6ea1SDimitry Andric     S.Stk.push<Pointer>(0, ElementDesc);
28970fca6ea1SDimitry Andric     return true;
28980fca6ea1SDimitry Andric   }
28990fca6ea1SDimitry Andric 
29000fca6ea1SDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
29010fca6ea1SDimitry Andric   Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
29020fca6ea1SDimitry Andric                                 S.Ctx.getEvalID());
29030fca6ea1SDimitry Andric   assert(B);
29040fca6ea1SDimitry Andric 
29050fca6ea1SDimitry Andric   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
29060fca6ea1SDimitry Andric 
29070fca6ea1SDimitry Andric   return true;
29080fca6ea1SDimitry Andric }
29090fca6ea1SDimitry Andric 
29100fca6ea1SDimitry Andric bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
29110fca6ea1SDimitry Andric static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
29120fca6ea1SDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
29130fca6ea1SDimitry Andric     return false;
29140fca6ea1SDimitry Andric 
29150fca6ea1SDimitry Andric   const Expr *Source = nullptr;
29160fca6ea1SDimitry Andric   const Block *BlockToDelete = nullptr;
29170fca6ea1SDimitry Andric   {
29180fca6ea1SDimitry Andric     // Extra scope for this so the block doesn't have this pointer
29190fca6ea1SDimitry Andric     // pointing to it when we destroy it.
29200fca6ea1SDimitry Andric     const Pointer &Ptr = S.Stk.pop<Pointer>();
29210fca6ea1SDimitry Andric 
29220fca6ea1SDimitry Andric     // Deleteing nullptr is always fine.
29230fca6ea1SDimitry Andric     if (Ptr.isZero())
29240fca6ea1SDimitry Andric       return true;
29250fca6ea1SDimitry Andric 
29260fca6ea1SDimitry Andric     if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
29270fca6ea1SDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
29280fca6ea1SDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
29290fca6ea1SDimitry Andric           << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
29300fca6ea1SDimitry Andric       return false;
29310fca6ea1SDimitry Andric     }
29320fca6ea1SDimitry Andric 
29330fca6ea1SDimitry Andric     Source = Ptr.getDeclDesc()->asExpr();
29340fca6ea1SDimitry Andric     BlockToDelete = Ptr.block();
29350fca6ea1SDimitry Andric 
29360fca6ea1SDimitry Andric     if (!CheckDeleteSource(S, OpPC, Source, Ptr))
29370fca6ea1SDimitry Andric       return false;
29380fca6ea1SDimitry Andric   }
29390fca6ea1SDimitry Andric   assert(Source);
29400fca6ea1SDimitry Andric   assert(BlockToDelete);
29410fca6ea1SDimitry Andric 
29420fca6ea1SDimitry Andric   // Invoke destructors before deallocating the memory.
29430fca6ea1SDimitry Andric   if (!RunDestructors(S, OpPC, BlockToDelete))
29440fca6ea1SDimitry Andric     return false;
29450fca6ea1SDimitry Andric 
29460fca6ea1SDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
29470fca6ea1SDimitry Andric   bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
29480fca6ea1SDimitry Andric   const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
29490fca6ea1SDimitry Andric 
29500fca6ea1SDimitry Andric   if (!Allocator.deallocate(Source, BlockToDelete, S)) {
29510fca6ea1SDimitry Andric     // Nothing has been deallocated, this must be a double-delete.
29520fca6ea1SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
29530fca6ea1SDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_double_delete);
29540fca6ea1SDimitry Andric     return false;
29550fca6ea1SDimitry Andric   }
29560fca6ea1SDimitry Andric   return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
29570fca6ea1SDimitry Andric                              BlockDesc, Source);
29580fca6ea1SDimitry Andric }
29590fca6ea1SDimitry Andric 
2960349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2961349cc55cSDimitry Andric // Read opcode arguments
2962349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2963349cc55cSDimitry Andric 
2964bdd1243dSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2965bdd1243dSDimitry Andric   if constexpr (std::is_pointer<T>::value) {
2966349cc55cSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
2967349cc55cSDimitry Andric     return reinterpret_cast<T>(S.P.getNativePointer(ID));
2968bdd1243dSDimitry Andric   } else {
2969bdd1243dSDimitry Andric     return OpPC.read<T>();
2970349cc55cSDimitry Andric   }
2971bdd1243dSDimitry Andric }
2972a7dea167SDimitry Andric 
29735f757f3fSDimitry Andric template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
29745f757f3fSDimitry Andric   Floating F = Floating::deserialize(*OpPC);
29755f757f3fSDimitry Andric   OpPC += align(F.bytesToSerialize());
29765f757f3fSDimitry Andric   return F;
29775f757f3fSDimitry Andric }
29785f757f3fSDimitry Andric 
29790fca6ea1SDimitry Andric template <>
29800fca6ea1SDimitry Andric inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
29810fca6ea1SDimitry Andric                                                     CodePtr &OpPC) {
29820fca6ea1SDimitry Andric   IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
29830fca6ea1SDimitry Andric   OpPC += align(I.bytesToSerialize());
29840fca6ea1SDimitry Andric   return I;
29850fca6ea1SDimitry Andric }
29860fca6ea1SDimitry Andric 
29870fca6ea1SDimitry Andric template <>
29880fca6ea1SDimitry Andric inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
29890fca6ea1SDimitry Andric                                                   CodePtr &OpPC) {
29900fca6ea1SDimitry Andric   IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
29910fca6ea1SDimitry Andric   OpPC += align(I.bytesToSerialize());
29920fca6ea1SDimitry Andric   return I;
29930fca6ea1SDimitry Andric }
29940fca6ea1SDimitry Andric 
2995a7dea167SDimitry Andric } // namespace interp
2996a7dea167SDimitry Andric } // namespace clang
2997a7dea167SDimitry Andric 
2998a7dea167SDimitry Andric #endif
2999