1//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Definition of the interpreter state and entry point.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
15
16#include "../ExprConstShared.h"
17#include "Boolean.h"
18#include "DynamicAllocator.h"
19#include "Floating.h"
20#include "Function.h"
21#include "FunctionPointer.h"
22#include "InterpFrame.h"
23#include "InterpStack.h"
24#include "InterpState.h"
25#include "MemberPointer.h"
26#include "Opcode.h"
27#include "PrimType.h"
28#include "Program.h"
29#include "State.h"
30#include "clang/AST/ASTContext.h"
31#include "clang/AST/Expr.h"
32#include "llvm/ADT/APFloat.h"
33#include "llvm/ADT/APSInt.h"
34#include <type_traits>
35
36namespace clang {
37namespace interp {
38
39using APSInt = llvm::APSInt;
40
41/// Convert a value to an APValue.
42template <typename T>
43bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
44 R = V.toAPValue(S.getCtx());
45 return true;
46}
47
48/// Checks if the variable has externally defined storage.
49bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50
51/// Checks if the array is offsetable.
52bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53
54/// Checks if a pointer is live and accessible.
55bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56 AccessKinds AK);
57
58/// Checks if a pointer is a dummy pointer.
59bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60 AccessKinds AK);
61
62/// Checks if a pointer is null.
63bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 CheckSubobjectKind CSK);
65
66/// Checks if a pointer is in range.
67bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 AccessKinds AK);
69
70/// Checks if a field from which a pointer is going to be derived is valid.
71bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72 CheckSubobjectKind CSK);
73
74/// Checks if Ptr is a one-past-the-end pointer.
75bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76 CheckSubobjectKind CSK);
77
78/// Checks if the dowcast using the given offset is possible with the given
79/// pointer.
80bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
81 uint32_t Offset);
82
83/// Checks if a pointer points to const storage.
84bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86/// Checks if the Descriptor is of a constexpr or const global variable.
87bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
88
89/// Checks if a pointer points to a mutable field.
90bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
91
92/// Checks if a value can be loaded from a block.
93bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
94 AccessKinds AK = AK_Read);
95
96bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
97 AccessKinds AK);
98/// Check if a global variable is initialized.
99bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
100
101/// Checks if a value can be stored in a block.
102bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
103
104/// Checks if a method can be invoked on an object.
105bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
106
107/// Checks if a value can be initialized.
108bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
109
110/// Checks if a method can be called.
111bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
112
113/// Checks if calling the currently active function would exceed
114/// the allowed call depth.
115bool CheckCallDepth(InterpState &S, CodePtr OpPC);
116
117/// Checks the 'this' pointer.
118bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
119
120/// Checks if a method is pure virtual.
121bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
122
123/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
124bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
125 const CallExpr *CE, unsigned ArgSize);
126
127/// Checks if dynamic memory allocation is available in the current
128/// language mode.
129bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
130
131/// Diagnose mismatched new[]/delete or new/delete[] pairs.
132bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
133 bool DeleteIsArray, const Descriptor *D,
134 const Expr *NewExpr);
135
136/// Check the source of the pointer passed to delete/delete[] has actually
137/// been heap allocated by us.
138bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
139 const Pointer &Ptr);
140
141/// Sets the given integral value to the pointer, which is of
142/// a std::{weak,partial,strong}_ordering type.
143bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
144 const Pointer &Ptr, const APSInt &IntValue);
145
146/// Copy the contents of Src into Dest.
147bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
148
149/// Checks if the shift operation is legal.
150template <typename LT, typename RT>
151bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
152 unsigned Bits) {
153 if (RHS.isNegative()) {
154 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
155 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS.toAPSInt();
156 if (!S.noteUndefinedBehavior())
157 return false;
158 }
159
160 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
161 // the shifted type.
162 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
163 const Expr *E = S.Current->getExpr(PC: OpPC);
164 const APSInt Val = RHS.toAPSInt();
165 QualType Ty = E->getType();
166 S.CCEDiag(E, DiagId: diag::note_constexpr_large_shift) << Val << Ty << Bits;
167 if (!S.noteUndefinedBehavior())
168 return false;
169 }
170
171 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
172 const Expr *E = S.Current->getExpr(PC: OpPC);
173 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
174 // operand, and must not overflow the corresponding unsigned type.
175 if (LHS.isNegative()) {
176 S.CCEDiag(E, DiagId: diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
177 if (!S.noteUndefinedBehavior())
178 return false;
179 } else if (LHS.toUnsigned().countLeadingZeros() <
180 static_cast<unsigned>(RHS)) {
181 S.CCEDiag(E, DiagId: diag::note_constexpr_lshift_discards);
182 if (!S.noteUndefinedBehavior())
183 return false;
184 }
185 }
186
187 // C++2a [expr.shift]p2: [P0907R4]:
188 // E1 << E2 is the unique value congruent to
189 // E1 x 2^E2 module 2^N.
190 return true;
191}
192
193/// Checks if Div/Rem operation on LHS and RHS is valid.
194template <typename T>
195bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
196 if (RHS.isZero()) {
197 const auto *Op = cast<BinaryOperator>(Val: S.Current->getExpr(PC: OpPC));
198 if constexpr (std::is_same_v<T, Floating>) {
199 S.CCEDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
200 << Op->getRHS()->getSourceRange();
201 return true;
202 }
203
204 S.FFDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
205 << Op->getRHS()->getSourceRange();
206 return false;
207 }
208
209 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
210 APSInt LHSInt = LHS.toAPSInt();
211 SmallString<32> Trunc;
212 (-LHSInt.extend(width: LHSInt.getBitWidth() + 1)).toString(Str&: Trunc, Radix: 10);
213 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
214 const Expr *E = S.Current->getExpr(PC: OpPC);
215 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_overflow) << Trunc << E->getType();
216 return false;
217 }
218 return true;
219}
220
221template <typename SizeT>
222bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
223 unsigned ElemSize, bool IsNoThrow) {
224 // FIXME: Both the SizeT::from() as well as the
225 // NumElements.toAPSInt() in this function are rather expensive.
226
227 // FIXME: GH63562
228 // APValue stores array extents as unsigned,
229 // so anything that is greater that unsigned would overflow when
230 // constructing the array, we catch this here.
231 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
232 if (NumElements->toAPSInt().getActiveBits() >
233 ConstantArrayType::getMaxSizeBits(Context: S.getCtx()) ||
234 *NumElements > MaxElements) {
235 if (!IsNoThrow) {
236 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
237 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_new_too_large)
238 << NumElements->toDiagnosticString(S.getCtx());
239 }
240 return false;
241 }
242 return true;
243}
244
245/// Checks if the result of a floating-point operation is valid
246/// in the current context.
247bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
248 APFloat::opStatus Status);
249
250/// Checks why the given DeclRefExpr is invalid.
251bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
252
253/// Interpreter entry point.
254bool Interpret(InterpState &S, APValue &Result);
255
256/// Interpret a builtin function.
257bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
258 const CallExpr *Call);
259
260/// Interpret an offsetof operation.
261bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
262 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
263
264inline bool Invalid(InterpState &S, CodePtr OpPC);
265
266enum class ArithOp { Add, Sub };
267
268//===----------------------------------------------------------------------===//
269// Returning values
270//===----------------------------------------------------------------------===//
271
272void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
273
274template <PrimType Name, class T = typename PrimConv<Name>::T>
275bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
276 const T &Ret = S.Stk.pop<T>();
277
278 // Make sure returned pointers are live. We might be trying to return a
279 // pointer or reference to a local variable.
280 // Just return false, since a diagnostic has already been emitted in Sema.
281 if constexpr (std::is_same_v<T, Pointer>) {
282 // FIXME: We could be calling isLive() here, but the emitted diagnostics
283 // seem a little weird, at least if the returned expression is of
284 // pointer type.
285 // Null pointers are considered live here.
286 if (!Ret.isZero() && !Ret.isLive())
287 return false;
288 }
289
290 assert(S.Current);
291 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
292 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
293 cleanupAfterFunctionCall(S, OpPC: PC);
294
295 if (InterpFrame *Caller = S.Current->Caller) {
296 PC = S.Current->getRetPC();
297 delete S.Current;
298 S.Current = Caller;
299 S.Stk.push<T>(Ret);
300 } else {
301 delete S.Current;
302 S.Current = nullptr;
303 if (!ReturnValue<T>(S, Ret, Result))
304 return false;
305 }
306 return true;
307}
308
309inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
310 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
311
312 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
313 cleanupAfterFunctionCall(S, OpPC: PC);
314
315 if (InterpFrame *Caller = S.Current->Caller) {
316 PC = S.Current->getRetPC();
317 delete S.Current;
318 S.Current = Caller;
319 } else {
320 delete S.Current;
321 S.Current = nullptr;
322 }
323 return true;
324}
325
326//===----------------------------------------------------------------------===//
327// Add, Sub, Mul
328//===----------------------------------------------------------------------===//
329
330template <typename T, bool (*OpFW)(T, T, unsigned, T *),
331 template <typename U> class OpAP>
332bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
333 const T &RHS) {
334 // Fast path - add the numbers with fixed width.
335 T Result;
336 if (!OpFW(LHS, RHS, Bits, &Result)) {
337 S.Stk.push<T>(Result);
338 return true;
339 }
340
341 // If for some reason evaluation continues, use the truncated results.
342 S.Stk.push<T>(Result);
343
344 // Slow path - compute the result using another bit of precision.
345 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
346
347 // Report undefined behaviour, stopping if required.
348 const Expr *E = S.Current->getExpr(PC: OpPC);
349 QualType Type = E->getType();
350 if (S.checkingForUndefinedBehavior()) {
351 SmallString<32> Trunc;
352 Value.trunc(width: Result.bitWidth())
353 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
354 /*UpperCase=*/true, /*InsertSeparators=*/true);
355 auto Loc = E->getExprLoc();
356 S.report(Loc, DiagId: diag::warn_integer_constant_overflow)
357 << Trunc << Type << E->getSourceRange();
358 }
359
360 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << Value << Type;
361
362 if (!S.noteUndefinedBehavior()) {
363 S.Stk.pop<T>();
364 return false;
365 }
366
367 return true;
368}
369
370template <PrimType Name, class T = typename PrimConv<Name>::T>
371bool Add(InterpState &S, CodePtr OpPC) {
372 const T &RHS = S.Stk.pop<T>();
373 const T &LHS = S.Stk.pop<T>();
374 const unsigned Bits = RHS.bitWidth() + 1;
375 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
376}
377
378inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
379 const Floating &RHS = S.Stk.pop<Floating>();
380 const Floating &LHS = S.Stk.pop<Floating>();
381
382 Floating Result;
383 auto Status = Floating::add(A: LHS, B: RHS, RM, R: &Result);
384 S.Stk.push<Floating>(Args&: Result);
385 return CheckFloatResult(S, OpPC, Result, Status);
386}
387
388template <PrimType Name, class T = typename PrimConv<Name>::T>
389bool Sub(InterpState &S, CodePtr OpPC) {
390 const T &RHS = S.Stk.pop<T>();
391 const T &LHS = S.Stk.pop<T>();
392 const unsigned Bits = RHS.bitWidth() + 1;
393 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
394}
395
396inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
397 const Floating &RHS = S.Stk.pop<Floating>();
398 const Floating &LHS = S.Stk.pop<Floating>();
399
400 Floating Result;
401 auto Status = Floating::sub(A: LHS, B: RHS, RM, R: &Result);
402 S.Stk.push<Floating>(Args&: Result);
403 return CheckFloatResult(S, OpPC, Result, Status);
404}
405
406template <PrimType Name, class T = typename PrimConv<Name>::T>
407bool Mul(InterpState &S, CodePtr OpPC) {
408 const T &RHS = S.Stk.pop<T>();
409 const T &LHS = S.Stk.pop<T>();
410 const unsigned Bits = RHS.bitWidth() * 2;
411 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
412}
413
414inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
415 const Floating &RHS = S.Stk.pop<Floating>();
416 const Floating &LHS = S.Stk.pop<Floating>();
417
418 Floating Result;
419 auto Status = Floating::mul(A: LHS, B: RHS, RM, R: &Result);
420 S.Stk.push<Floating>(Args&: Result);
421 return CheckFloatResult(S, OpPC, Result, Status);
422}
423
424template <PrimType Name, class T = typename PrimConv<Name>::T>
425inline bool Mulc(InterpState &S, CodePtr OpPC) {
426 const Pointer &RHS = S.Stk.pop<Pointer>();
427 const Pointer &LHS = S.Stk.pop<Pointer>();
428 const Pointer &Result = S.Stk.peek<Pointer>();
429
430 if constexpr (std::is_same_v<T, Floating>) {
431 APFloat A = LHS.atIndex(Idx: 0).deref<Floating>().getAPFloat();
432 APFloat B = LHS.atIndex(Idx: 1).deref<Floating>().getAPFloat();
433 APFloat C = RHS.atIndex(Idx: 0).deref<Floating>().getAPFloat();
434 APFloat D = RHS.atIndex(Idx: 1).deref<Floating>().getAPFloat();
435
436 APFloat ResR(A.getSemantics());
437 APFloat ResI(A.getSemantics());
438 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
439
440 // Copy into the result.
441 Result.atIndex(Idx: 0).deref<Floating>() = Floating(ResR);
442 Result.atIndex(Idx: 0).initialize();
443 Result.atIndex(Idx: 1).deref<Floating>() = Floating(ResI);
444 Result.atIndex(Idx: 1).initialize();
445 Result.initialize();
446 } else {
447 // Integer element type.
448 const T &LHSR = LHS.atIndex(Idx: 0).deref<T>();
449 const T &LHSI = LHS.atIndex(Idx: 1).deref<T>();
450 const T &RHSR = RHS.atIndex(Idx: 0).deref<T>();
451 const T &RHSI = RHS.atIndex(Idx: 1).deref<T>();
452 unsigned Bits = LHSR.bitWidth();
453
454 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
455 T A;
456 if (T::mul(LHSR, RHSR, Bits, &A))
457 return false;
458 T B;
459 if (T::mul(LHSI, RHSI, Bits, &B))
460 return false;
461 if (T::sub(A, B, Bits, &Result.atIndex(Idx: 0).deref<T>()))
462 return false;
463 Result.atIndex(Idx: 0).initialize();
464
465 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
466 if (T::mul(LHSR, RHSI, Bits, &A))
467 return false;
468 if (T::mul(LHSI, RHSR, Bits, &B))
469 return false;
470 if (T::add(A, B, Bits, &Result.atIndex(Idx: 1).deref<T>()))
471 return false;
472 Result.atIndex(Idx: 1).initialize();
473 Result.initialize();
474 }
475
476 return true;
477}
478
479template <PrimType Name, class T = typename PrimConv<Name>::T>
480inline bool Divc(InterpState &S, CodePtr OpPC) {
481 const Pointer &RHS = S.Stk.pop<Pointer>();
482 const Pointer &LHS = S.Stk.pop<Pointer>();
483 const Pointer &Result = S.Stk.peek<Pointer>();
484
485 if constexpr (std::is_same_v<T, Floating>) {
486 APFloat A = LHS.atIndex(Idx: 0).deref<Floating>().getAPFloat();
487 APFloat B = LHS.atIndex(Idx: 1).deref<Floating>().getAPFloat();
488 APFloat C = RHS.atIndex(Idx: 0).deref<Floating>().getAPFloat();
489 APFloat D = RHS.atIndex(Idx: 1).deref<Floating>().getAPFloat();
490
491 APFloat ResR(A.getSemantics());
492 APFloat ResI(A.getSemantics());
493 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
494
495 // Copy into the result.
496 Result.atIndex(Idx: 0).deref<Floating>() = Floating(ResR);
497 Result.atIndex(Idx: 0).initialize();
498 Result.atIndex(Idx: 1).deref<Floating>() = Floating(ResI);
499 Result.atIndex(Idx: 1).initialize();
500 Result.initialize();
501 } else {
502 // Integer element type.
503 const T &LHSR = LHS.atIndex(Idx: 0).deref<T>();
504 const T &LHSI = LHS.atIndex(Idx: 1).deref<T>();
505 const T &RHSR = RHS.atIndex(Idx: 0).deref<T>();
506 const T &RHSI = RHS.atIndex(Idx: 1).deref<T>();
507 unsigned Bits = LHSR.bitWidth();
508 const T Zero = T::from(0, Bits);
509
510 if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
511 Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
512 const SourceInfo &E = S.Current->getSource(PC: OpPC);
513 S.FFDiag(SI: E, DiagId: diag::note_expr_divide_by_zero);
514 return false;
515 }
516
517 // Den = real(RHS)² + imag(RHS)²
518 T A, B;
519 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
520 return false;
521 T Den;
522 if (T::add(A, B, Bits, &Den))
523 return false;
524
525 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
526 T &ResultR = Result.atIndex(Idx: 0).deref<T>();
527 T &ResultI = Result.atIndex(Idx: 1).deref<T>();
528
529 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
530 return false;
531 if (T::add(A, B, Bits, &ResultR))
532 return false;
533 if (T::div(ResultR, Den, Bits, &ResultR))
534 return false;
535 Result.atIndex(Idx: 0).initialize();
536
537 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
538 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
539 return false;
540 if (T::sub(A, B, Bits, &ResultI))
541 return false;
542 if (T::div(ResultI, Den, Bits, &ResultI))
543 return false;
544 Result.atIndex(Idx: 1).initialize();
545 Result.initialize();
546 }
547
548 return true;
549}
550
551/// 1) Pops the RHS from the stack.
552/// 2) Pops the LHS from the stack.
553/// 3) Pushes 'LHS & RHS' on the stack
554template <PrimType Name, class T = typename PrimConv<Name>::T>
555bool BitAnd(InterpState &S, CodePtr OpPC) {
556 const T &RHS = S.Stk.pop<T>();
557 const T &LHS = S.Stk.pop<T>();
558
559 unsigned Bits = RHS.bitWidth();
560 T Result;
561 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
562 S.Stk.push<T>(Result);
563 return true;
564 }
565 return false;
566}
567
568/// 1) Pops the RHS from the stack.
569/// 2) Pops the LHS from the stack.
570/// 3) Pushes 'LHS | RHS' on the stack
571template <PrimType Name, class T = typename PrimConv<Name>::T>
572bool BitOr(InterpState &S, CodePtr OpPC) {
573 const T &RHS = S.Stk.pop<T>();
574 const T &LHS = S.Stk.pop<T>();
575
576 unsigned Bits = RHS.bitWidth();
577 T Result;
578 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
579 S.Stk.push<T>(Result);
580 return true;
581 }
582 return false;
583}
584
585/// 1) Pops the RHS from the stack.
586/// 2) Pops the LHS from the stack.
587/// 3) Pushes 'LHS ^ RHS' on the stack
588template <PrimType Name, class T = typename PrimConv<Name>::T>
589bool BitXor(InterpState &S, CodePtr OpPC) {
590 const T &RHS = S.Stk.pop<T>();
591 const T &LHS = S.Stk.pop<T>();
592
593 unsigned Bits = RHS.bitWidth();
594 T Result;
595 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
596 S.Stk.push<T>(Result);
597 return true;
598 }
599 return false;
600}
601
602/// 1) Pops the RHS from the stack.
603/// 2) Pops the LHS from the stack.
604/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
605template <PrimType Name, class T = typename PrimConv<Name>::T>
606bool Rem(InterpState &S, CodePtr OpPC) {
607 const T &RHS = S.Stk.pop<T>();
608 const T &LHS = S.Stk.pop<T>();
609
610 if (!CheckDivRem(S, OpPC, LHS, RHS))
611 return false;
612
613 const unsigned Bits = RHS.bitWidth() * 2;
614 T Result;
615 if (!T::rem(LHS, RHS, Bits, &Result)) {
616 S.Stk.push<T>(Result);
617 return true;
618 }
619 return false;
620}
621
622/// 1) Pops the RHS from the stack.
623/// 2) Pops the LHS from the stack.
624/// 3) Pushes 'LHS / RHS' on the stack
625template <PrimType Name, class T = typename PrimConv<Name>::T>
626bool Div(InterpState &S, CodePtr OpPC) {
627 const T &RHS = S.Stk.pop<T>();
628 const T &LHS = S.Stk.pop<T>();
629
630 if (!CheckDivRem(S, OpPC, LHS, RHS))
631 return false;
632
633 const unsigned Bits = RHS.bitWidth() * 2;
634 T Result;
635 if (!T::div(LHS, RHS, Bits, &Result)) {
636 S.Stk.push<T>(Result);
637 return true;
638 }
639 return false;
640}
641
642inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
643 const Floating &RHS = S.Stk.pop<Floating>();
644 const Floating &LHS = S.Stk.pop<Floating>();
645
646 if (!CheckDivRem(S, OpPC, LHS, RHS))
647 return false;
648
649 Floating Result;
650 auto Status = Floating::div(A: LHS, B: RHS, RM, R: &Result);
651 S.Stk.push<Floating>(Args&: Result);
652 return CheckFloatResult(S, OpPC, Result, Status);
653}
654
655//===----------------------------------------------------------------------===//
656// Inv
657//===----------------------------------------------------------------------===//
658
659template <PrimType Name, class T = typename PrimConv<Name>::T>
660bool Inv(InterpState &S, CodePtr OpPC) {
661 using BoolT = PrimConv<PT_Bool>::T;
662 const T &Val = S.Stk.pop<T>();
663 const unsigned Bits = Val.bitWidth();
664 Boolean R;
665 Boolean::inv(A: BoolT::from(Val, Bits), R: &R);
666
667 S.Stk.push<BoolT>(Args&: R);
668 return true;
669}
670
671//===----------------------------------------------------------------------===//
672// Neg
673//===----------------------------------------------------------------------===//
674
675template <PrimType Name, class T = typename PrimConv<Name>::T>
676bool Neg(InterpState &S, CodePtr OpPC) {
677 const T &Value = S.Stk.pop<T>();
678 T Result;
679
680 if (!T::neg(Value, &Result)) {
681 S.Stk.push<T>(Result);
682 return true;
683 }
684
685 assert(isIntegralType(Name) &&
686 "don't expect other types to fail at constexpr negation");
687 S.Stk.push<T>(Result);
688
689 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
690 const Expr *E = S.Current->getExpr(PC: OpPC);
691 QualType Type = E->getType();
692
693 if (S.checkingForUndefinedBehavior()) {
694 SmallString<32> Trunc;
695 NegatedValue.trunc(width: Result.bitWidth())
696 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
697 /*UpperCase=*/true, /*InsertSeparators=*/true);
698 auto Loc = E->getExprLoc();
699 S.report(Loc, DiagId: diag::warn_integer_constant_overflow)
700 << Trunc << Type << E->getSourceRange();
701 return true;
702 }
703
704 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << NegatedValue << Type;
705 return S.noteUndefinedBehavior();
706}
707
708enum class PushVal : bool {
709 No,
710 Yes,
711};
712enum class IncDecOp {
713 Inc,
714 Dec,
715};
716
717template <typename T, IncDecOp Op, PushVal DoPush>
718bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
719 assert(!Ptr.isDummy());
720
721 if constexpr (std::is_same_v<T, Boolean>) {
722 if (!S.getLangOpts().CPlusPlus14)
723 return Invalid(S, OpPC);
724 }
725
726 const T &Value = Ptr.deref<T>();
727 T Result;
728
729 if constexpr (DoPush == PushVal::Yes)
730 S.Stk.push<T>(Value);
731
732 if constexpr (Op == IncDecOp::Inc) {
733 if (!T::increment(Value, &Result)) {
734 Ptr.deref<T>() = Result;
735 return true;
736 }
737 } else {
738 if (!T::decrement(Value, &Result)) {
739 Ptr.deref<T>() = Result;
740 return true;
741 }
742 }
743
744 // Something went wrong with the previous operation. Compute the
745 // result with another bit of precision.
746 unsigned Bits = Value.bitWidth() + 1;
747 APSInt APResult;
748 if constexpr (Op == IncDecOp::Inc)
749 APResult = ++Value.toAPSInt(Bits);
750 else
751 APResult = --Value.toAPSInt(Bits);
752
753 // Report undefined behaviour, stopping if required.
754 const Expr *E = S.Current->getExpr(PC: OpPC);
755 QualType Type = E->getType();
756 if (S.checkingForUndefinedBehavior()) {
757 SmallString<32> Trunc;
758 APResult.trunc(width: Result.bitWidth())
759 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
760 /*UpperCase=*/true, /*InsertSeparators=*/true);
761 auto Loc = E->getExprLoc();
762 S.report(Loc, DiagId: diag::warn_integer_constant_overflow)
763 << Trunc << Type << E->getSourceRange();
764 return true;
765 }
766
767 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << APResult << Type;
768 return S.noteUndefinedBehavior();
769}
770
771/// 1) Pops a pointer from the stack
772/// 2) Load the value from the pointer
773/// 3) Writes the value increased by one back to the pointer
774/// 4) Pushes the original (pre-inc) value on the stack.
775template <PrimType Name, class T = typename PrimConv<Name>::T>
776bool Inc(InterpState &S, CodePtr OpPC) {
777 const Pointer &Ptr = S.Stk.pop<Pointer>();
778 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
779 return false;
780
781 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
782}
783
784/// 1) Pops a pointer from the stack
785/// 2) Load the value from the pointer
786/// 3) Writes the value increased by one back to the pointer
787template <PrimType Name, class T = typename PrimConv<Name>::T>
788bool IncPop(InterpState &S, CodePtr OpPC) {
789 const Pointer &Ptr = S.Stk.pop<Pointer>();
790 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
791 return false;
792
793 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
794}
795
796/// 1) Pops a pointer from the stack
797/// 2) Load the value from the pointer
798/// 3) Writes the value decreased by one back to the pointer
799/// 4) Pushes the original (pre-dec) value on the stack.
800template <PrimType Name, class T = typename PrimConv<Name>::T>
801bool Dec(InterpState &S, CodePtr OpPC) {
802 const Pointer &Ptr = S.Stk.pop<Pointer>();
803 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
804 return false;
805
806 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
807}
808
809/// 1) Pops a pointer from the stack
810/// 2) Load the value from the pointer
811/// 3) Writes the value decreased by one back to the pointer
812template <PrimType Name, class T = typename PrimConv<Name>::T>
813bool DecPop(InterpState &S, CodePtr OpPC) {
814 const Pointer &Ptr = S.Stk.pop<Pointer>();
815 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
816 return false;
817
818 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
819}
820
821template <IncDecOp Op, PushVal DoPush>
822bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
823 llvm::RoundingMode RM) {
824 Floating Value = Ptr.deref<Floating>();
825 Floating Result;
826
827 if constexpr (DoPush == PushVal::Yes)
828 S.Stk.push<Floating>(Args&: Value);
829
830 llvm::APFloat::opStatus Status;
831 if constexpr (Op == IncDecOp::Inc)
832 Status = Floating::increment(A: Value, RM, R: &Result);
833 else
834 Status = Floating::decrement(A: Value, RM, R: &Result);
835
836 Ptr.deref<Floating>() = Result;
837
838 return CheckFloatResult(S, OpPC, Result, Status);
839}
840
841inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
842 const Pointer &Ptr = S.Stk.pop<Pointer>();
843 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
844 return false;
845
846 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
847}
848
849inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
850 const Pointer &Ptr = S.Stk.pop<Pointer>();
851 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
852 return false;
853
854 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
855}
856
857inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
858 const Pointer &Ptr = S.Stk.pop<Pointer>();
859 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
860 return false;
861
862 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
863}
864
865inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
866 const Pointer &Ptr = S.Stk.pop<Pointer>();
867 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
868 return false;
869
870 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
871}
872
873/// 1) Pops the value from the stack.
874/// 2) Pushes the bitwise complemented value on the stack (~V).
875template <PrimType Name, class T = typename PrimConv<Name>::T>
876bool Comp(InterpState &S, CodePtr OpPC) {
877 const T &Val = S.Stk.pop<T>();
878 T Result;
879 if (!T::comp(Val, &Result)) {
880 S.Stk.push<T>(Result);
881 return true;
882 }
883
884 return false;
885}
886
887//===----------------------------------------------------------------------===//
888// EQ, NE, GT, GE, LT, LE
889//===----------------------------------------------------------------------===//
890
891using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
892
893template <typename T>
894bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
895 assert((!std::is_same_v<T, MemberPointer>) &&
896 "Non-equality comparisons on member pointer types should already be "
897 "rejected in Sema.");
898 using BoolT = PrimConv<PT_Bool>::T;
899 const T &RHS = S.Stk.pop<T>();
900 const T &LHS = S.Stk.pop<T>();
901 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
902 return true;
903}
904
905template <typename T>
906bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
907 return CmpHelper<T>(S, OpPC, Fn);
908}
909
910/// Function pointers cannot be compared in an ordered way.
911template <>
912inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
913 CompareFn Fn) {
914 const auto &RHS = S.Stk.pop<FunctionPointer>();
915 const auto &LHS = S.Stk.pop<FunctionPointer>();
916
917 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
918 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
919 << LHS.toDiagnosticString(Ctx: S.getCtx())
920 << RHS.toDiagnosticString(Ctx: S.getCtx());
921 return false;
922}
923
924template <>
925inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
926 CompareFn Fn) {
927 const auto &RHS = S.Stk.pop<FunctionPointer>();
928 const auto &LHS = S.Stk.pop<FunctionPointer>();
929
930 // We cannot compare against weak declarations at compile time.
931 for (const auto &FP : {LHS, RHS}) {
932 if (FP.isWeak()) {
933 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
934 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_weak_comparison)
935 << FP.toDiagnosticString(Ctx: S.getCtx());
936 return false;
937 }
938 }
939
940 S.Stk.push<Boolean>(Args: Boolean::from(Value: Fn(LHS.compare(RHS))));
941 return true;
942}
943
944template <>
945inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
946 using BoolT = PrimConv<PT_Bool>::T;
947 const Pointer &RHS = S.Stk.pop<Pointer>();
948 const Pointer &LHS = S.Stk.pop<Pointer>();
949
950 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
951 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
952 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
953 << LHS.toDiagnosticString(Ctx: S.getCtx())
954 << RHS.toDiagnosticString(Ctx: S.getCtx());
955 return false;
956 } else {
957 unsigned VL = LHS.getByteOffset();
958 unsigned VR = RHS.getByteOffset();
959 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: VL, Y: VR))));
960 return true;
961 }
962}
963
964template <>
965inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
966 using BoolT = PrimConv<PT_Bool>::T;
967 const Pointer &RHS = S.Stk.pop<Pointer>();
968 const Pointer &LHS = S.Stk.pop<Pointer>();
969
970 if (LHS.isZero() && RHS.isZero()) {
971 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Equal)));
972 return true;
973 }
974
975 // Reject comparisons to weak pointers.
976 for (const auto &P : {LHS, RHS}) {
977 if (P.isZero())
978 continue;
979 if (P.isWeak()) {
980 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
981 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_weak_comparison)
982 << P.toDiagnosticString(Ctx: S.getCtx());
983 return false;
984 }
985 }
986
987 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
988 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
989 RHS.getOffset() == 0) {
990 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
991 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
992 << LHS.toDiagnosticString(Ctx: S.getCtx());
993 return false;
994 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
995 LHS.getOffset() == 0) {
996 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
997 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
998 << RHS.toDiagnosticString(Ctx: S.getCtx());
999 return false;
1000 }
1001
1002 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Unordered)));
1003 return true;
1004 } else {
1005 unsigned VL = LHS.getByteOffset();
1006 unsigned VR = RHS.getByteOffset();
1007
1008 // In our Pointer class, a pointer to an array and a pointer to the first
1009 // element in the same array are NOT equal. They have the same Base value,
1010 // but a different Offset. This is a pretty rare case, so we fix this here
1011 // by comparing pointers to the first elements.
1012 if (!LHS.isZero() && LHS.isArrayRoot())
1013 VL = LHS.atIndex(Idx: 0).getByteOffset();
1014 if (!RHS.isZero() && RHS.isArrayRoot())
1015 VR = RHS.atIndex(Idx: 0).getByteOffset();
1016
1017 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: VL, Y: VR))));
1018 return true;
1019 }
1020}
1021
1022template <>
1023inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1024 CompareFn Fn) {
1025 const auto &RHS = S.Stk.pop<MemberPointer>();
1026 const auto &LHS = S.Stk.pop<MemberPointer>();
1027
1028 // If either operand is a pointer to a weak function, the comparison is not
1029 // constant.
1030 for (const auto &MP : {LHS, RHS}) {
1031 if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
1032 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1033 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_mem_pointer_weak_comparison) << MD;
1034 return false;
1035 }
1036 }
1037
1038 // C++11 [expr.eq]p2:
1039 // If both operands are null, they compare equal. Otherwise if only one is
1040 // null, they compare unequal.
1041 if (LHS.isZero() && RHS.isZero()) {
1042 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Equal));
1043 return true;
1044 }
1045 if (LHS.isZero() || RHS.isZero()) {
1046 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Unordered));
1047 return true;
1048 }
1049
1050 // We cannot compare against virtual declarations at compile time.
1051 for (const auto &MP : {LHS, RHS}) {
1052 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1053 MD && MD->isVirtual()) {
1054 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1055 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1056 }
1057 }
1058
1059 S.Stk.push<Boolean>(Args: Boolean::from(Value: Fn(LHS.compare(RHS))));
1060 return true;
1061}
1062
1063template <PrimType Name, class T = typename PrimConv<Name>::T>
1064bool EQ(InterpState &S, CodePtr OpPC) {
1065 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1066 return R == ComparisonCategoryResult::Equal;
1067 });
1068}
1069
1070template <PrimType Name, class T = typename PrimConv<Name>::T>
1071bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1072 const T &RHS = S.Stk.pop<T>();
1073 const T &LHS = S.Stk.pop<T>();
1074 const Pointer &P = S.Stk.peek<Pointer>();
1075
1076 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1077 if (CmpResult == ComparisonCategoryResult::Unordered) {
1078 // This should only happen with pointers.
1079 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1080 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1081 << LHS.toDiagnosticString(S.getCtx())
1082 << RHS.toDiagnosticString(S.getCtx());
1083 return false;
1084 }
1085
1086 assert(CmpInfo);
1087 const auto *CmpValueInfo =
1088 CmpInfo->getValueInfo(ValueKind: CmpInfo->makeWeakResult(Res: CmpResult));
1089 assert(CmpValueInfo);
1090 assert(CmpValueInfo->hasValidIntValue());
1091 return SetThreeWayComparisonField(S, OpPC, Ptr: P, IntValue: CmpValueInfo->getIntValue());
1092}
1093
1094template <PrimType Name, class T = typename PrimConv<Name>::T>
1095bool NE(InterpState &S, CodePtr OpPC) {
1096 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1097 return R != ComparisonCategoryResult::Equal;
1098 });
1099}
1100
1101template <PrimType Name, class T = typename PrimConv<Name>::T>
1102bool LT(InterpState &S, CodePtr OpPC) {
1103 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1104 return R == ComparisonCategoryResult::Less;
1105 });
1106}
1107
1108template <PrimType Name, class T = typename PrimConv<Name>::T>
1109bool LE(InterpState &S, CodePtr OpPC) {
1110 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1111 return R == ComparisonCategoryResult::Less ||
1112 R == ComparisonCategoryResult::Equal;
1113 });
1114}
1115
1116template <PrimType Name, class T = typename PrimConv<Name>::T>
1117bool GT(InterpState &S, CodePtr OpPC) {
1118 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1119 return R == ComparisonCategoryResult::Greater;
1120 });
1121}
1122
1123template <PrimType Name, class T = typename PrimConv<Name>::T>
1124bool GE(InterpState &S, CodePtr OpPC) {
1125 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1126 return R == ComparisonCategoryResult::Greater ||
1127 R == ComparisonCategoryResult::Equal;
1128 });
1129}
1130
1131//===----------------------------------------------------------------------===//
1132// InRange
1133//===----------------------------------------------------------------------===//
1134
1135template <PrimType Name, class T = typename PrimConv<Name>::T>
1136bool InRange(InterpState &S, CodePtr OpPC) {
1137 const T RHS = S.Stk.pop<T>();
1138 const T LHS = S.Stk.pop<T>();
1139 const T Value = S.Stk.pop<T>();
1140
1141 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1142 return true;
1143}
1144
1145//===----------------------------------------------------------------------===//
1146// Dup, Pop, Test
1147//===----------------------------------------------------------------------===//
1148
1149template <PrimType Name, class T = typename PrimConv<Name>::T>
1150bool Dup(InterpState &S, CodePtr OpPC) {
1151 S.Stk.push<T>(S.Stk.peek<T>());
1152 return true;
1153}
1154
1155template <PrimType Name, class T = typename PrimConv<Name>::T>
1156bool Pop(InterpState &S, CodePtr OpPC) {
1157 S.Stk.pop<T>();
1158 return true;
1159}
1160
1161//===----------------------------------------------------------------------===//
1162// Const
1163//===----------------------------------------------------------------------===//
1164
1165template <PrimType Name, class T = typename PrimConv<Name>::T>
1166bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1167 S.Stk.push<T>(Arg);
1168 return true;
1169}
1170
1171//===----------------------------------------------------------------------===//
1172// Get/Set Local/Param/Global/This
1173//===----------------------------------------------------------------------===//
1174
1175template <PrimType Name, class T = typename PrimConv<Name>::T>
1176bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1177 const Pointer &Ptr = S.Current->getLocalPointer(Offset: I);
1178 if (!CheckLoad(S, OpPC, Ptr))
1179 return false;
1180 S.Stk.push<T>(Ptr.deref<T>());
1181 return true;
1182}
1183
1184/// 1) Pops the value from the stack.
1185/// 2) Writes the value to the local variable with the
1186/// given offset.
1187template <PrimType Name, class T = typename PrimConv<Name>::T>
1188bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1189 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1190 return true;
1191}
1192
1193template <PrimType Name, class T = typename PrimConv<Name>::T>
1194bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1195 if (S.checkingPotentialConstantExpression()) {
1196 return false;
1197 }
1198 S.Stk.push<T>(S.Current->getParam<T>(I));
1199 return true;
1200}
1201
1202template <PrimType Name, class T = typename PrimConv<Name>::T>
1203bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1204 S.Current->setParam<T>(I, S.Stk.pop<T>());
1205 return true;
1206}
1207
1208/// 1) Peeks a pointer on the stack
1209/// 2) Pushes the value of the pointer's field on the stack
1210template <PrimType Name, class T = typename PrimConv<Name>::T>
1211bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1212 const Pointer &Obj = S.Stk.peek<Pointer>();
1213 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1214 return false;
1215 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1216 return false;
1217 const Pointer &Field = Obj.atField(Off: I);
1218 if (!CheckLoad(S, OpPC, Ptr: Field))
1219 return false;
1220 S.Stk.push<T>(Field.deref<T>());
1221 return true;
1222}
1223
1224template <PrimType Name, class T = typename PrimConv<Name>::T>
1225bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1226 const T &Value = S.Stk.pop<T>();
1227 const Pointer &Obj = S.Stk.peek<Pointer>();
1228 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1229 return false;
1230 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1231 return false;
1232 const Pointer &Field = Obj.atField(Off: I);
1233 if (!CheckStore(S, OpPC, Ptr: Field))
1234 return false;
1235 Field.initialize();
1236 Field.deref<T>() = Value;
1237 return true;
1238}
1239
1240/// 1) Pops a pointer from the stack
1241/// 2) Pushes the value of the pointer's field on the stack
1242template <PrimType Name, class T = typename PrimConv<Name>::T>
1243bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1244 const Pointer &Obj = S.Stk.pop<Pointer>();
1245 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1246 return false;
1247 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1248 return false;
1249 const Pointer &Field = Obj.atField(Off: I);
1250 if (!CheckLoad(S, OpPC, Ptr: Field))
1251 return false;
1252 S.Stk.push<T>(Field.deref<T>());
1253 return true;
1254}
1255
1256template <PrimType Name, class T = typename PrimConv<Name>::T>
1257bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1258 if (S.checkingPotentialConstantExpression())
1259 return false;
1260 const Pointer &This = S.Current->getThis();
1261 if (!CheckThis(S, OpPC, This))
1262 return false;
1263 const Pointer &Field = This.atField(Off: I);
1264 if (!CheckLoad(S, OpPC, Ptr: Field))
1265 return false;
1266 S.Stk.push<T>(Field.deref<T>());
1267 return true;
1268}
1269
1270template <PrimType Name, class T = typename PrimConv<Name>::T>
1271bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1272 if (S.checkingPotentialConstantExpression())
1273 return false;
1274 const T &Value = S.Stk.pop<T>();
1275 const Pointer &This = S.Current->getThis();
1276 if (!CheckThis(S, OpPC, This))
1277 return false;
1278 const Pointer &Field = This.atField(Off: I);
1279 if (!CheckStore(S, OpPC, Ptr: Field))
1280 return false;
1281 Field.deref<T>() = Value;
1282 return true;
1283}
1284
1285template <PrimType Name, class T = typename PrimConv<Name>::T>
1286bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1287 const Pointer &Ptr = S.P.getPtrGlobal(Idx: I);
1288 if (!CheckConstant(S, OpPC, Desc: Ptr.getFieldDesc()))
1289 return false;
1290 if (Ptr.isExtern())
1291 return false;
1292
1293 // If a global variable is uninitialized, that means the initializer we've
1294 // compiled for it wasn't a constant expression. Diagnose that.
1295 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1296 return false;
1297
1298 S.Stk.push<T>(Ptr.deref<T>());
1299 return true;
1300}
1301
1302/// Same as GetGlobal, but without the checks.
1303template <PrimType Name, class T = typename PrimConv<Name>::T>
1304bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1305 const Pointer &Ptr = S.P.getPtrGlobal(Idx: I);
1306 if (!Ptr.isInitialized())
1307 return false;
1308 S.Stk.push<T>(Ptr.deref<T>());
1309 return true;
1310}
1311
1312template <PrimType Name, class T = typename PrimConv<Name>::T>
1313bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1314 // TODO: emit warning.
1315 return false;
1316}
1317
1318template <PrimType Name, class T = typename PrimConv<Name>::T>
1319bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1320 const Pointer &P = S.P.getGlobal(Idx: I);
1321 P.deref<T>() = S.Stk.pop<T>();
1322 P.initialize();
1323 return true;
1324}
1325
1326/// 1) Converts the value on top of the stack to an APValue
1327/// 2) Sets that APValue on \Temp
1328/// 3) Initializes global with index \I with that
1329template <PrimType Name, class T = typename PrimConv<Name>::T>
1330bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1331 const LifetimeExtendedTemporaryDecl *Temp) {
1332 const Pointer &Ptr = S.P.getGlobal(Idx: I);
1333
1334 const T Value = S.Stk.peek<T>();
1335 APValue APV = Value.toAPValue(S.getCtx());
1336 APValue *Cached = Temp->getOrCreateValue(MayCreate: true);
1337 *Cached = APV;
1338
1339 assert(Ptr.getDeclDesc()->asExpr());
1340
1341 S.SeenGlobalTemporaries.push_back(
1342 Elt: std::make_pair(x: Ptr.getDeclDesc()->asExpr(), y&: Temp));
1343
1344 Ptr.deref<T>() = S.Stk.pop<T>();
1345 Ptr.initialize();
1346 return true;
1347}
1348
1349/// 1) Converts the value on top of the stack to an APValue
1350/// 2) Sets that APValue on \Temp
1351/// 3) Initialized global with index \I with that
1352inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1353 const LifetimeExtendedTemporaryDecl *Temp) {
1354 assert(Temp);
1355 const Pointer &P = S.Stk.peek<Pointer>();
1356 APValue *Cached = Temp->getOrCreateValue(MayCreate: true);
1357
1358 S.SeenGlobalTemporaries.push_back(
1359 Elt: std::make_pair(x: P.getDeclDesc()->asExpr(), y&: Temp));
1360
1361 if (std::optional<APValue> APV =
1362 P.toRValue(Ctx: S.getCtx(), ResultType: Temp->getTemporaryExpr()->getType())) {
1363 *Cached = *APV;
1364 return true;
1365 }
1366
1367 return false;
1368}
1369
1370template <PrimType Name, class T = typename PrimConv<Name>::T>
1371bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1372 if (S.checkingPotentialConstantExpression())
1373 return false;
1374 const Pointer &This = S.Current->getThis();
1375 if (!CheckThis(S, OpPC, This))
1376 return false;
1377 const Pointer &Field = This.atField(Off: I);
1378 Field.deref<T>() = S.Stk.pop<T>();
1379 Field.initialize();
1380 return true;
1381}
1382
1383// FIXME: The Field pointer here is too much IMO and we could instead just
1384// pass an Offset + BitWidth pair.
1385template <PrimType Name, class T = typename PrimConv<Name>::T>
1386bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1387 uint32_t FieldOffset) {
1388 assert(F->isBitField());
1389 if (S.checkingPotentialConstantExpression())
1390 return false;
1391 const Pointer &This = S.Current->getThis();
1392 if (!CheckThis(S, OpPC, This))
1393 return false;
1394 const Pointer &Field = This.atField(Off: FieldOffset);
1395 const auto &Value = S.Stk.pop<T>();
1396 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(Ctx: S.getCtx()));
1397 Field.initialize();
1398 return true;
1399}
1400
1401template <PrimType Name, class T = typename PrimConv<Name>::T>
1402bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1403 if (S.checkingPotentialConstantExpression())
1404 return false;
1405 const Pointer &This = S.Current->getThis();
1406 if (!CheckThis(S, OpPC, This))
1407 return false;
1408 const Pointer &Field = This.atField(Off: I);
1409 Field.deref<T>() = S.Stk.pop<T>();
1410 Field.activate();
1411 Field.initialize();
1412 return true;
1413}
1414
1415/// 1) Pops the value from the stack
1416/// 2) Peeks a pointer from the stack
1417/// 3) Pushes the value to field I of the pointer on the stack
1418template <PrimType Name, class T = typename PrimConv<Name>::T>
1419bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1420 const T &Value = S.Stk.pop<T>();
1421 const Pointer &Field = S.Stk.peek<Pointer>().atField(Off: I);
1422 Field.deref<T>() = Value;
1423 Field.activate();
1424 Field.initialize();
1425 return true;
1426}
1427
1428template <PrimType Name, class T = typename PrimConv<Name>::T>
1429bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1430 assert(F->isBitField());
1431 const T &Value = S.Stk.pop<T>();
1432 const Pointer &Field = S.Stk.peek<Pointer>().atField(Off: F->Offset);
1433 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(Ctx: S.getCtx()));
1434 Field.activate();
1435 Field.initialize();
1436 return true;
1437}
1438
1439template <PrimType Name, class T = typename PrimConv<Name>::T>
1440bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1441 const T &Value = S.Stk.pop<T>();
1442 const Pointer &Ptr = S.Stk.pop<Pointer>();
1443 const Pointer &Field = Ptr.atField(Off: I);
1444 Field.deref<T>() = Value;
1445 Field.activate();
1446 Field.initialize();
1447 return true;
1448}
1449
1450//===----------------------------------------------------------------------===//
1451// GetPtr Local/Param/Global/Field/This
1452//===----------------------------------------------------------------------===//
1453
1454inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1455 S.Stk.push<Pointer>(Args: S.Current->getLocalPointer(Offset: I));
1456 return true;
1457}
1458
1459inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1460 if (S.checkingPotentialConstantExpression()) {
1461 return false;
1462 }
1463 S.Stk.push<Pointer>(Args: S.Current->getParamPointer(Offset: I));
1464 return true;
1465}
1466
1467inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1468 S.Stk.push<Pointer>(Args: S.P.getPtrGlobal(Idx: I));
1469 return true;
1470}
1471
1472/// 1) Peeks a Pointer
1473/// 2) Pushes Pointer.atField(Off) on the stack
1474inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1475 const Pointer &Ptr = S.Stk.peek<Pointer>();
1476
1477 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1478 !CheckNull(S, OpPC, Ptr, CSK: CSK_Field))
1479 return false;
1480
1481 if (!CheckExtern(S, OpPC, Ptr))
1482 return false;
1483 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1484 return false;
1485 if (!CheckArray(S, OpPC, Ptr))
1486 return false;
1487 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Field))
1488 return false;
1489
1490 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1491 return false;
1492 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1493 return true;
1494}
1495
1496inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1497 const Pointer &Ptr = S.Stk.pop<Pointer>();
1498
1499 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1500 !CheckNull(S, OpPC, Ptr, CSK: CSK_Field))
1501 return false;
1502
1503 if (!CheckExtern(S, OpPC, Ptr))
1504 return false;
1505 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1506 return false;
1507 if (!CheckArray(S, OpPC, Ptr))
1508 return false;
1509 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Field))
1510 return false;
1511
1512 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1513 return false;
1514
1515 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1516 return true;
1517}
1518
1519inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1520 if (S.checkingPotentialConstantExpression())
1521 return false;
1522 const Pointer &This = S.Current->getThis();
1523 if (!CheckThis(S, OpPC, This))
1524 return false;
1525 S.Stk.push<Pointer>(Args: This.atField(Off));
1526 return true;
1527}
1528
1529inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1530 const Pointer &Ptr = S.Stk.pop<Pointer>();
1531 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Field))
1532 return false;
1533 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1534 return false;
1535 Pointer Field = Ptr.atField(Off);
1536 Ptr.deactivate();
1537 Field.activate();
1538 S.Stk.push<Pointer>(Args: std::move(Field));
1539 return true;
1540}
1541
1542inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1543 if (S.checkingPotentialConstantExpression())
1544 return false;
1545 const Pointer &This = S.Current->getThis();
1546 if (!CheckThis(S, OpPC, This))
1547 return false;
1548 Pointer Field = This.atField(Off);
1549 This.deactivate();
1550 Field.activate();
1551 S.Stk.push<Pointer>(Args: std::move(Field));
1552 return true;
1553}
1554
1555inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1556 const Pointer &Ptr = S.Stk.pop<Pointer>();
1557 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Derived))
1558 return false;
1559 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Derived))
1560 return false;
1561 if (!CheckDowncast(S, OpPC, Ptr, Offset: Off))
1562 return false;
1563
1564 S.Stk.push<Pointer>(Args: Ptr.atFieldSub(Off));
1565 return true;
1566}
1567
1568inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1569 const Pointer &Ptr = S.Stk.peek<Pointer>();
1570 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1571 return false;
1572 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1573 return false;
1574 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1575 return true;
1576}
1577
1578inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1579 const Pointer &Ptr = S.Stk.pop<Pointer>();
1580 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1581 return false;
1582 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1583 return false;
1584 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1585 return true;
1586}
1587
1588inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1589 const auto &Ptr = S.Stk.pop<MemberPointer>();
1590 S.Stk.push<MemberPointer>(Args: Ptr.atInstanceBase(Offset: Off));
1591 return true;
1592}
1593
1594inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1595 if (S.checkingPotentialConstantExpression())
1596 return false;
1597 const Pointer &This = S.Current->getThis();
1598 if (!CheckThis(S, OpPC, This))
1599 return false;
1600 S.Stk.push<Pointer>(Args: This.atField(Off));
1601 return true;
1602}
1603
1604inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1605 const Pointer &Ptr = S.Stk.pop<Pointer>();
1606 if (Ptr.canBeInitialized()) {
1607 Ptr.initialize();
1608 Ptr.activate();
1609 }
1610 return true;
1611}
1612
1613inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1614 const Pointer &Ptr = S.Stk.peek<Pointer>();
1615 if (Ptr.canBeInitialized()) {
1616 Ptr.initialize();
1617 Ptr.activate();
1618 }
1619 return true;
1620}
1621
1622inline bool Dump(InterpState &S, CodePtr OpPC) {
1623 S.Stk.dump();
1624 return true;
1625}
1626
1627inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1628 const Pointer &Ptr) {
1629 Pointer Base = Ptr;
1630 while (Base.isBaseClass())
1631 Base = Base.getBase();
1632
1633 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(RD: Decl);
1634 S.Stk.push<Pointer>(Args: Base.atField(Off: VirtBase->Offset));
1635 return true;
1636}
1637
1638inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
1639 const RecordDecl *D) {
1640 assert(D);
1641 const Pointer &Ptr = S.Stk.pop<Pointer>();
1642 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1643 return false;
1644 return VirtBaseHelper(S, OpPC, Decl: D, Ptr);
1645}
1646
1647inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1648 const RecordDecl *D) {
1649 assert(D);
1650 if (S.checkingPotentialConstantExpression())
1651 return false;
1652 const Pointer &This = S.Current->getThis();
1653 if (!CheckThis(S, OpPC, This))
1654 return false;
1655 return VirtBaseHelper(S, OpPC, Decl: D, Ptr: S.Current->getThis());
1656}
1657
1658//===----------------------------------------------------------------------===//
1659// Load, Store, Init
1660//===----------------------------------------------------------------------===//
1661
1662template <PrimType Name, class T = typename PrimConv<Name>::T>
1663bool Load(InterpState &S, CodePtr OpPC) {
1664 const Pointer &Ptr = S.Stk.peek<Pointer>();
1665 if (!CheckLoad(S, OpPC, Ptr))
1666 return false;
1667 if (!Ptr.isBlockPointer())
1668 return false;
1669 S.Stk.push<T>(Ptr.deref<T>());
1670 return true;
1671}
1672
1673template <PrimType Name, class T = typename PrimConv<Name>::T>
1674bool LoadPop(InterpState &S, CodePtr OpPC) {
1675 const Pointer &Ptr = S.Stk.pop<Pointer>();
1676 if (!CheckLoad(S, OpPC, Ptr))
1677 return false;
1678 if (!Ptr.isBlockPointer())
1679 return false;
1680 S.Stk.push<T>(Ptr.deref<T>());
1681 return true;
1682}
1683
1684template <PrimType Name, class T = typename PrimConv<Name>::T>
1685bool Store(InterpState &S, CodePtr OpPC) {
1686 const T &Value = S.Stk.pop<T>();
1687 const Pointer &Ptr = S.Stk.peek<Pointer>();
1688 if (!CheckStore(S, OpPC, Ptr))
1689 return false;
1690 if (Ptr.canBeInitialized())
1691 Ptr.initialize();
1692 Ptr.deref<T>() = Value;
1693 return true;
1694}
1695
1696template <PrimType Name, class T = typename PrimConv<Name>::T>
1697bool StorePop(InterpState &S, CodePtr OpPC) {
1698 const T &Value = S.Stk.pop<T>();
1699 const Pointer &Ptr = S.Stk.pop<Pointer>();
1700 if (!CheckStore(S, OpPC, Ptr))
1701 return false;
1702 if (Ptr.canBeInitialized())
1703 Ptr.initialize();
1704 Ptr.deref<T>() = Value;
1705 return true;
1706}
1707
1708template <PrimType Name, class T = typename PrimConv<Name>::T>
1709bool StoreBitField(InterpState &S, CodePtr OpPC) {
1710 const T &Value = S.Stk.pop<T>();
1711 const Pointer &Ptr = S.Stk.peek<Pointer>();
1712 if (!CheckStore(S, OpPC, Ptr))
1713 return false;
1714 if (Ptr.canBeInitialized())
1715 Ptr.initialize();
1716 if (const auto *FD = Ptr.getField())
1717 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(Ctx: S.getCtx()));
1718 else
1719 Ptr.deref<T>() = Value;
1720 return true;
1721}
1722
1723template <PrimType Name, class T = typename PrimConv<Name>::T>
1724bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1725 const T &Value = S.Stk.pop<T>();
1726 const Pointer &Ptr = S.Stk.pop<Pointer>();
1727 if (!CheckStore(S, OpPC, Ptr))
1728 return false;
1729 if (Ptr.canBeInitialized())
1730 Ptr.initialize();
1731 if (const auto *FD = Ptr.getField())
1732 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(Ctx: S.getCtx()));
1733 else
1734 Ptr.deref<T>() = Value;
1735 return true;
1736}
1737
1738template <PrimType Name, class T = typename PrimConv<Name>::T>
1739bool Init(InterpState &S, CodePtr OpPC) {
1740 const T &Value = S.Stk.pop<T>();
1741 const Pointer &Ptr = S.Stk.peek<Pointer>();
1742 if (!CheckInit(S, OpPC, Ptr)) {
1743 assert(false);
1744 return false;
1745 }
1746 Ptr.initialize();
1747 new (&Ptr.deref<T>()) T(Value);
1748 return true;
1749}
1750
1751template <PrimType Name, class T = typename PrimConv<Name>::T>
1752bool InitPop(InterpState &S, CodePtr OpPC) {
1753 const T &Value = S.Stk.pop<T>();
1754 const Pointer &Ptr = S.Stk.pop<Pointer>();
1755 if (!CheckInit(S, OpPC, Ptr))
1756 return false;
1757 Ptr.initialize();
1758 new (&Ptr.deref<T>()) T(Value);
1759 return true;
1760}
1761
1762/// 1) Pops the value from the stack
1763/// 2) Peeks a pointer and gets its index \Idx
1764/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1765template <PrimType Name, class T = typename PrimConv<Name>::T>
1766bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1767 const T &Value = S.Stk.pop<T>();
1768 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1769 if (Ptr.isUnknownSizeArray())
1770 return false;
1771 if (!CheckInit(S, OpPC, Ptr))
1772 return false;
1773 Ptr.initialize();
1774 new (&Ptr.deref<T>()) T(Value);
1775 return true;
1776}
1777
1778/// The same as InitElem, but pops the pointer as well.
1779template <PrimType Name, class T = typename PrimConv<Name>::T>
1780bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1781 const T &Value = S.Stk.pop<T>();
1782 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1783 if (Ptr.isUnknownSizeArray())
1784 return false;
1785 if (!CheckInit(S, OpPC, Ptr))
1786 return false;
1787 Ptr.initialize();
1788 new (&Ptr.deref<T>()) T(Value);
1789 return true;
1790}
1791
1792inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1793 const Pointer &Src = S.Stk.pop<Pointer>();
1794 Pointer &Dest = S.Stk.peek<Pointer>();
1795
1796 if (!CheckLoad(S, OpPC, Ptr: Src))
1797 return false;
1798
1799 return DoMemcpy(S, OpPC, Src, Dest);
1800}
1801
1802inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1803 const auto &Member = S.Stk.pop<MemberPointer>();
1804 const auto &Base = S.Stk.pop<Pointer>();
1805
1806 S.Stk.push<MemberPointer>(Args: Member.takeInstance(Instance: Base));
1807 return true;
1808}
1809
1810inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1811 const auto &MP = S.Stk.pop<MemberPointer>();
1812
1813 if (std::optional<Pointer> Ptr = MP.toPointer(Ctx: S.Ctx)) {
1814 S.Stk.push<Pointer>(Args&: *Ptr);
1815 return true;
1816 }
1817 return false;
1818}
1819
1820//===----------------------------------------------------------------------===//
1821// AddOffset, SubOffset
1822//===----------------------------------------------------------------------===//
1823
1824template <class T, ArithOp Op>
1825bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1826 const Pointer &Ptr) {
1827 // A zero offset does not change the pointer.
1828 if (Offset.isZero()) {
1829 S.Stk.push<Pointer>(Args: Ptr);
1830 return true;
1831 }
1832
1833 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_ArrayIndex)) {
1834 // The CheckNull will have emitted a note already, but we only
1835 // abort in C++, since this is fine in C.
1836 if (S.getLangOpts().CPlusPlus)
1837 return false;
1838 }
1839
1840 // Arrays of unknown bounds cannot have pointers into them.
1841 if (!CheckArray(S, OpPC, Ptr))
1842 return false;
1843
1844 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1845 uint64_t Index;
1846 if (Ptr.isOnePastEnd())
1847 Index = MaxIndex;
1848 else
1849 Index = Ptr.getIndex();
1850
1851 bool Invalid = false;
1852 // Helper to report an invalid offset, computed as APSInt.
1853 auto DiagInvalidOffset = [&]() -> void {
1854 const unsigned Bits = Offset.bitWidth();
1855 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1856 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1857 /*IsUnsigned=*/false);
1858 APSInt NewIndex =
1859 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1860 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_array_index)
1861 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1862 Invalid = true;
1863 };
1864
1865 if (Ptr.isBlockPointer()) {
1866 uint64_t IOffset = static_cast<uint64_t>(Offset);
1867 uint64_t MaxOffset = MaxIndex - Index;
1868
1869 if constexpr (Op == ArithOp::Add) {
1870 // If the new offset would be negative, bail out.
1871 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1872 DiagInvalidOffset();
1873
1874 // If the new offset would be out of bounds, bail out.
1875 if (Offset.isPositive() && IOffset > MaxOffset)
1876 DiagInvalidOffset();
1877 } else {
1878 // If the new offset would be negative, bail out.
1879 if (Offset.isPositive() && Index < IOffset)
1880 DiagInvalidOffset();
1881
1882 // If the new offset would be out of bounds, bail out.
1883 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1884 DiagInvalidOffset();
1885 }
1886 }
1887
1888 if (Invalid && S.getLangOpts().CPlusPlus)
1889 return false;
1890
1891 // Offset is valid - compute it on unsigned.
1892 int64_t WideIndex = static_cast<int64_t>(Index);
1893 int64_t WideOffset = static_cast<int64_t>(Offset);
1894 int64_t Result;
1895 if constexpr (Op == ArithOp::Add)
1896 Result = WideIndex + WideOffset;
1897 else
1898 Result = WideIndex - WideOffset;
1899
1900 // When the pointer is one-past-end, going back to index 0 is the only
1901 // useful thing we can do. Any other index has been diagnosed before and
1902 // we don't get here.
1903 if (Result == 0 && Ptr.isOnePastEnd()) {
1904 S.Stk.push<Pointer>(Args: Ptr.asBlockPointer().Pointee,
1905 Args: Ptr.asBlockPointer().Base);
1906 return true;
1907 }
1908
1909 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: static_cast<uint64_t>(Result)));
1910 return true;
1911}
1912
1913template <PrimType Name, class T = typename PrimConv<Name>::T>
1914bool AddOffset(InterpState &S, CodePtr OpPC) {
1915 const T &Offset = S.Stk.pop<T>();
1916 const Pointer &Ptr = S.Stk.pop<Pointer>();
1917 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1918}
1919
1920template <PrimType Name, class T = typename PrimConv<Name>::T>
1921bool SubOffset(InterpState &S, CodePtr OpPC) {
1922 const T &Offset = S.Stk.pop<T>();
1923 const Pointer &Ptr = S.Stk.pop<Pointer>();
1924 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1925}
1926
1927template <ArithOp Op>
1928static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1929 const Pointer &Ptr) {
1930 if (Ptr.isDummy())
1931 return false;
1932
1933 using OneT = Integral<8, false>;
1934
1935 const Pointer &P = Ptr.deref<Pointer>();
1936 if (!CheckNull(S, OpPC, Ptr: P, CSK: CSK_ArrayIndex))
1937 return false;
1938
1939 // Get the current value on the stack.
1940 S.Stk.push<Pointer>(Args: P);
1941
1942 // Now the current Ptr again and a constant 1.
1943 OneT One = OneT::from(Value: 1);
1944 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1945 return false;
1946
1947 // Store the new value.
1948 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1949 return true;
1950}
1951
1952static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1953 const Pointer &Ptr = S.Stk.pop<Pointer>();
1954
1955 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
1956 return false;
1957
1958 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1959}
1960
1961static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1962 const Pointer &Ptr = S.Stk.pop<Pointer>();
1963
1964 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
1965 return false;
1966
1967 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1968}
1969
1970/// 1) Pops a Pointer from the stack.
1971/// 2) Pops another Pointer from the stack.
1972/// 3) Pushes the different of the indices of the two pointers on the stack.
1973template <PrimType Name, class T = typename PrimConv<Name>::T>
1974inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1975 const Pointer &LHS = S.Stk.pop<Pointer>();
1976 const Pointer &RHS = S.Stk.pop<Pointer>();
1977
1978 if (RHS.isZero()) {
1979 S.Stk.push<T>(T::from(LHS.getIndex()));
1980 return true;
1981 }
1982
1983 if (!Pointer::hasSameBase(A: LHS, B: RHS) && S.getLangOpts().CPlusPlus) {
1984 // TODO: Diagnose.
1985 return false;
1986 }
1987
1988 if (LHS.isZero() && RHS.isZero()) {
1989 S.Stk.push<T>();
1990 return true;
1991 }
1992
1993 T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
1994 : T::from(LHS.getIndex());
1995 T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
1996 : T::from(RHS.getIndex());
1997 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1998}
1999
2000//===----------------------------------------------------------------------===//
2001// Destroy
2002//===----------------------------------------------------------------------===//
2003
2004inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2005 S.Current->destroy(Idx: I);
2006 return true;
2007}
2008
2009//===----------------------------------------------------------------------===//
2010// Cast, CastFP
2011//===----------------------------------------------------------------------===//
2012
2013template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2014 using T = typename PrimConv<TIn>::T;
2015 using U = typename PrimConv<TOut>::T;
2016 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2017 return true;
2018}
2019
2020/// 1) Pops a Floating from the stack.
2021/// 2) Pushes a new floating on the stack that uses the given semantics.
2022inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2023 llvm::RoundingMode RM) {
2024 Floating F = S.Stk.pop<Floating>();
2025 Floating Result = F.toSemantics(Sem, RM);
2026 S.Stk.push<Floating>(Args&: Result);
2027 return true;
2028}
2029
2030/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2031/// to know what bitwidth the result should be.
2032template <PrimType Name, class T = typename PrimConv<Name>::T>
2033bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2034 S.Stk.push<IntegralAP<false>>(
2035 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2036 return true;
2037}
2038
2039template <PrimType Name, class T = typename PrimConv<Name>::T>
2040bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2041 S.Stk.push<IntegralAP<true>>(
2042 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2043 return true;
2044}
2045
2046template <PrimType Name, class T = typename PrimConv<Name>::T>
2047bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
2048 const llvm::fltSemantics *Sem,
2049 llvm::RoundingMode RM) {
2050 const T &From = S.Stk.pop<T>();
2051 APSInt FromAP = From.toAPSInt();
2052 Floating Result;
2053
2054 auto Status = Floating::fromIntegral(Val: FromAP, Sem: *Sem, RM, Result);
2055 S.Stk.push<Floating>(Args&: Result);
2056
2057 return CheckFloatResult(S, OpPC, Result, Status);
2058}
2059
2060template <PrimType Name, class T = typename PrimConv<Name>::T>
2061bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
2062 const Floating &F = S.Stk.pop<Floating>();
2063
2064 if constexpr (std::is_same_v<T, Boolean>) {
2065 S.Stk.push<T>(T(F.isNonZero()));
2066 return true;
2067 } else {
2068 APSInt Result(std::max(8u, T::bitWidth()),
2069 /*IsUnsigned=*/!T::isSigned());
2070 auto Status = F.convertToInteger(Result);
2071
2072 // Float-to-Integral overflow check.
2073 if ((Status & APFloat::opStatus::opInvalidOp)) {
2074 const Expr *E = S.Current->getExpr(PC: OpPC);
2075 QualType Type = E->getType();
2076
2077 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2078 if (S.noteUndefinedBehavior()) {
2079 S.Stk.push<T>(T(Result));
2080 return true;
2081 }
2082 return false;
2083 }
2084
2085 S.Stk.push<T>(T(Result));
2086 return CheckFloatResult(S, OpPC, Result: F, Status);
2087 }
2088}
2089
2090static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2091 uint32_t BitWidth) {
2092 const Floating &F = S.Stk.pop<Floating>();
2093
2094 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2095 auto Status = F.convertToInteger(Result);
2096
2097 // Float-to-Integral overflow check.
2098 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2099 const Expr *E = S.Current->getExpr(PC: OpPC);
2100 QualType Type = E->getType();
2101
2102 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2103 return S.noteUndefinedBehavior();
2104 }
2105
2106 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>(Result));
2107 return CheckFloatResult(S, OpPC, Result: F, Status);
2108}
2109
2110static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2111 uint32_t BitWidth) {
2112 const Floating &F = S.Stk.pop<Floating>();
2113
2114 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2115 auto Status = F.convertToInteger(Result);
2116
2117 // Float-to-Integral overflow check.
2118 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2119 const Expr *E = S.Current->getExpr(PC: OpPC);
2120 QualType Type = E->getType();
2121
2122 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2123 return S.noteUndefinedBehavior();
2124 }
2125
2126 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>(Result));
2127 return CheckFloatResult(S, OpPC, Result: F, Status);
2128}
2129
2130template <PrimType Name, class T = typename PrimConv<Name>::T>
2131bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
2132 const Pointer &Ptr = S.Stk.pop<Pointer>();
2133
2134 if (Ptr.isDummy())
2135 return false;
2136
2137 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2138 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2139 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2140
2141 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2142 return true;
2143}
2144
2145static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
2146 uint32_t BitWidth) {
2147 const Pointer &Ptr = S.Stk.pop<Pointer>();
2148
2149 if (Ptr.isDummy())
2150 return false;
2151
2152 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2153 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2154 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2155
2156 S.Stk.push<IntegralAP<false>>(
2157 Args: IntegralAP<false>::from(Value: Ptr.getIntegerRepresentation(), NumBits: BitWidth));
2158 return true;
2159}
2160
2161static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
2162 uint32_t BitWidth) {
2163 const Pointer &Ptr = S.Stk.pop<Pointer>();
2164
2165 if (Ptr.isDummy())
2166 return false;
2167
2168 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2169 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2170 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2171
2172 S.Stk.push<IntegralAP<true>>(
2173 Args: IntegralAP<true>::from(Value: Ptr.getIntegerRepresentation(), NumBits: BitWidth));
2174 return true;
2175}
2176
2177static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2178 const auto &Ptr = S.Stk.peek<Pointer>();
2179
2180 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2181 bool HasValidResult = !Ptr.isZero();
2182
2183 if (HasValidResult) {
2184 // FIXME: note_constexpr_invalid_void_star_cast
2185 } else if (!S.getLangOpts().CPlusPlus26) {
2186 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2187 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2188 << 3 << "'void *'" << S.Current->getRange(PC: OpPC);
2189 }
2190 } else {
2191 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2192 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2193 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2194 }
2195
2196 return true;
2197}
2198
2199//===----------------------------------------------------------------------===//
2200// Zero, Nullptr
2201//===----------------------------------------------------------------------===//
2202
2203template <PrimType Name, class T = typename PrimConv<Name>::T>
2204bool Zero(InterpState &S, CodePtr OpPC) {
2205 S.Stk.push<T>(T::zero());
2206 return true;
2207}
2208
2209static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2210 S.Stk.push<IntegralAP<false>>(Args: IntegralAP<false>::zero(BitWidth));
2211 return true;
2212}
2213
2214static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2215 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>::zero(BitWidth));
2216 return true;
2217}
2218
2219template <PrimType Name, class T = typename PrimConv<Name>::T>
2220inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2221 // Note: Desc can be null.
2222 S.Stk.push<T>(0, Desc);
2223 return true;
2224}
2225
2226//===----------------------------------------------------------------------===//
2227// This, ImplicitThis
2228//===----------------------------------------------------------------------===//
2229
2230inline bool This(InterpState &S, CodePtr OpPC) {
2231 // Cannot read 'this' in this mode.
2232 if (S.checkingPotentialConstantExpression()) {
2233 return false;
2234 }
2235
2236 const Pointer &This = S.Current->getThis();
2237 if (!CheckThis(S, OpPC, This))
2238 return false;
2239
2240 // Ensure the This pointer has been cast to the correct base.
2241 if (!This.isDummy()) {
2242 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2243 assert(This.getRecord());
2244 assert(
2245 This.getRecord()->getDecl() ==
2246 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2247 }
2248
2249 S.Stk.push<Pointer>(Args: This);
2250 return true;
2251}
2252
2253inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2254 assert(S.Current->getFunction()->hasRVO());
2255 if (S.checkingPotentialConstantExpression())
2256 return false;
2257 S.Stk.push<Pointer>(Args: S.Current->getRVOPtr());
2258 return true;
2259}
2260
2261//===----------------------------------------------------------------------===//
2262// Shr, Shl
2263//===----------------------------------------------------------------------===//
2264enum class ShiftDir { Left, Right };
2265
2266template <class LT, class RT, ShiftDir Dir>
2267inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2268 const unsigned Bits = LHS.bitWidth();
2269
2270 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2271 if (S.getLangOpts().OpenCL)
2272 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2273 RHS.bitWidth(), &RHS);
2274
2275 if (RHS.isNegative()) {
2276 // During constant-folding, a negative shift is an opposite shift. Such a
2277 // shift is not a constant expression.
2278 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2279 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2280 if (!S.noteUndefinedBehavior())
2281 return false;
2282 RHS = -RHS;
2283 return DoShift < LT, RT,
2284 Dir == ShiftDir::Left ? ShiftDir::Right
2285 : ShiftDir::Left > (S, OpPC, LHS, RHS);
2286 }
2287
2288 if constexpr (Dir == ShiftDir::Left) {
2289 if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
2290 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
2291 // operand, and must not overflow the corresponding unsigned type.
2292 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2293 // E1 x 2^E2 module 2^N.
2294 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2295 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2296 if (!S.noteUndefinedBehavior())
2297 return false;
2298 }
2299 }
2300
2301 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2302 return false;
2303
2304 // Limit the shift amount to Bits - 1. If this happened,
2305 // it has already been diagnosed by CheckShift() above,
2306 // but we still need to handle it.
2307 typename LT::AsUnsigned R;
2308 if constexpr (Dir == ShiftDir::Left) {
2309 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2310 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2311 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2312 else
2313 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2314 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2315 } else {
2316 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2317 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2318 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2319 else
2320 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2321 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2322 }
2323
2324 S.Stk.push<LT>(LT::from(R));
2325 return true;
2326}
2327
2328template <PrimType NameL, PrimType NameR>
2329inline bool Shr(InterpState &S, CodePtr OpPC) {
2330 using LT = typename PrimConv<NameL>::T;
2331 using RT = typename PrimConv<NameR>::T;
2332 auto RHS = S.Stk.pop<RT>();
2333 auto LHS = S.Stk.pop<LT>();
2334
2335 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2336}
2337
2338template <PrimType NameL, PrimType NameR>
2339inline bool Shl(InterpState &S, CodePtr OpPC) {
2340 using LT = typename PrimConv<NameL>::T;
2341 using RT = typename PrimConv<NameR>::T;
2342 auto RHS = S.Stk.pop<RT>();
2343 auto LHS = S.Stk.pop<LT>();
2344
2345 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2346}
2347
2348//===----------------------------------------------------------------------===//
2349// NoRet
2350//===----------------------------------------------------------------------===//
2351
2352inline bool NoRet(InterpState &S, CodePtr OpPC) {
2353 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2354 S.FFDiag(Loc: EndLoc, DiagId: diag::note_constexpr_no_return);
2355 return false;
2356}
2357
2358//===----------------------------------------------------------------------===//
2359// NarrowPtr, ExpandPtr
2360//===----------------------------------------------------------------------===//
2361
2362inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2363 const Pointer &Ptr = S.Stk.pop<Pointer>();
2364 S.Stk.push<Pointer>(Args: Ptr.narrow());
2365 return true;
2366}
2367
2368inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2369 const Pointer &Ptr = S.Stk.pop<Pointer>();
2370 S.Stk.push<Pointer>(Args: Ptr.expand());
2371 return true;
2372}
2373
2374// 1) Pops an integral value from the stack
2375// 2) Peeks a pointer
2376// 3) Pushes a new pointer that's a narrowed array
2377// element of the peeked pointer with the value
2378// from 1) added as offset.
2379//
2380// This leaves the original pointer on the stack and pushes a new one
2381// with the offset applied and narrowed.
2382template <PrimType Name, class T = typename PrimConv<Name>::T>
2383inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2384 const T &Offset = S.Stk.pop<T>();
2385 const Pointer &Ptr = S.Stk.peek<Pointer>();
2386
2387 if (!Ptr.isZero()) {
2388 if (!CheckArray(S, OpPC, Ptr))
2389 return false;
2390 }
2391
2392 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2393 return false;
2394
2395 return NarrowPtr(S, OpPC);
2396}
2397
2398template <PrimType Name, class T = typename PrimConv<Name>::T>
2399inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2400 const T &Offset = S.Stk.pop<T>();
2401 const Pointer &Ptr = S.Stk.pop<Pointer>();
2402
2403 if (!Ptr.isZero()) {
2404 if (!CheckArray(S, OpPC, Ptr))
2405 return false;
2406 }
2407
2408 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2409 return false;
2410
2411 return NarrowPtr(S, OpPC);
2412}
2413
2414template <PrimType Name, class T = typename PrimConv<Name>::T>
2415inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2416 const Pointer &Ptr = S.Stk.peek<Pointer>();
2417
2418 if (!CheckLoad(S, OpPC, Ptr))
2419 return false;
2420
2421 S.Stk.push<T>(Ptr.atIndex(Idx: Index).deref<T>());
2422 return true;
2423}
2424
2425template <PrimType Name, class T = typename PrimConv<Name>::T>
2426inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2427 const Pointer &Ptr = S.Stk.pop<Pointer>();
2428
2429 if (!CheckLoad(S, OpPC, Ptr))
2430 return false;
2431
2432 S.Stk.push<T>(Ptr.atIndex(Idx: Index).deref<T>());
2433 return true;
2434}
2435
2436template <PrimType Name, class T = typename PrimConv<Name>::T>
2437inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) {
2438 const auto &SrcPtr = S.Stk.pop<Pointer>();
2439 const auto &DestPtr = S.Stk.peek<Pointer>();
2440
2441 for (uint32_t I = 0; I != Size; ++I) {
2442 const Pointer &SP = SrcPtr.atIndex(Idx: SrcIndex + I);
2443
2444 if (!CheckLoad(S, OpPC, Ptr: SP))
2445 return false;
2446
2447 const Pointer &DP = DestPtr.atIndex(Idx: DestIndex + I);
2448 DP.deref<T>() = SP.deref<T>();
2449 DP.initialize();
2450 }
2451 return true;
2452}
2453
2454/// Just takes a pointer and checks if it's an incomplete
2455/// array type.
2456inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2457 const Pointer &Ptr = S.Stk.pop<Pointer>();
2458
2459 if (Ptr.isZero()) {
2460 S.Stk.push<Pointer>(Args: Ptr);
2461 return true;
2462 }
2463
2464 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_ArrayToPointer))
2465 return false;
2466
2467 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
2468 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0));
2469 return true;
2470 }
2471
2472 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2473 S.FFDiag(SI: E, DiagId: diag::note_constexpr_unsupported_unsized_array);
2474
2475 return false;
2476}
2477
2478inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2479 uint32_t VarArgSize) {
2480 if (Func->hasThisPointer()) {
2481 size_t ArgSize = Func->getArgSize() + VarArgSize;
2482 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2483 const Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2484
2485 // If the current function is a lambda static invoker and
2486 // the function we're about to call is a lambda call operator,
2487 // skip the CheckInvoke, since the ThisPtr is a null pointer
2488 // anyway.
2489 if (!(S.Current->getFunction() &&
2490 S.Current->getFunction()->isLambdaStaticInvoker() &&
2491 Func->isLambdaCallOperator())) {
2492 if (!CheckInvoke(S, OpPC, Ptr: ThisPtr))
2493 return false;
2494 }
2495
2496 if (S.checkingPotentialConstantExpression())
2497 return false;
2498 }
2499
2500 if (!CheckCallable(S, OpPC, F: Func))
2501 return false;
2502
2503 if (!CheckCallDepth(S, OpPC))
2504 return false;
2505
2506 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: OpPC, args&: VarArgSize);
2507 InterpFrame *FrameBefore = S.Current;
2508 S.Current = NewFrame.get();
2509
2510 APValue CallResult;
2511 // Note that we cannot assert(CallResult.hasValue()) here since
2512 // Ret() above only sets the APValue if the curent frame doesn't
2513 // have a caller set.
2514 if (Interpret(S, Result&: CallResult)) {
2515 NewFrame.release(); // Frame was delete'd already.
2516 assert(S.Current == FrameBefore);
2517 return true;
2518 }
2519
2520 // Interpreting the function failed somehow. Reset to
2521 // previous state.
2522 S.Current = FrameBefore;
2523 return false;
2524
2525 return false;
2526}
2527
2528inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2529 uint32_t VarArgSize) {
2530 if (Func->hasThisPointer()) {
2531 size_t ArgSize = Func->getArgSize() + VarArgSize;
2532 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2533
2534 const Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2535
2536 // If the current function is a lambda static invoker and
2537 // the function we're about to call is a lambda call operator,
2538 // skip the CheckInvoke, since the ThisPtr is a null pointer
2539 // anyway.
2540 if (!(S.Current->getFunction() &&
2541 S.Current->getFunction()->isLambdaStaticInvoker() &&
2542 Func->isLambdaCallOperator())) {
2543 if (!CheckInvoke(S, OpPC, Ptr: ThisPtr))
2544 return false;
2545 }
2546 }
2547
2548 if (!CheckCallable(S, OpPC, F: Func))
2549 return false;
2550
2551 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2552 return false;
2553
2554 if (!CheckCallDepth(S, OpPC))
2555 return false;
2556
2557 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: OpPC, args&: VarArgSize);
2558 InterpFrame *FrameBefore = S.Current;
2559 S.Current = NewFrame.get();
2560
2561 APValue CallResult;
2562 // Note that we cannot assert(CallResult.hasValue()) here since
2563 // Ret() above only sets the APValue if the curent frame doesn't
2564 // have a caller set.
2565 if (Interpret(S, Result&: CallResult)) {
2566 NewFrame.release(); // Frame was delete'd already.
2567 assert(S.Current == FrameBefore);
2568 return true;
2569 }
2570
2571 // Interpreting the function failed somehow. Reset to
2572 // previous state.
2573 S.Current = FrameBefore;
2574 return false;
2575}
2576
2577inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2578 uint32_t VarArgSize) {
2579 assert(Func->hasThisPointer());
2580 assert(Func->isVirtual());
2581 size_t ArgSize = Func->getArgSize() + VarArgSize;
2582 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2583 Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2584
2585 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2586 const CXXRecordDecl *DynamicDecl;
2587 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2588 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2589 else
2590 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2591 const auto *StaticDecl = cast<CXXRecordDecl>(Val: Func->getParentDecl());
2592 const auto *InitialFunction = cast<CXXMethodDecl>(Val: Func->getDecl());
2593 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2594 DynamicDecl, StaticDecl, InitialFunction);
2595
2596 if (Overrider != InitialFunction) {
2597 // DR1872: An instantiated virtual constexpr function can't be called in a
2598 // constant expression (prior to C++20). We can still constant-fold such a
2599 // call.
2600 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2601 const Expr *E = S.Current->getExpr(PC: OpPC);
2602 S.CCEDiag(E, DiagId: diag::note_constexpr_virtual_call) << E->getSourceRange();
2603 }
2604
2605 Func = S.getContext().getOrCreateFunction(FD: Overrider);
2606
2607 const CXXRecordDecl *ThisFieldDecl =
2608 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2609 if (Func->getParentDecl()->isDerivedFrom(Base: ThisFieldDecl)) {
2610 // If the function we call is further DOWN the hierarchy than the
2611 // FieldDesc of our pointer, just get the DeclDesc instead, which
2612 // is the furthest we might go up in the hierarchy.
2613 ThisPtr = ThisPtr.getDeclPtr();
2614 }
2615 }
2616
2617 return Call(S, OpPC, Func, VarArgSize);
2618}
2619
2620inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2621 const CallExpr *CE) {
2622 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: PC);
2623
2624 InterpFrame *FrameBefore = S.Current;
2625 S.Current = NewFrame.get();
2626
2627 if (InterpretBuiltin(S, OpPC: PC, F: Func, Call: CE)) {
2628 NewFrame.release();
2629 return true;
2630 }
2631 S.Current = FrameBefore;
2632 return false;
2633}
2634
2635inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2636 const CallExpr *CE) {
2637 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2638
2639 const Function *F = FuncPtr.getFunction();
2640 if (!F) {
2641 const Expr *E = S.Current->getExpr(PC: OpPC);
2642 S.FFDiag(E, DiagId: diag::note_constexpr_null_callee)
2643 << const_cast<Expr *>(E) << E->getSourceRange();
2644 return false;
2645 }
2646
2647 if (!FuncPtr.isValid())
2648 return false;
2649
2650 assert(F);
2651
2652 // This happens when the call expression has been cast to
2653 // something else, but we don't support that.
2654 if (S.Ctx.classify(T: F->getDecl()->getReturnType()) !=
2655 S.Ctx.classify(T: CE->getType()))
2656 return false;
2657
2658 // Check argument nullability state.
2659 if (F->hasNonNullAttr()) {
2660 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2661 return false;
2662 }
2663
2664 assert(ArgSize >= F->getWrittenArgSize());
2665 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2666
2667 // We need to do this explicitly here since we don't have the necessary
2668 // information to do it automatically.
2669 if (F->isThisPointerExplicit())
2670 VarArgSize -= align(Size: primSize(Type: PT_Ptr));
2671
2672 if (F->isVirtual())
2673 return CallVirt(S, OpPC, Func: F, VarArgSize);
2674
2675 return Call(S, OpPC, Func: F, VarArgSize);
2676}
2677
2678inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2679 assert(Func);
2680 S.Stk.push<FunctionPointer>(Args&: Func);
2681 return true;
2682}
2683
2684template <PrimType Name, class T = typename PrimConv<Name>::T>
2685inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2686 const T &IntVal = S.Stk.pop<T>();
2687
2688 S.Stk.push<Pointer>(Args: static_cast<uint64_t>(IntVal), Args&: Desc);
2689 return true;
2690}
2691
2692inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
2693 S.Stk.push<MemberPointer>(Args&: D);
2694 return true;
2695}
2696
2697inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2698 const auto &MP = S.Stk.pop<MemberPointer>();
2699
2700 S.Stk.push<Pointer>(Args: MP.getBase());
2701 return true;
2702}
2703
2704inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2705 const auto &MP = S.Stk.pop<MemberPointer>();
2706
2707 const auto *FD = cast<FunctionDecl>(Val: MP.getDecl());
2708 const auto *Func = S.getContext().getOrCreateFunction(FD);
2709
2710 S.Stk.push<FunctionPointer>(Args&: Func);
2711 return true;
2712}
2713
2714/// Just emit a diagnostic. The expression that caused emission of this
2715/// op is not valid in a constant context.
2716inline bool Invalid(InterpState &S, CodePtr OpPC) {
2717 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2718 S.FFDiag(Loc, DiagId: diag::note_invalid_subexpr_in_const_expr)
2719 << S.Current->getRange(PC: OpPC);
2720 return false;
2721}
2722
2723inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2724 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2725 S.FFDiag(Loc, DiagId: diag::note_constexpr_stmt_expr_unsupported)
2726 << S.Current->getRange(PC: OpPC);
2727 return false;
2728}
2729
2730/// Do nothing and just abort execution.
2731inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2732
2733/// Same here, but only for casts.
2734inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2735 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2736
2737 // FIXME: Support diagnosing other invalid cast kinds.
2738 if (Kind == CastKind::Reinterpret)
2739 S.FFDiag(Loc, DiagId: diag::note_constexpr_invalid_cast)
2740 << static_cast<unsigned>(Kind) << S.Current->getRange(PC: OpPC);
2741 return false;
2742}
2743
2744inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
2745 const DeclRefExpr *DR) {
2746 assert(DR);
2747 return CheckDeclRef(S, OpPC, DR);
2748}
2749
2750inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
2751 if (S.inConstantContext()) {
2752 const SourceRange &ArgRange = S.Current->getRange(PC: OpPC);
2753 const Expr *E = S.Current->getExpr(PC: OpPC);
2754 S.CCEDiag(E, DiagId: diag::note_constexpr_non_const_vectorelements) << ArgRange;
2755 }
2756 return false;
2757}
2758
2759inline bool Assume(InterpState &S, CodePtr OpPC) {
2760 const auto Val = S.Stk.pop<Boolean>();
2761
2762 if (Val)
2763 return true;
2764
2765 // Else, diagnose.
2766 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2767 S.CCEDiag(Loc, DiagId: diag::note_constexpr_assumption_failed);
2768 return false;
2769}
2770
2771template <PrimType Name, class T = typename PrimConv<Name>::T>
2772inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2773 llvm::SmallVector<int64_t> ArrayIndices;
2774 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2775 ArrayIndices.emplace_back(Args: S.Stk.pop<int64_t>());
2776
2777 int64_t Result;
2778 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2779 return false;
2780
2781 S.Stk.push<T>(T::from(Result));
2782
2783 return true;
2784}
2785
2786template <PrimType Name, class T = typename PrimConv<Name>::T>
2787inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2788 const T &Arg = S.Stk.peek<T>();
2789 if (!Arg.isZero())
2790 return true;
2791
2792 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2793 S.CCEDiag(Loc, DiagId: diag::note_non_null_attribute_failed);
2794
2795 return false;
2796}
2797
2798void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2799 const APSInt &Value);
2800
2801template <PrimType Name, class T = typename PrimConv<Name>::T>
2802inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2803 assert(ED);
2804 assert(!ED->isFixed());
2805 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2806
2807 if (S.inConstantContext())
2808 diagnoseEnumValue(S, OpPC, ED, Value: Val);
2809 return true;
2810}
2811
2812/// OldPtr -> Integer -> NewPtr.
2813template <PrimType TIn, PrimType TOut>
2814inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2815 static_assert(isPtrType(T: TIn) && isPtrType(T: TOut));
2816 using FromT = typename PrimConv<TIn>::T;
2817 using ToT = typename PrimConv<TOut>::T;
2818
2819 const FromT &OldPtr = S.Stk.pop<FromT>();
2820 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2821 return true;
2822}
2823
2824inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2825 // An expression E is a core constant expression unless the evaluation of E
2826 // would evaluate one of the following: [C++23] - a control flow that passes
2827 // through a declaration of a variable with static or thread storage duration
2828 // unless that variable is usable in constant expressions.
2829 assert(VD->isLocalVarDecl() &&
2830 VD->isStaticLocal()); // Checked before emitting this.
2831
2832 if (VD == S.EvaluatingDecl)
2833 return true;
2834
2835 if (!VD->isUsableInConstantExpressions(C: S.getCtx())) {
2836 S.CCEDiag(Loc: VD->getLocation(), DiagId: diag::note_constexpr_static_local)
2837 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2838 return false;
2839 }
2840 return true;
2841}
2842
2843inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2844 assert(Desc);
2845
2846 if (!CheckDynamicMemoryAllocation(S, OpPC))
2847 return false;
2848
2849 DynamicAllocator &Allocator = S.getAllocator();
2850 Block *B = Allocator.allocate(D: Desc, EvalID: S.Ctx.getEvalID());
2851 assert(B);
2852
2853 S.Stk.push<Pointer>(Args&: B, Args: sizeof(InlineDescriptor));
2854
2855 return true;
2856}
2857
2858template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2859inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2860 bool IsNoThrow) {
2861 if (!CheckDynamicMemoryAllocation(S, OpPC))
2862 return false;
2863
2864 SizeT NumElements = S.Stk.pop<SizeT>();
2865 if (!CheckArraySize(S, OpPC, &NumElements, primSize(Type: T), IsNoThrow)) {
2866 if (!IsNoThrow)
2867 return false;
2868
2869 // If this failed and is nothrow, just return a null ptr.
2870 S.Stk.push<Pointer>(Args: 0, Args: nullptr);
2871 return true;
2872 }
2873
2874 DynamicAllocator &Allocator = S.getAllocator();
2875 Block *B = Allocator.allocate(Source, T, NumElements: static_cast<size_t>(NumElements),
2876 EvalID: S.Ctx.getEvalID());
2877 assert(B);
2878 S.Stk.push<Pointer>(Args&: B, Args: sizeof(InlineDescriptor));
2879
2880 return true;
2881}
2882
2883template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2884inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2885 bool IsNoThrow) {
2886 if (!CheckDynamicMemoryAllocation(S, OpPC))
2887 return false;
2888
2889 SizeT NumElements = S.Stk.pop<SizeT>();
2890 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2891 IsNoThrow)) {
2892 if (!IsNoThrow)
2893 return false;
2894
2895 // If this failed and is nothrow, just return a null ptr.
2896 S.Stk.push<Pointer>(Args: 0, Args&: ElementDesc);
2897 return true;
2898 }
2899
2900 DynamicAllocator &Allocator = S.getAllocator();
2901 Block *B = Allocator.allocate(D: ElementDesc, NumElements: static_cast<size_t>(NumElements),
2902 EvalID: S.Ctx.getEvalID());
2903 assert(B);
2904
2905 S.Stk.push<Pointer>(Args&: B, Args: sizeof(InlineDescriptor));
2906
2907 return true;
2908}
2909
2910bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
2911static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
2912 if (!CheckDynamicMemoryAllocation(S, OpPC))
2913 return false;
2914
2915 const Expr *Source = nullptr;
2916 const Block *BlockToDelete = nullptr;
2917 {
2918 // Extra scope for this so the block doesn't have this pointer
2919 // pointing to it when we destroy it.
2920 const Pointer &Ptr = S.Stk.pop<Pointer>();
2921
2922 // Deleteing nullptr is always fine.
2923 if (Ptr.isZero())
2924 return true;
2925
2926 if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
2927 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2928 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_delete_subobject)
2929 << Ptr.toDiagnosticString(Ctx: S.getCtx()) << Ptr.isOnePastEnd();
2930 return false;
2931 }
2932
2933 Source = Ptr.getDeclDesc()->asExpr();
2934 BlockToDelete = Ptr.block();
2935
2936 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
2937 return false;
2938 }
2939 assert(Source);
2940 assert(BlockToDelete);
2941
2942 // Invoke destructors before deallocating the memory.
2943 if (!RunDestructors(S, OpPC, B: BlockToDelete))
2944 return false;
2945
2946 DynamicAllocator &Allocator = S.getAllocator();
2947 bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
2948 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
2949
2950 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
2951 // Nothing has been deallocated, this must be a double-delete.
2952 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2953 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_double_delete);
2954 return false;
2955 }
2956 return CheckNewDeleteForms(S, OpPC, NewWasArray: WasArrayAlloc, DeleteIsArray: DeleteIsArrayForm,
2957 D: BlockDesc, NewExpr: Source);
2958}
2959
2960//===----------------------------------------------------------------------===//
2961// Read opcode arguments
2962//===----------------------------------------------------------------------===//
2963
2964template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2965 if constexpr (std::is_pointer<T>::value) {
2966 uint32_t ID = OpPC.read<uint32_t>();
2967 return reinterpret_cast<T>(S.P.getNativePointer(Idx: ID));
2968 } else {
2969 return OpPC.read<T>();
2970 }
2971}
2972
2973template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2974 Floating F = Floating::deserialize(Buff: *OpPC);
2975 OpPC += align(Size: F.bytesToSerialize());
2976 return F;
2977}
2978
2979template <>
2980inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2981 CodePtr &OpPC) {
2982 IntegralAP<false> I = IntegralAP<false>::deserialize(Buff: *OpPC);
2983 OpPC += align(Size: I.bytesToSerialize());
2984 return I;
2985}
2986
2987template <>
2988inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2989 CodePtr &OpPC) {
2990 IntegralAP<true> I = IntegralAP<true>::deserialize(Buff: *OpPC);
2991 OpPC += align(Size: I.bytesToSerialize());
2992 return I;
2993}
2994
2995} // namespace interp
2996} // namespace clang
2997
2998#endif
2999