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 "BitcastBuffer.h"
18#include "Boolean.h"
19#include "Char.h"
20#include "DynamicAllocator.h"
21#include "FixedPoint.h"
22#include "Floating.h"
23#include "Function.h"
24#include "InterpBuiltinBitCast.h"
25#include "InterpFrame.h"
26#include "InterpHelpers.h"
27#include "InterpStack.h"
28#include "InterpState.h"
29#include "MemberPointer.h"
30#include "PrimType.h"
31#include "Program.h"
32#include "State.h"
33#include "clang/AST/ASTContext.h"
34#include "clang/AST/Expr.h"
35#include "llvm/ADT/APFloat.h"
36#include "llvm/ADT/APSInt.h"
37#include "llvm/Support/Compiler.h"
38#include <type_traits>
39
40// preserve_none causes problems when asan is enabled on both AArch64 and other
41// platforms. Disable it until all the bugs are fixed here.
42//
43// See https://github.com/llvm/llvm-project/issues/177519 for AArch64.
44#if !defined(__aarch64__) && !defined(__i386__) && \
45 !__has_feature(address_sanitizer) && \
46 __has_cpp_attribute(clang::preserve_none)
47#define PRESERVE_NONE [[clang::preserve_none]]
48#else
49#define PRESERVE_NONE
50#endif
51
52namespace clang {
53namespace interp {
54
55using APSInt = llvm::APSInt;
56using FixedPointSemantics = llvm::FixedPointSemantics;
57
58/// Checks if a pointer is null.
59bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60 CheckSubobjectKind CSK);
61
62/// Checks if Ptr is a one-past-the-end pointer.
63bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 CheckSubobjectKind CSK);
65
66/// Checks if the dowcast using the given offset is possible with the given
67/// pointer.
68bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
69 uint32_t Offset);
70
71/// Checks if a pointer points to const storage.
72bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
73
74/// Checks if the Descriptor is of a constexpr or const global variable.
75bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc,
76 AccessKinds AK = AK_Read);
77
78bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79
80bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
81 AccessKinds AK);
82
83bool diagnoseArrayIndex(InterpState &S, CodePtr OpPC, const APSInt &Index,
84 std::optional<uint64_t> NumElems = std::nullopt,
85 bool IsArray = true);
86
87/// Checks a direct load of a primitive value from a global or local variable.
88bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
89bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);
90
91/// Checks if a value can be stored in a block.
92bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
93 AccessKinds AK = AK_Assign, bool WillBeActivated = false);
94
95/// Checks if a value can be initialized.
96bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
97
98/// Checks the 'this' pointer.
99bool CheckThis(InterpState &S, CodePtr OpPC);
100
101/// Checks if dynamic memory allocation is available in the current
102/// language mode.
103bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
104
105/// Check the source of the pointer passed to delete/delete[] has actually
106/// been heap allocated by us.
107bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
108 const Pointer &Ptr);
109
110bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
111 AccessKinds AK, bool WillActivate = false);
112
113/// Sets the given integral value to the pointer, which is of
114/// a std::{weak,partial,strong}_ordering type.
115bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
116 const Pointer &Ptr, const APSInt &IntValue);
117
118bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
119 uint32_t VarArgSize);
120bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
121 uint32_t VarArgSize);
122bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
123 uint32_t VarArgSize);
124bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
125 uint32_t BuiltinID);
126bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
127 const CallExpr *CE);
128bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
129bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
130bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
131 bool TargetIsUCharOrByte);
132bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
133bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
134bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD);
135bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
136 bool SrcIsVoidPtr);
137bool handleReference(InterpState &S, CodePtr OpPC, Block *B);
138bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal);
139
140bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
141 const FixedPoint &FP);
142
143bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I);
144bool isConstexprUnknown(const Pointer &P);
145bool isConstexprUnknown(const Block *B);
146bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestType,
147 bool IsReferenceCast);
148bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
149 uint32_t FPOI);
150bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
151 uint32_t FPOI);
152
153enum class ShiftDir { Left, Right };
154
155enum class ShiftFailure {
156 NegativeCount,
157 TooLarge,
158 NegativeLeftOperand,
159 DiscardsBits,
160};
161
162LLVM_ATTRIBUTE_NOINLINE bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC,
163 ShiftFailure Failure,
164 const APSInt *Value = nullptr,
165 unsigned Bits = 0);
166
167/// Checks if the shift operation is legal.
168template <ShiftDir Dir, typename LT, typename RT>
169bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
170 unsigned Bits) {
171 if (RHS.isNegative()) {
172 const APSInt Value = RHS.toAPSInt();
173 if (!diagnoseShiftFailure(S, OpPC, Failure: ShiftFailure::NegativeCount, Value: &Value))
174 return false;
175 }
176
177 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
178 // the shifted type.
179 if (Bits > 1 && RHS >= Bits) {
180 const APSInt Value = RHS.toAPSInt();
181 if (!diagnoseShiftFailure(S, OpPC, Failure: ShiftFailure::TooLarge, Value: &Value, Bits))
182 return false;
183 }
184
185 if constexpr (Dir == ShiftDir::Left) {
186 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
187 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
188 // operand, and must not overflow the corresponding unsigned type.
189 if (LHS.isNegative()) {
190 const APSInt Value = LHS.toAPSInt();
191 if (!diagnoseShiftFailure(S, OpPC, Failure: ShiftFailure::NegativeLeftOperand,
192 Value: &Value))
193 return false;
194 } else if (LHS.toUnsigned().countLeadingZeros() <
195 static_cast<unsigned>(RHS)) {
196 if (!diagnoseShiftFailure(S, OpPC, Failure: ShiftFailure::DiscardsBits))
197 return false;
198 }
199 }
200 }
201
202 // C++2a [expr.shift]p2: [P0907R4]:
203 // E1 << E2 is the unique value congruent to
204 // E1 x 2^E2 module 2^N.
205 return true;
206}
207
208/// Checks if Div/Rem operation on LHS and RHS is valid.
209template <typename T>
210bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
211
212 if constexpr (isIntegralOrPointer<T>()) {
213 if (!LHS.isNumber() || !RHS.isNumber())
214 return false;
215 }
216
217 if (RHS.isZero()) {
218 const auto *Op = cast<BinaryOperator>(Val: S.Current->getExpr(PC: OpPC));
219 if constexpr (std::is_same_v<T, Floating>) {
220 S.CCEDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
221 << Op->getRHS()->getSourceRange();
222 return true;
223 }
224
225 S.FFDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
226 << Op->getRHS()->getSourceRange();
227 return false;
228 }
229
230 if constexpr (!std::is_same_v<T, FixedPoint>) {
231 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
232 APSInt LHSInt = LHS.toAPSInt();
233 SmallString<32> Trunc;
234 (-LHSInt.extend(width: LHSInt.getBitWidth() + 1)).toString(Str&: Trunc, Radix: 10);
235 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
236 const Expr *E = S.Current->getExpr(PC: OpPC);
237 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_overflow) << Trunc << E->getType();
238 return false;
239 }
240 }
241 return true;
242}
243
244/// Checks if the result of a floating-point operation is valid
245/// in the current context.
246/// Notes:
247/// - CheckFloatStatus is the same as
248/// checkFloatingPointResultForConstantFolding in
249/// clang/lib/AST/ExprConstant.cpp.
250/// - CheckFloatResult will also check if the result is NaN, in addition to
251/// CheckFloatStatus's checks.
252// FIXME: P3899R3 (adopted by WG21 in June 2026) likely makes this interface
253// obsolete.
254// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3899r3.html
255// Also see the comment:
256// https://github.com/llvm/llvm-project/pull/213750/changes/2fea01449764e23b84ce6790bc7121d369546192#r3708712572
257bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
258 APFloat::opStatus Status, FPOptions FPO);
259
260/// Check if the given floating-point evaluation status is allowed for
261/// compile-time constant folding during translation (as opposed to mandatory
262/// constant expression evaluation).
263bool CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status,
264 FPOptions FPO);
265
266/// Checks why the given DeclRefExpr is invalid.
267bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
268bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
269 bool InitializerFailed);
270
271/// DerivedToBaseMemberPointer
272bool CastMemberPtrBasePop(InterpState &S, int32_t Off,
273 const RecordDecl *BaseDecl);
274/// BaseToDerivedMemberPointer
275bool CastMemberPtrDerivedPop(InterpState &S, int32_t Off,
276 const RecordDecl *BaseDecl);
277enum class ArithOp { Add, Sub };
278
279//===----------------------------------------------------------------------===//
280// Returning values
281//===----------------------------------------------------------------------===//
282
283void cleanupAfterFunctionCall(InterpState &S, const Function *Func);
284
285template <PrimType Name, class T = typename PrimConv<Name>::T>
286PRESERVE_NONE bool Ret(InterpState &S) {
287 const T &Ret = S.Stk.pop<T>();
288
289 assert(S.Current);
290#ifndef NDEBUG
291 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
292#endif
293
294 // This only happens via Context::Run().
295 if (S.Current->isBottomFrame())
296 return true;
297
298 cleanupAfterFunctionCall(S, Func: S.Current->getFunction());
299 S.PC = S.Current->getRetPC();
300 S.Stk.push<T>(Ret);
301 return true;
302}
303
304PRESERVE_NONE inline bool RetVoid(InterpState &S) {
305 assert(S.Current);
306#ifndef NDEBUG
307 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
308#endif
309
310 // This only happens via Context::Run().
311 if (S.Current->isBottomFrame())
312 return true;
313
314 cleanupAfterFunctionCall(S, Func: S.Current->getFunction());
315 S.PC = S.Current->getRetPC();
316 return true;
317}
318
319//===----------------------------------------------------------------------===//
320// Add, Sub, Mul
321//===----------------------------------------------------------------------===//
322
323template <typename T, bool (*OpFW)(T, T, unsigned, T *),
324 template <typename U> class OpAP>
325bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
326 const T &RHS) {
327 // Should've been handled before.
328 if constexpr (isIntegralOrPointer<T>()) {
329 assert(LHS.isNumber() && RHS.isNumber());
330 }
331
332 // Fast path - add the numbers with fixed width.
333 T Result;
334 if constexpr (needsAlloc<T>())
335 Result = S.allocAP<T>(LHS.bitWidth());
336
337 if (!OpFW(LHS, RHS, Bits, &Result)) {
338 S.Stk.push<T>(Result);
339 return true;
340 }
341 // If for some reason evaluation continues, use the truncated results.
342 S.Stk.push<T>(Result);
343
344 // Short-circuit fixed-points here since the error handling is easier.
345 if constexpr (std::is_same_v<T, FixedPoint>)
346 return handleFixedPointOverflow(S, OpPC, Result);
347
348 // If wrapping is enabled, the new value is fine.
349 if (S.Current->getExpr(PC: OpPC)->getType().isWrapType())
350 return true;
351
352 // Slow path - compute the result using another bit of precision.
353 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
354
355 // Report undefined behaviour, stopping if required.
356 if (S.checkingForUndefinedBehavior()) {
357 const Expr *E = S.Current->getExpr(PC: OpPC);
358 QualType Type = E->getType();
359 SmallString<32> Trunc;
360 Value.trunc(width: Result.bitWidth())
361 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
362 /*UpperCase=*/true, /*InsertSeparators=*/true);
363 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
364 << Trunc << Type << E->getSourceRange();
365 }
366
367 if (!handleOverflow(S, OpPC, SrcValue: Value)) {
368 S.Stk.pop<T>();
369 return false;
370 }
371 return true;
372}
373
374// Add or subtract an integer-thats-actually-a-pointer and one real integer.
375template <typename T, template <typename U> class Op>
376static bool AddSubNonNumber(InterpState &S, CodePtr OpPC, T LHS, T RHS) {
377 assert(!LHS.isNumber() || !RHS.isNumber());
378
379 typename T::ReprT Number;
380 const void *Ptr;
381 typename T::ReprT Offset;
382 IntegralKind Kind;
383 if (LHS.isNumber()) {
384 if (RHS.getKind() == IntegralKind::AddrLabelDiff)
385 return Invalid(S, OpPC);
386
387 Number = static_cast<typename T::ReprT>(LHS);
388 Ptr = RHS.getPtr();
389 Offset = RHS.getOffset();
390 Kind = RHS.getKind();
391 } else {
392 assert(RHS.isNumber());
393 if (LHS.getKind() == IntegralKind::AddrLabelDiff)
394 return Invalid(S, OpPC);
395
396 Number = static_cast<typename T::ReprT>(RHS);
397 Ptr = LHS.getPtr();
398 Offset = LHS.getOffset();
399 Kind = LHS.getKind();
400 }
401
402 S.Stk.push<T>(Kind, Ptr, Op<int32_t>()(Offset, Number));
403 return true;
404}
405
406template <PrimType Name, class T = typename PrimConv<Name>::T>
407bool Add(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() + 1;
411
412 if constexpr (isIntegralOrPointer<T>()) {
413 if (LHS.isNumber() != RHS.isNumber())
414 return AddSubNonNumber<T, std::plus>(S, OpPC, LHS, RHS);
415 else if (LHS.isNumber() && RHS.isNumber())
416 ; // Fall through to proper addition below.
417 else
418 return false; // Reject everything else.
419 }
420
421 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
422}
423
424inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
425 const Floating &RHS = S.Stk.pop<Floating>();
426 const Floating &LHS = S.Stk.pop<Floating>();
427
428 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
429 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
430 auto Status = Floating::add(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
431 S.Stk.push<Floating>(Args&: Result);
432 return CheckFloatResult(S, OpPC, Result, Status, FPO);
433}
434
435template <PrimType Name, class T = typename PrimConv<Name>::T>
436bool Sub(InterpState &S, CodePtr OpPC) {
437 const T &RHS = S.Stk.pop<T>();
438 const T &LHS = S.Stk.pop<T>();
439 const unsigned Bits = RHS.bitWidth() + 1;
440
441 if constexpr (isIntegralOrPointer<T>()) {
442 // Handle (int)&&a - (int)&&b.
443 // Both operands should be integrals that point to labels and the result is
444 // a AddrLabelDiff integral.
445 if (LHS.getKind() == IntegralKind::LabelAddress ||
446 RHS.getKind() == IntegralKind::LabelAddress) {
447 const auto *A = LHS.getKind() == IntegralKind::LabelAddress
448 ? reinterpret_cast<const Expr *>(LHS.getPtr())
449 : nullptr;
450 const auto *B = RHS.getKind() == IntegralKind::LabelAddress
451 ? reinterpret_cast<const Expr *>(RHS.getPtr())
452 : nullptr;
453 if (!isa_and_nonnull<AddrLabelExpr>(A) ||
454 !isa_and_nonnull<AddrLabelExpr>(B))
455 return false;
456 const auto *LHSAddrExpr = cast<AddrLabelExpr>(A);
457 const auto *RHSAddrExpr = cast<AddrLabelExpr>(B);
458
459 if (LHSAddrExpr->getLabel()->getDeclContext() !=
460 RHSAddrExpr->getLabel()->getDeclContext())
461 return Invalid(S, OpPC);
462
463 S.Stk.push<T>(LHSAddrExpr, RHSAddrExpr);
464 return true;
465 }
466
467 if (!LHS.isNumber() && RHS.isNumber())
468 return AddSubNonNumber<T, std::minus>(S, OpPC, LHS, RHS);
469 else if (LHS.isNumber() && RHS.isNumber())
470 ; // Fall through to proper addition below.
471 else
472 return false; // Reject everything else.
473 }
474
475 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
476}
477
478inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
479 const Floating &RHS = S.Stk.pop<Floating>();
480 const Floating &LHS = S.Stk.pop<Floating>();
481
482 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
483 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
484 auto Status = Floating::sub(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
485 S.Stk.push<Floating>(Args&: Result);
486 return CheckFloatResult(S, OpPC, Result, Status, FPO);
487}
488
489template <PrimType Name, class T = typename PrimConv<Name>::T>
490bool Mul(InterpState &S, CodePtr OpPC) {
491 const T &RHS = S.Stk.pop<T>();
492 const T &LHS = S.Stk.pop<T>();
493 const unsigned Bits = RHS.bitWidth() * 2;
494
495 if constexpr (isIntegralOrPointer<T>()) {
496 if (!LHS.isNumber() || !RHS.isNumber())
497 return Invalid(S, OpPC);
498 }
499
500 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
501}
502
503inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
504 const Floating &RHS = S.Stk.pop<Floating>();
505 const Floating &LHS = S.Stk.pop<Floating>();
506
507 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
508 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
509
510 auto Status = Floating::mul(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
511
512 S.Stk.push<Floating>(Args&: Result);
513 return CheckFloatResult(S, OpPC, Result, Status, FPO);
514}
515
516template <PrimType Name, class T = typename PrimConv<Name>::T>
517inline bool Mulc(InterpState &S) {
518 const Pointer &RHS = S.Stk.pop<Pointer>();
519 const Pointer &LHS = S.Stk.pop<Pointer>();
520 const Pointer &Result = S.Stk.peek<Pointer>();
521
522 if constexpr (std::is_same_v<T, Floating>) {
523 APFloat A = LHS.elem<Floating>(I: 0).getAPFloat();
524 APFloat B = LHS.elem<Floating>(I: 1).getAPFloat();
525 APFloat C = RHS.elem<Floating>(I: 0).getAPFloat();
526 APFloat D = RHS.elem<Floating>(I: 1).getAPFloat();
527
528 APFloat ResR(A.getSemantics());
529 APFloat ResI(A.getSemantics());
530 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
531
532 // Copy into the result.
533 Floating RA = S.allocFloat(Sem: A.getSemantics());
534 RA.copy(F: ResR);
535 Result.elem<Floating>(I: 0) = RA; // Floating(ResR);
536
537 Floating RI = S.allocFloat(Sem: A.getSemantics());
538 RI.copy(F: ResI);
539 Result.elem<Floating>(I: 1) = RI; // Floating(ResI);
540 Result.initializeAllElements();
541 } else {
542 // Integer element type.
543 const T &LHSR = LHS.elem<T>(0);
544 const T &LHSI = LHS.elem<T>(1);
545 const T &RHSR = RHS.elem<T>(0);
546 const T &RHSI = RHS.elem<T>(1);
547 unsigned Bits = LHSR.bitWidth();
548
549 // We only handle actual numbers here.
550 if (!LHSR.isNumber() || !LHSI.isNumber() || !RHSR.isNumber() ||
551 !RHSI.isNumber())
552 return false;
553
554 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
555 T A;
556 if constexpr (needsAlloc<T>())
557 A = S.allocAP<T>(Bits);
558 if (T::mul(LHSR, RHSR, Bits, &A))
559 return false;
560
561 T B;
562 if constexpr (needsAlloc<T>())
563 B = S.allocAP<T>(Bits);
564 if (T::mul(LHSI, RHSI, Bits, &B))
565 return false;
566
567 if constexpr (needsAlloc<T>())
568 Result.elem<T>(0) = S.allocAP<T>(Bits);
569 if (T::sub(A, B, Bits, &Result.elem<T>(0)))
570 return false;
571
572 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
573 if (T::mul(LHSR, RHSI, Bits, &A))
574 return false;
575 if (T::mul(LHSI, RHSR, Bits, &B))
576 return false;
577
578 if constexpr (needsAlloc<T>())
579 Result.elem<T>(1) = S.allocAP<T>(Bits);
580 if (T::add(A, B, Bits, &Result.elem<T>(1)))
581 return false;
582 Result.initialize();
583 Result.initializeAllElements();
584 }
585
586 return true;
587}
588
589template <PrimType Name, class T = typename PrimConv<Name>::T>
590inline bool Divc(InterpState &S, CodePtr OpPC) {
591 const Pointer &RHS = S.Stk.pop<Pointer>();
592 const Pointer &LHS = S.Stk.pop<Pointer>();
593 const Pointer &Result = S.Stk.peek<Pointer>();
594
595 if constexpr (std::is_same_v<T, Floating>) {
596 APFloat A = LHS.elem<Floating>(I: 0).getAPFloat();
597 APFloat B = LHS.elem<Floating>(I: 1).getAPFloat();
598 APFloat C = RHS.elem<Floating>(I: 0).getAPFloat();
599 APFloat D = RHS.elem<Floating>(I: 1).getAPFloat();
600
601 APFloat ResR(A.getSemantics());
602 APFloat ResI(A.getSemantics());
603 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
604
605 // Copy into the result.
606 Floating RA = S.allocFloat(Sem: A.getSemantics());
607 RA.copy(F: ResR);
608 Result.elem<Floating>(I: 0) = RA; // Floating(ResR);
609
610 Floating RI = S.allocFloat(Sem: A.getSemantics());
611 RI.copy(F: ResI);
612 Result.elem<Floating>(I: 1) = RI; // Floating(ResI);
613
614 Result.initializeAllElements();
615 } else {
616 // Integer element type.
617 const T &LHSR = LHS.elem<T>(0);
618 const T &LHSI = LHS.elem<T>(1);
619 const T &RHSR = RHS.elem<T>(0);
620 const T &RHSI = RHS.elem<T>(1);
621 unsigned Bits = LHSR.bitWidth();
622
623 if (RHSR.isZero() && RHSI.isZero()) {
624 const SourceInfo &E = S.Current->getSource(PC: OpPC);
625 S.FFDiag(SI: E, DiagId: diag::note_expr_divide_by_zero);
626 return false;
627 }
628
629 // Den = real(RHS)² + imag(RHS)²
630 T A, B;
631 if constexpr (needsAlloc<T>()) {
632 A = S.allocAP<T>(Bits);
633 B = S.allocAP<T>(Bits);
634 }
635
636 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
637 // Ignore overflow here, because that's what the current interpeter does.
638 }
639 T Den;
640 if constexpr (needsAlloc<T>())
641 Den = S.allocAP<T>(Bits);
642
643 if (T::add(A, B, Bits, &Den))
644 return false;
645
646 if (Den.isZero()) {
647 const SourceInfo &E = S.Current->getSource(PC: OpPC);
648 S.FFDiag(SI: E, DiagId: diag::note_expr_divide_by_zero);
649 return false;
650 }
651
652 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
653 T &ResultR = Result.elem<T>(0);
654 T &ResultI = Result.elem<T>(1);
655 if constexpr (needsAlloc<T>()) {
656 ResultR = S.allocAP<T>(Bits);
657 ResultI = S.allocAP<T>(Bits);
658 }
659 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
660 return false;
661 if (T::add(A, B, Bits, &ResultR))
662 return false;
663 if (T::div(ResultR, Den, Bits, &ResultR))
664 return false;
665
666 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
667 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
668 return false;
669 if (T::sub(A, B, Bits, &ResultI))
670 return false;
671 if (T::div(ResultI, Den, Bits, &ResultI))
672 return false;
673 Result.initializeAllElements();
674 }
675
676 return true;
677}
678
679/// 1) Pops the RHS from the stack.
680/// 2) Pops the LHS from the stack.
681/// 3) Pushes 'LHS & RHS' on the stack
682template <PrimType Name, class T = typename PrimConv<Name>::T>
683bool BitAnd(InterpState &S) {
684 const T &RHS = S.Stk.pop<T>();
685 const T &LHS = S.Stk.pop<T>();
686 unsigned Bits = RHS.bitWidth();
687
688 if constexpr (isIntegralOrPointer<T>()) {
689 if (!LHS.isNumber() || !RHS.isNumber())
690 return false;
691 }
692
693 T Result;
694 if constexpr (needsAlloc<T>())
695 Result = S.allocAP<T>(Bits);
696
697 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
698 S.Stk.push<T>(Result);
699 return true;
700 }
701 return false;
702}
703
704/// 1) Pops the RHS from the stack.
705/// 2) Pops the LHS from the stack.
706/// 3) Pushes 'LHS | RHS' on the stack
707template <PrimType Name, class T = typename PrimConv<Name>::T>
708bool BitOr(InterpState &S) {
709 const T &RHS = S.Stk.pop<T>();
710 const T &LHS = S.Stk.pop<T>();
711 unsigned Bits = RHS.bitWidth();
712
713 if constexpr (isIntegralOrPointer<T>()) {
714 if (!LHS.isNumber() || !RHS.isNumber())
715 return false;
716 }
717
718 T Result;
719 if constexpr (needsAlloc<T>())
720 Result = S.allocAP<T>(Bits);
721
722 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
723 S.Stk.push<T>(Result);
724 return true;
725 }
726 return false;
727}
728
729/// 1) Pops the RHS from the stack.
730/// 2) Pops the LHS from the stack.
731/// 3) Pushes 'LHS ^ RHS' on the stack
732template <PrimType Name, class T = typename PrimConv<Name>::T>
733bool BitXor(InterpState &S) {
734 const T &RHS = S.Stk.pop<T>();
735 const T &LHS = S.Stk.pop<T>();
736 unsigned Bits = RHS.bitWidth();
737
738 if constexpr (isIntegralOrPointer<T>()) {
739 if (!LHS.isNumber() || !RHS.isNumber())
740 return false;
741 }
742
743 T Result;
744 if constexpr (needsAlloc<T>())
745 Result = S.allocAP<T>(Bits);
746
747 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
748 S.Stk.push<T>(Result);
749 return true;
750 }
751 return false;
752}
753
754/// 1) Pops the RHS from the stack.
755/// 2) Pops the LHS from the stack.
756/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
757template <PrimType Name, class T = typename PrimConv<Name>::T>
758bool Rem(InterpState &S, CodePtr OpPC) {
759 const T &RHS = S.Stk.pop<T>();
760 const T &LHS = S.Stk.pop<T>();
761 const unsigned Bits = RHS.bitWidth() * 2;
762
763 if (!CheckDivRem(S, OpPC, LHS, RHS))
764 return false;
765
766 T Result;
767 if constexpr (needsAlloc<T>())
768 Result = S.allocAP<T>(LHS.bitWidth());
769
770 if (!T::rem(LHS, RHS, Bits, &Result)) {
771 S.Stk.push<T>(Result);
772 return true;
773 }
774 return false;
775}
776
777/// 1) Pops the RHS from the stack.
778/// 2) Pops the LHS from the stack.
779/// 3) Pushes 'LHS / RHS' on the stack
780template <PrimType Name, class T = typename PrimConv<Name>::T>
781bool Div(InterpState &S, CodePtr OpPC) {
782 const T &RHS = S.Stk.pop<T>();
783 const T &LHS = S.Stk.pop<T>();
784 const unsigned Bits = RHS.bitWidth() * 2;
785
786 if (!CheckDivRem(S, OpPC, LHS, RHS))
787 return false;
788
789 T Result;
790 if constexpr (needsAlloc<T>())
791 Result = S.allocAP<T>(LHS.bitWidth());
792
793 if (!T::div(LHS, RHS, Bits, &Result)) {
794 S.Stk.push<T>(Result);
795 return true;
796 }
797
798 if constexpr (std::is_same_v<T, FixedPoint>) {
799 if (handleFixedPointOverflow(S, OpPC, Result)) {
800 S.Stk.push<T>(Result);
801 return true;
802 }
803 }
804 return false;
805}
806
807inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
808 const Floating &RHS = S.Stk.pop<Floating>();
809 const Floating &LHS = S.Stk.pop<Floating>();
810
811 if (!CheckDivRem(S, OpPC, LHS, RHS))
812 return false;
813
814 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
815
816 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
817 auto Status = Floating::div(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
818
819 S.Stk.push<Floating>(Args&: Result);
820 return CheckFloatResult(S, OpPC, Result, Status, FPO);
821}
822
823//===----------------------------------------------------------------------===//
824// Inv
825//===----------------------------------------------------------------------===//
826
827inline bool Inv(InterpState &S) {
828 const auto &Val = S.Stk.pop<Boolean>();
829 S.Stk.push<Boolean>(Args: !Val);
830 return true;
831}
832
833//===----------------------------------------------------------------------===//
834// Neg
835//===----------------------------------------------------------------------===//
836
837template <PrimType Name, class T = typename PrimConv<Name>::T>
838bool Neg(InterpState &S, CodePtr OpPC) {
839 const T &Value = S.Stk.pop<T>();
840
841 if constexpr (std::is_same_v<T, Floating>) {
842 T Result = S.allocFloat(Sem: Value.getSemantics());
843
844 if (!T::neg(Value, &Result)) {
845 S.Stk.push<T>(Result);
846 return true;
847 }
848 return false;
849 } else {
850 T Result;
851 if constexpr (needsAlloc<T>())
852 Result = S.allocAP<T>(Value.bitWidth());
853
854 if (!T::neg(Value, &Result)) {
855 S.Stk.push<T>(Result);
856 return true;
857 }
858
859 assert((isIntegerType(Name) || Name == PT_FixedPoint) &&
860 "don't expect other types to fail at constexpr negation");
861 S.Stk.push<T>(Result);
862
863 if (S.Current->getExpr(PC: OpPC)->getType().isWrapType())
864 return true;
865
866 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
867 if (S.checkingForUndefinedBehavior()) {
868 const Expr *E = S.Current->getExpr(PC: OpPC);
869 QualType Type = E->getType();
870 SmallString<32> Trunc;
871 NegatedValue.trunc(width: Result.bitWidth())
872 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
873 /*UpperCase=*/true, /*InsertSeparators=*/true);
874 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
875 << Trunc << Type << E->getSourceRange();
876 return true;
877 }
878
879 return handleOverflow(S, OpPC, SrcValue: NegatedValue);
880 }
881}
882
883enum class PushVal : bool {
884 No,
885 Yes,
886};
887enum class IncDecOp {
888 Inc,
889 Dec,
890};
891
892template <typename T, IncDecOp Op, PushVal DoPush>
893bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
894 bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {
895 assert(!Ptr.isDummy());
896
897 if (!S.inConstantContext()) {
898 if (isConstexprUnknown(P: Ptr))
899 return false;
900 }
901
902 if constexpr (std::is_same_v<T, Boolean>) {
903 if (!S.getLangOpts().CPlusPlus14)
904 return Invalid(S, OpPC);
905 }
906
907 const T &Value = Ptr.deref<T>();
908
909 // Can't inc/dec non-numbers.
910 if constexpr (isIntegralOrPointer<T>()) {
911 if (!Value.isNumber())
912 return false;
913 }
914
915 T Result;
916 if constexpr (needsAlloc<T>())
917 Result = S.allocAP<T>(Value.bitWidth());
918
919 if constexpr (DoPush == PushVal::Yes)
920 S.Stk.push<T>(Value);
921
922 if constexpr (Op == IncDecOp::Inc) {
923 if (!T::increment(Value, &Result) || !CanOverflow) {
924 if (BitWidth)
925 Ptr.deref<T>() = Result.truncate(*BitWidth);
926 else
927 Ptr.deref<T>() = Result;
928 return true;
929 }
930 } else {
931 if (!T::decrement(Value, &Result) || !CanOverflow) {
932 if (BitWidth)
933 Ptr.deref<T>() = Result.truncate(*BitWidth);
934 else
935 Ptr.deref<T>() = Result;
936 return true;
937 }
938 }
939 assert(CanOverflow);
940
941 if (S.Current->getExpr(PC: OpPC)->getType().isWrapType()) {
942 Ptr.deref<T>() = Result;
943 return true;
944 }
945
946 // Something went wrong with the previous operation. Compute the
947 // result with another bit of precision.
948 unsigned Bits = Value.bitWidth() + 1;
949 APSInt APResult;
950 if constexpr (Op == IncDecOp::Inc)
951 APResult = ++Value.toAPSInt(Bits);
952 else
953 APResult = --Value.toAPSInt(Bits);
954
955 // Report undefined behaviour, stopping if required.
956 if (S.checkingForUndefinedBehavior()) {
957 const Expr *E = S.Current->getExpr(PC: OpPC);
958 QualType Type = E->getType();
959 SmallString<32> Trunc;
960 APResult.trunc(width: Result.bitWidth())
961 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
962 /*UpperCase=*/true, /*InsertSeparators=*/true);
963 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
964 << Trunc << Type << E->getSourceRange();
965 return true;
966 }
967 return handleOverflow(S, OpPC, SrcValue: APResult);
968}
969
970/// 1) Pops a pointer from the stack
971/// 2) Load the value from the pointer
972/// 3) Writes the value increased by one back to the pointer
973/// 4) Pushes the original (pre-inc) value on the stack.
974template <PrimType Name, class T = typename PrimConv<Name>::T>
975bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
976 const Pointer &Ptr = S.Stk.pop<Pointer>();
977 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
978 return false;
979 if (!CheckConst(S, OpPC, Ptr))
980 return false;
981
982 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,
983 CanOverflow);
984}
985
986template <PrimType Name, class T = typename PrimConv<Name>::T>
987bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
988 unsigned BitWidth) {
989 const Pointer &Ptr = S.Stk.pop<Pointer>();
990 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
991 return false;
992 if (!CheckConst(S, OpPC, Ptr))
993 return false;
994
995 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
996 BitWidth);
997}
998
999/// 1) Pops a pointer from the stack
1000/// 2) Load the value from the pointer
1001/// 3) Writes the value increased by one back to the pointer
1002template <PrimType Name, class T = typename PrimConv<Name>::T>
1003bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
1004 const Pointer &Ptr = S.Stk.pop<Pointer>();
1005 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1006 return false;
1007 if (!CheckConst(S, OpPC, Ptr))
1008 return false;
1009
1010 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
1011}
1012
1013template <PrimType Name, class T = typename PrimConv<Name>::T>
1014bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
1015 uint32_t BitWidth) {
1016 const Pointer &Ptr = S.Stk.pop<Pointer>();
1017 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1018 return false;
1019 if (!CheckConst(S, OpPC, Ptr))
1020 return false;
1021
1022 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
1023 BitWidth);
1024}
1025
1026template <PrimType Name, class T = typename PrimConv<Name>::T>
1027bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
1028 const Pointer &Ptr = S.Stk.peek<Pointer>();
1029 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1030 return false;
1031 if (!CheckConst(S, OpPC, Ptr))
1032 return false;
1033
1034 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
1035}
1036
1037template <PrimType Name, class T = typename PrimConv<Name>::T>
1038bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
1039 uint32_t BitWidth) {
1040 const Pointer &Ptr = S.Stk.peek<Pointer>();
1041 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1042 return false;
1043 if (!CheckConst(S, OpPC, Ptr))
1044 return false;
1045
1046 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
1047 BitWidth);
1048}
1049
1050/// 1) Pops a pointer from the stack
1051/// 2) Load the value from the pointer
1052/// 3) Writes the value decreased by one back to the pointer
1053/// 4) Pushes the original (pre-dec) value on the stack.
1054template <PrimType Name, class T = typename PrimConv<Name>::T>
1055bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
1056 const Pointer &Ptr = S.Stk.pop<Pointer>();
1057 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1058 return false;
1059 if (!CheckConst(S, OpPC, Ptr))
1060 return false;
1061
1062 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
1063 CanOverflow);
1064}
1065template <PrimType Name, class T = typename PrimConv<Name>::T>
1066bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
1067 uint32_t BitWidth) {
1068 const Pointer &Ptr = S.Stk.pop<Pointer>();
1069 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1070 return false;
1071 if (!CheckConst(S, OpPC, Ptr))
1072 return false;
1073
1074 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
1075 BitWidth);
1076}
1077
1078/// 1) Pops a pointer from the stack
1079/// 2) Load the value from the pointer
1080/// 3) Writes the value decreased by one back to the pointer
1081template <PrimType Name, class T = typename PrimConv<Name>::T>
1082bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
1083 const Pointer &Ptr = S.Stk.pop<Pointer>();
1084 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1085 return false;
1086 if (!CheckConst(S, OpPC, Ptr))
1087 return false;
1088
1089 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
1090}
1091
1092template <PrimType Name, class T = typename PrimConv<Name>::T>
1093bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
1094 uint32_t BitWidth) {
1095 const Pointer &Ptr = S.Stk.pop<Pointer>();
1096 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1097 return false;
1098 if (!CheckConst(S, OpPC, Ptr))
1099 return false;
1100
1101 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
1102 BitWidth);
1103}
1104
1105template <PrimType Name, class T = typename PrimConv<Name>::T>
1106bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
1107 const Pointer &Ptr = S.Stk.peek<Pointer>();
1108 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1109 return false;
1110 if (!CheckConst(S, OpPC, Ptr))
1111 return false;
1112 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
1113}
1114
1115template <PrimType Name, class T = typename PrimConv<Name>::T>
1116bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
1117 uint32_t BitWidth) {
1118 const Pointer &Ptr = S.Stk.peek<Pointer>();
1119 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1120 return false;
1121 if (!CheckConst(S, OpPC, Ptr))
1122 return false;
1123 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
1124 BitWidth);
1125}
1126
1127template <IncDecOp Op, PushVal DoPush>
1128bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1129 uint32_t FPOI) {
1130 Floating Value = Ptr.deref<Floating>();
1131 Floating Result = S.allocFloat(Sem: Value.getSemantics());
1132
1133 if constexpr (DoPush == PushVal::Yes)
1134 S.Stk.push<Floating>(Args&: Value);
1135
1136 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
1137 llvm::APFloat::opStatus Status;
1138 if constexpr (Op == IncDecOp::Inc)
1139 Status = Floating::increment(A: Value, RM: getRoundingMode(FPO), R: &Result);
1140 else
1141 Status = Floating::decrement(A: Value, RM: getRoundingMode(FPO), R: &Result);
1142
1143 Ptr.deref<Floating>() = Result;
1144
1145 return CheckFloatResult(S, OpPC, Result, Status, FPO);
1146}
1147
1148inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1149 const Pointer &Ptr = S.Stk.pop<Pointer>();
1150 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1151 return false;
1152 if (!CheckConst(S, OpPC, Ptr))
1153 return false;
1154
1155 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
1156}
1157
1158inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1159 const Pointer &Ptr = S.Stk.pop<Pointer>();
1160 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
1161 return false;
1162 if (!CheckConst(S, OpPC, Ptr))
1163 return false;
1164
1165 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
1166}
1167
1168inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1169 const Pointer &Ptr = S.Stk.pop<Pointer>();
1170 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1171 return false;
1172 if (!CheckConst(S, OpPC, Ptr))
1173 return false;
1174
1175 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
1176}
1177
1178inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1179 const Pointer &Ptr = S.Stk.pop<Pointer>();
1180 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1181 return false;
1182 if (!CheckConst(S, OpPC, Ptr))
1183 return false;
1184
1185 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
1186}
1187
1188/// 1) Pops the value from the stack.
1189/// 2) Pushes the bitwise complemented value on the stack (~V).
1190template <PrimType Name, class T = typename PrimConv<Name>::T>
1191bool Comp(InterpState &S) {
1192 const T &Val = S.Stk.pop<T>();
1193
1194 T Result;
1195 if constexpr (needsAlloc<T>())
1196 Result = S.allocAP<T>(Val.bitWidth());
1197
1198 if (!T::comp(Val, &Result)) {
1199 S.Stk.push<T>(Result);
1200 return true;
1201 }
1202 return false;
1203}
1204
1205//===----------------------------------------------------------------------===//
1206// EQ, NE, GT, GE, LT, LE
1207//===----------------------------------------------------------------------===//
1208
1209using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
1210
1211template <typename T>
1212bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1213 assert((!std::is_same_v<T, MemberPointer>) &&
1214 "Non-equality comparisons on member pointer types should already be "
1215 "rejected in Sema.");
1216 using BoolT = PrimConv<PT_Bool>::T;
1217 const T &RHS = S.Stk.pop<T>();
1218 const T &LHS = S.Stk.pop<T>();
1219
1220 if constexpr (isIntegralOrPointer<T>()) {
1221 if (!LHS.isNumber() || !RHS.isNumber())
1222 return Invalid(S, OpPC);
1223 }
1224
1225 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
1226 return true;
1227}
1228
1229template <typename T>
1230bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1231 return CmpHelper<T>(S, OpPC, Fn);
1232}
1233
1234template <>
1235inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1236 using BoolT = PrimConv<PT_Bool>::T;
1237 const Pointer &RHS = S.Stk.pop<Pointer>();
1238 const Pointer &LHS = S.Stk.pop<Pointer>();
1239
1240 // Function pointers cannot be compared in an ordered way.
1241 if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||
1242 LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
1243 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1244 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1245 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1246 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1247 return false;
1248 }
1249
1250 if (LHS == RHS) {
1251 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Equal)));
1252 return true;
1253 }
1254
1255 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
1256 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1257 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1258 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1259 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1260 return false;
1261 }
1262
1263 // Diagnose comparisons between fields with different access specifiers,
1264 // comparisons between bases and bases+fields.
1265 if (std::optional<std::pair<PtrView, PtrView>> Split =
1266 Pointer::computeSplitPoint(A: LHS, B: RHS)) {
1267 const FieldDecl *LF = Split->first.getField();
1268 const FieldDecl *RF = Split->second.getField();
1269 if (!LF && !RF)
1270 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
1271 DiagId: diag::note_constexpr_pointer_comparison_base_classes);
1272 else if (!LF)
1273 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
1274 DiagId: diag::note_constexpr_pointer_comparison_base_field)
1275 << Split->first.getRecord()->getDecl() << RF->getParent() << RF;
1276 else if (!RF)
1277 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
1278 DiagId: diag::note_constexpr_pointer_comparison_base_field)
1279 << Split->second.getRecord()->getDecl() << LF->getParent() << LF;
1280 else if (!LF->getParent()->isUnion() &&
1281 LF->getAccess() != RF->getAccess()) {
1282 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
1283 DiagId: diag::note_constexpr_pointer_comparison_differing_access)
1284 << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();
1285 }
1286 }
1287
1288 std::optional<size_t> VL = LHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1289 std::optional<size_t> VR = RHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1290 if (!VL || !VR)
1291 return Invalid(S, OpPC);
1292 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: *VL, Y: *VR))));
1293 return true;
1294}
1295
1296static inline bool IsOpaqueConstantCall(const CallExpr *E) {
1297 unsigned Builtin = E->getBuiltinCallee();
1298 return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1299 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1300 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1301 Builtin == Builtin::BI__builtin_function_start);
1302}
1303
1304bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
1305 const Pointer &RHS);
1306
1307template <>
1308inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1309 using BoolT = PrimConv<PT_Bool>::T;
1310 const Pointer &RHS = S.Stk.pop<Pointer>();
1311 const Pointer &LHS = S.Stk.pop<Pointer>();
1312
1313 if (LHS.isZero() && RHS.isZero()) {
1314 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Equal)));
1315 return true;
1316 }
1317
1318 // Reject comparisons to weak pointers.
1319 for (const auto &P : {LHS, RHS}) {
1320 if (P.isZero())
1321 continue;
1322 if (P.isWeak()) {
1323 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1324 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_weak_comparison)
1325 << P.toDiagnosticString(Ctx: S.getASTContext());
1326 return false;
1327 }
1328 }
1329
1330 // p == nullptr or nullptr == p.
1331 if (RHS.isZero() || LHS.isZero()) {
1332 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Unordered)));
1333 return true;
1334 }
1335
1336 assert(!LHS.isZero());
1337 assert(!RHS.isZero());
1338
1339 if (!S.inConstantContext()) {
1340 if (isConstexprUnknown(P: LHS) || isConstexprUnknown(P: RHS))
1341 return false;
1342 }
1343
1344 if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {
1345 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: LHS.getIntegerRepresentation(),
1346 Y: RHS.getIntegerRepresentation()))));
1347 return true;
1348 }
1349
1350 if (Pointer::hasSameBase(A: LHS, B: RHS)) {
1351 std::optional<size_t> A = LHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1352 std::optional<size_t> B = RHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1353 if (!A || !B)
1354 return Invalid(S, OpPC);
1355
1356 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: *A, Y: *B))));
1357 return true;
1358 }
1359 // Otherwise we need to do a bunch of extra checks before returning Unordered.
1360
1361 if (LHS.isStringPointer() && RHS.isStringPointer() &&
1362 arePotentiallyOverlappingStringLiterals(LHS, RHS)) {
1363 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
1364 DiagId: diag::note_constexpr_literal_comparison)
1365 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1366 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1367 return false;
1368 }
1369
1370 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd()) {
1371 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1372 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
1373 << LHS.toDiagnosticString(Ctx: S.getASTContext());
1374 return false;
1375 }
1376 if (RHS.isOnePastEnd() && !LHS.isOnePastEnd()) {
1377 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1378 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
1379 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1380 return false;
1381 }
1382
1383 // Reject comparisons to literals.
1384 for (const auto &P : {LHS, RHS}) {
1385 if (P.isZero())
1386 continue;
1387 if (P.pointsToLiteral()) {
1388 const Expr *E = P.getRootExpr();
1389 if (isa<StringLiteral>(Val: E)) {
1390 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1391 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_literal_comparison);
1392 return false;
1393 }
1394 if (const auto *CE = dyn_cast<CallExpr>(Val: E);
1395 CE && IsOpaqueConstantCall(E: CE)) {
1396 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1397 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_opaque_call_comparison)
1398 << P.toDiagnosticString(Ctx: S.getASTContext());
1399 return false;
1400 }
1401 } else if (P.isIntegralPointer()) {
1402 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1403 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_constant_comparison)
1404 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1405 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1406 return false;
1407 }
1408 }
1409
1410 if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
1411 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1412 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_zero_sized)
1413 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1414 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1415 return false;
1416 }
1417
1418 if (LHS.isConstexprUnknown() || RHS.isConstexprUnknown()) {
1419 if (!S.checkingPotentialConstantExpression())
1420 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
1421 DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1422 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1423 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1424 return false;
1425 }
1426
1427 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Unordered)));
1428 return true;
1429}
1430
1431template <>
1432inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1433 CompareFn Fn) {
1434 const auto &RHS = S.Stk.pop<MemberPointer>();
1435 const auto &LHS = S.Stk.pop<MemberPointer>();
1436
1437 // If either operand is a pointer to a weak function, the comparison is not
1438 // constant.
1439 for (const auto &MP : {LHS, RHS}) {
1440 if (MP.isWeak()) {
1441 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1442 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_mem_pointer_weak_comparison)
1443 << MP.getMemberFunction();
1444 return false;
1445 }
1446 }
1447
1448 // C++11 [expr.eq]p2:
1449 // If both operands are null, they compare equal. Otherwise if only one is
1450 // null, they compare unequal.
1451 if (LHS.isZero() && RHS.isZero()) {
1452 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Equal));
1453 return true;
1454 }
1455 if (LHS.isZero() || RHS.isZero()) {
1456 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Unordered));
1457 return true;
1458 }
1459
1460 // We cannot compare against virtual declarations at compile time.
1461 for (const auto &MP : {LHS, RHS}) {
1462 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1463 MD && MD->isVirtual()) {
1464 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1465 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1466 }
1467 }
1468
1469 S.Stk.push<Boolean>(Args: Boolean::from(Value: Fn(LHS.compare(RHS))));
1470 return true;
1471}
1472
1473template <PrimType Name, class T = typename PrimConv<Name>::T>
1474bool EQ(InterpState &S, CodePtr OpPC) {
1475 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1476 return R == ComparisonCategoryResult::Equal;
1477 });
1478}
1479
1480template <PrimType Name, class T = typename PrimConv<Name>::T>
1481bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1482 const T &RHS = S.Stk.pop<T>();
1483 const T &LHS = S.Stk.pop<T>();
1484 const Pointer &P = S.Stk.peek<Pointer>();
1485
1486 ComparisonCategoryResult CmpResult;
1487 if constexpr (std::is_same_v<T, Pointer>) {
1488 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
1489 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
1490 DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1491 << LHS.toDiagnosticString(S.getASTContext())
1492 << RHS.toDiagnosticString(S.getASTContext());
1493 return false;
1494 }
1495 std::optional<size_t> LHSOffset =
1496 LHS.computeLayoutOffset(S.getASTContext());
1497 std::optional<size_t> RHSOffset =
1498 RHS.computeLayoutOffset(S.getASTContext());
1499 if (!LHSOffset || !RHSOffset)
1500 return false;
1501
1502 if (LHSOffset < RHSOffset)
1503 CmpResult = ComparisonCategoryResult::Less;
1504 else if (LHSOffset > RHSOffset)
1505 CmpResult = ComparisonCategoryResult::Greater;
1506 else
1507 CmpResult = ComparisonCategoryResult::Equal;
1508 } else {
1509 CmpResult = LHS.compare(RHS);
1510 }
1511
1512 assert(CmpInfo);
1513 const auto *CmpValueInfo =
1514 CmpInfo->getValueInfo(ValueKind: CmpInfo->makeWeakResult(Res: CmpResult));
1515 assert(CmpValueInfo);
1516 assert(CmpValueInfo->hasValidIntValue());
1517 return SetThreeWayComparisonField(S, OpPC, Ptr: P, IntValue: CmpValueInfo->getIntValue());
1518}
1519
1520template <PrimType Name, class T = typename PrimConv<Name>::T>
1521bool NE(InterpState &S, CodePtr OpPC) {
1522 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1523 return R != ComparisonCategoryResult::Equal;
1524 });
1525}
1526
1527template <PrimType Name, class T = typename PrimConv<Name>::T>
1528bool LT(InterpState &S, CodePtr OpPC) {
1529 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1530 return R == ComparisonCategoryResult::Less;
1531 });
1532}
1533
1534template <PrimType Name, class T = typename PrimConv<Name>::T>
1535bool LE(InterpState &S, CodePtr OpPC) {
1536 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1537 return R == ComparisonCategoryResult::Less ||
1538 R == ComparisonCategoryResult::Equal;
1539 });
1540}
1541
1542template <PrimType Name, class T = typename PrimConv<Name>::T>
1543bool GT(InterpState &S, CodePtr OpPC) {
1544 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1545 return R == ComparisonCategoryResult::Greater;
1546 });
1547}
1548
1549template <PrimType Name, class T = typename PrimConv<Name>::T>
1550bool GE(InterpState &S, CodePtr OpPC) {
1551 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1552 return R == ComparisonCategoryResult::Greater ||
1553 R == ComparisonCategoryResult::Equal;
1554 });
1555}
1556
1557//===----------------------------------------------------------------------===//
1558// Dup, Pop, Test
1559//===----------------------------------------------------------------------===//
1560
1561template <PrimType Name, class T = typename PrimConv<Name>::T>
1562bool Dup(InterpState &S) {
1563 S.Stk.push<T>(S.Stk.peek<T>());
1564 return true;
1565}
1566
1567template <PrimType Name, class T = typename PrimConv<Name>::T>
1568bool Pop(InterpState &S) {
1569 S.Stk.discard<T>();
1570 return true;
1571}
1572
1573/// [Value1, Value2] -> [Value2, Value1]
1574template <PrimType TopName, PrimType BottomName> bool Flip(InterpState &S) {
1575 using TopT = typename PrimConv<TopName>::T;
1576 using BottomT = typename PrimConv<BottomName>::T;
1577
1578 const auto &Top = S.Stk.pop<TopT>();
1579 const auto &Bottom = S.Stk.pop<BottomT>();
1580
1581 S.Stk.push<TopT>(Top);
1582 S.Stk.push<BottomT>(Bottom);
1583
1584 return true;
1585}
1586
1587//===----------------------------------------------------------------------===//
1588// Const
1589//===----------------------------------------------------------------------===//
1590
1591template <PrimType Name, class T = typename PrimConv<Name>::T>
1592bool Const(InterpState &S, const T &Arg) {
1593 if constexpr (needsAlloc<T>()) {
1594 T Result = S.allocAP<T>(Arg.bitWidth());
1595 Result.copy(Arg.toAPSInt());
1596 S.Stk.push<T>(Result);
1597 return true;
1598 }
1599
1600 if constexpr (std::is_same_v<T, uint16_t>) {
1601 S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Arg));
1602 } else if constexpr (std::is_same_v<T, int16_t>) {
1603 S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Arg));
1604 } else if constexpr (std::is_same_v<T, uint32_t>) {
1605 S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Arg));
1606 } else if constexpr (std::is_same_v<T, int32_t>) {
1607 S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Arg));
1608 } else if constexpr (std::is_same_v<T, uint64_t>) {
1609 S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Arg));
1610 } else if constexpr (std::is_same_v<T, int64_t>) {
1611 S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Arg));
1612 } else {
1613 // Bool.
1614 S.Stk.push<T>(Arg);
1615 }
1616
1617 return true;
1618}
1619
1620inline bool ConstFloat(InterpState &S, const Floating &F) {
1621 Floating Result = S.allocFloat(Sem: F.getSemantics());
1622 Result.copy(F: F.getAPFloat());
1623 S.Stk.push<Floating>(Args&: Result);
1624 return true;
1625}
1626
1627//===----------------------------------------------------------------------===//
1628// Get/Set Local/Param/Global/This
1629//===----------------------------------------------------------------------===//
1630
1631template <PrimType Name, class T = typename PrimConv<Name>::T>
1632bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1633 const Block *B = S.Current->getLocalBlock(Offset: I);
1634 if (!CheckLocalLoad(S, OpPC, B))
1635 return false;
1636 S.Stk.push<T>(B->deref<T>());
1637 return true;
1638}
1639
1640bool EndLifetime(InterpState &S, CodePtr OpPC);
1641bool PseudoDtor(InterpState &S, CodePtr OpPC);
1642bool StartThisLifetime(InterpState &S);
1643bool StartThisLifetime1(InterpState &S);
1644bool MarkDestroyed(InterpState &S, CodePtr OpPC);
1645
1646/// 1) Pops the value from the stack.
1647/// 2) Writes the value to the local variable with the
1648/// given offset.
1649template <PrimType Name, class T = typename PrimConv<Name>::T>
1650bool SetLocal(InterpState &S, uint32_t I) {
1651 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1652 return true;
1653}
1654
1655template <PrimType Name, class T = typename PrimConv<Name>::T>
1656bool GetParam(InterpState &S, uint32_t Index) {
1657 if (S.checkingPotentialConstantExpression()) {
1658 return false;
1659 }
1660 S.Stk.push<T>(S.Current->getParam<T>(Index));
1661 return true;
1662}
1663
1664template <PrimType Name, class T = typename PrimConv<Name>::T>
1665bool SetParam(InterpState &S, uint32_t I) {
1666 S.Current->setParam<T>(I, S.Stk.pop<T>());
1667 return true;
1668}
1669
1670/// 1) Peeks a pointer on the stack
1671/// 2) Pushes the value of the pointer's field on the stack
1672template <PrimType Name, class T = typename PrimConv<Name>::T>
1673bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1674 const Pointer &Obj = S.Stk.peek<Pointer>();
1675 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1676 return false;
1677 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1678 return false;
1679
1680 if (!Obj.isBlockPointer())
1681 return false;
1682
1683 // FIXME(postswitch): The isUnknownSizeArray() check here is only needed
1684 // to keep an invalid sample producing the same diagnostics as the current
1685 // interpreter.
1686 if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray())
1687 return false;
1688
1689 const Pointer &Field = Obj.atField(Off: I);
1690 if (!CheckLoad(S, OpPC, Ptr: Field))
1691 return false;
1692 S.Stk.push<T>(Field.deref<T>());
1693 return true;
1694}
1695
1696/// 1) Pops a pointer from the stack
1697/// 2) Pushes the value of the pointer's field on the stack
1698template <PrimType Name, class T = typename PrimConv<Name>::T>
1699bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1700 const Pointer &Obj = S.Stk.pop<Pointer>();
1701 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1702 return false;
1703 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1704 return false;
1705
1706 if (!Obj.isBlockPointer())
1707 return false;
1708
1709 // FIXME(postswitch): The isUnknownSizeArray() check here is only needed
1710 // to keep an invalid sample producing the same diagnostics as the current
1711 // interpreter.
1712 if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray())
1713 return false;
1714
1715 const Pointer &Field = Obj.atField(Off: I);
1716 if (!CheckLoad(S, OpPC, Ptr: Field))
1717 return false;
1718 S.Stk.push<T>(Field.deref<T>());
1719 return true;
1720}
1721
1722template <PrimType Name, class T = typename PrimConv<Name>::T>
1723bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1724 if (S.checkingPotentialConstantExpression())
1725 return false;
1726 if (!CheckThis(S, OpPC))
1727 return false;
1728 const Pointer &This = S.Current->getThis();
1729
1730 if (!This.isBlockPointer())
1731 return false;
1732
1733 const Pointer &Field = This.atField(Off: I);
1734 if (!CheckLoad(S, OpPC, Ptr: Field))
1735 return false;
1736 S.Stk.push<T>(Field.deref<T>());
1737 return true;
1738}
1739
1740template <PrimType Name, class T = typename PrimConv<Name>::T>
1741bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1742 const Block *B = S.P.getGlobal(Idx: I);
1743
1744 if (!CheckGlobalLoad(S, OpPC, B))
1745 return false;
1746
1747 S.Stk.push<T>(B->deref<T>());
1748 return true;
1749}
1750
1751/// Same as GetGlobal, but without the checks.
1752template <PrimType Name, class T = typename PrimConv<Name>::T>
1753bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1754 const Block *B = S.P.getGlobal(Idx: I);
1755 const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
1756 if (Desc.InitState != GlobalInitState::Initialized)
1757 return diagnoseUninitialized(S, OpPC, Extern: B->isExtern(), B);
1758
1759 S.Stk.push<T>(B->deref<T>());
1760 return true;
1761}
1762
1763template <PrimType Name, class T = typename PrimConv<Name>::T>
1764bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1765 // TODO: emit warning.
1766 return false;
1767}
1768
1769template <PrimType Name, class T = typename PrimConv<Name>::T>
1770bool InitGlobal(InterpState &S, uint32_t I) {
1771 const Pointer &P = S.P.getGlobal(Idx: I);
1772
1773 P.deref<T>() = S.Stk.pop<T>();
1774
1775 if constexpr (std::is_same_v<T, Floating>) {
1776 auto &Val = P.deref<Floating>();
1777 if (!Val.singleWord()) {
1778 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1779 Val.take(NewMemory);
1780 }
1781
1782 } else if constexpr (std::is_same_v<T, MemberPointer>) {
1783 auto &Val = P.deref<MemberPointer>();
1784 unsigned PathLength = Val.getPathLength();
1785 auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
1786 for (unsigned I = 0; I != PathLength; ++I) {
1787 NewPath[I] = Val.getPathEntry(Index: I);
1788 }
1789 Val.takePath(NewPath);
1790 } else if constexpr (std::is_same_v<T, Pointer>) {
1791 auto &Val = P.deref<Pointer>();
1792 if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
1793 const OpaquePointer &OP = Val.asOpaquePointer();
1794 auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
1795 std::memcpy(dest: NewPath, src: OP.Path, n: OP.PathLength * sizeof(PointerPathEntry));
1796 Val = Pointer(OP.withPath(Path: NewPath, PathLength: OP.PathLength,
1797 FieldTy: OP.getFieldType().getTypePtr(),
1798 PastEnd: OP.isOnePastEnd()),
1799 Val.getByteOffset());
1800 }
1801
1802 } else if constexpr (needsAlloc<T>()) {
1803 auto &Val = P.deref<T>();
1804 if (!Val.singleWord()) {
1805 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1806 Val.take(NewMemory);
1807 }
1808 }
1809
1810 P.initialize();
1811 return true;
1812}
1813
1814/// 1) Converts the value on top of the stack to an APValue
1815/// 2) Sets that APValue on \Temp
1816/// 3) Initializes global with index \I with that
1817template <PrimType Name, class T = typename PrimConv<Name>::T>
1818bool InitGlobalTemp(InterpState &S, uint32_t I,
1819 const LifetimeExtendedTemporaryDecl *Temp) {
1820 if (S.EvalMode == EvaluationMode::ConstantFold)
1821 return false;
1822 assert(Temp);
1823
1824 const Pointer &Ptr = S.P.getGlobal(Idx: I);
1825 assert(Ptr.getRootExpr());
1826 S.SeenGlobalTemporaries.push_back(Elt: std::make_pair(x: Ptr.getRootExpr(), y&: Temp));
1827
1828 Ptr.deref<T>() = S.Stk.pop<T>();
1829 Ptr.initialize();
1830 return true;
1831}
1832
1833/// 1) Converts the value on top of the stack to an APValue
1834/// 2) Sets that APValue on \Temp
1835/// 3) Initialized global with index \I with that
1836inline bool InitGlobalTempComp(InterpState &S,
1837 const LifetimeExtendedTemporaryDecl *Temp) {
1838 if (S.EvalMode == EvaluationMode::ConstantFold)
1839 return false;
1840 assert(Temp);
1841
1842 const Pointer &Ptr = S.Stk.peek<Pointer>();
1843 S.SeenGlobalTemporaries.push_back(Elt: std::make_pair(x: Ptr.getRootExpr(), y&: Temp));
1844 return true;
1845}
1846
1847template <PrimType Name, class T = typename PrimConv<Name>::T>
1848bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1849 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
1850 return false;
1851 if (!CheckThis(S, OpPC))
1852 return false;
1853 const Pointer &This = S.Current->getThis();
1854 if (!This.isDereferencable())
1855 return false;
1856
1857 const Pointer &Field = This.atField(Off: I);
1858 assert(Field.canBeInitialized());
1859 Field.deref<T>() = S.Stk.pop<T>();
1860 Field.initialize();
1861 return true;
1862}
1863
1864template <PrimType Name, class T = typename PrimConv<Name>::T>
1865bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1866 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
1867 return false;
1868 if (!CheckThis(S, OpPC))
1869 return false;
1870 const Pointer &This = S.Current->getThis();
1871 if (!This.isDereferencable())
1872 return false;
1873
1874 const Pointer &Field = This.atField(Off: I);
1875 assert(Field.canBeInitialized());
1876 Field.deref<T>() = S.Stk.pop<T>();
1877 Field.activate();
1878 Field.initialize();
1879 return true;
1880}
1881
1882template <PrimType Name, class T = typename PrimConv<Name>::T>
1883bool InitThisBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
1884 uint32_t FieldBitWidth) {
1885 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
1886 return false;
1887 if (!CheckThis(S, OpPC))
1888 return false;
1889 const Pointer &This = S.Current->getThis();
1890 if (!This.isDereferencable())
1891 return false;
1892
1893 const Pointer &Field = This.atField(Off: FieldOffset);
1894 assert(Field.canBeInitialized());
1895 const auto &Value = S.Stk.pop<T>();
1896
1897 if constexpr (isIntegralOrPointer<T>()) {
1898 if (!Value.isNumber())
1899 return false;
1900 }
1901
1902 Field.deref<T>() = Value.truncate(FieldBitWidth);
1903 Field.initialize();
1904 return true;
1905}
1906
1907template <PrimType Name, class T = typename PrimConv<Name>::T>
1908bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC,
1909 uint32_t FieldOffset, uint32_t FieldBitWidth) {
1910 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
1911 return false;
1912 if (!CheckThis(S, OpPC))
1913 return false;
1914 const Pointer &This = S.Current->getThis();
1915 if (!This.isDereferencable())
1916 return false;
1917
1918 const Pointer &Field = This.atField(Off: FieldOffset);
1919 assert(Field.canBeInitialized());
1920 const auto &Value = S.Stk.pop<T>();
1921
1922 if constexpr (isIntegralOrPointer<T>()) {
1923 if (!Value.isNumber())
1924 return false;
1925 }
1926
1927 Field.deref<T>() = Value.truncate(FieldBitWidth);
1928 Field.initialize();
1929 Field.activate();
1930 return true;
1931}
1932
1933/// 1) Pops the value from the stack
1934/// 2) Peeks a pointer from the stack
1935/// 3) Pushes the value to field I of the pointer on the stack
1936template <PrimType Name, class T = typename PrimConv<Name>::T>
1937bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1938 const T &Value = S.Stk.pop<T>();
1939 const Pointer &Ptr = S.Stk.peek<Pointer>();
1940 if (!Ptr.isDereferencable())
1941 return false;
1942
1943 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1944 return false;
1945 if (!CheckArray(S, OpPC, Ptr))
1946 return false;
1947
1948 const Pointer &Field = Ptr.atField(Off: I);
1949 Field.deref<T>() = Value;
1950 Field.initialize();
1951 return true;
1952}
1953
1954template <PrimType Name, class T = typename PrimConv<Name>::T>
1955bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1956 const T &Value = S.Stk.pop<T>();
1957 const Pointer &Ptr = S.Stk.peek<Pointer>();
1958 if (!Ptr.isDereferencable())
1959 return false;
1960 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1961 return false;
1962 if (!CheckArray(S, OpPC, Ptr))
1963 return false;
1964
1965 const Pointer &Field = Ptr.atField(Off: I);
1966 Field.deref<T>() = Value;
1967 Field.activate();
1968 Field.initialize();
1969 return true;
1970}
1971
1972template <PrimType Name, class T = typename PrimConv<Name>::T>
1973bool InitBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
1974 uint32_t FieldBitWidth) {
1975 const T &Value = S.Stk.pop<T>();
1976 const Pointer &Ptr = S.Stk.peek<Pointer>();
1977 if (!Ptr.isDereferencable())
1978 return false;
1979
1980 if constexpr (isIntegralOrPointer<T>()) {
1981 if (!Value.isNumber())
1982 return false;
1983 }
1984 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1985 return false;
1986 if (!CheckArray(S, OpPC, Ptr))
1987 return false;
1988
1989 const Pointer &Field = Ptr.atField(Off: FieldOffset);
1990
1991 unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
1992 if constexpr (needsAlloc<T>()) {
1993 T Result = S.allocAP<T>(Value.bitWidth());
1994 if constexpr (T::isSigned())
1995 Result.copy(
1996 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
1997 else
1998 Result.copy(
1999 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
2000
2001 Field.deref<T>() = Result;
2002 } else {
2003 Field.deref<T>() = Value.truncate(FieldBitWidth);
2004 }
2005 Field.initialize();
2006 return true;
2007}
2008
2009template <PrimType Name, class T = typename PrimConv<Name>::T>
2010bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
2011 uint32_t FieldBitWidth) {
2012 const T &Value = S.Stk.pop<T>();
2013 const Pointer &Ptr = S.Stk.peek<Pointer>();
2014 if (!Ptr.isDereferencable())
2015 return false;
2016
2017 if constexpr (isIntegralOrPointer<T>()) {
2018 if (!Value.isNumber())
2019 return false;
2020 }
2021 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
2022 return false;
2023 if (!CheckArray(S, OpPC, Ptr))
2024 return false;
2025
2026 const Pointer &Field = Ptr.atField(Off: FieldOffset);
2027
2028 unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
2029 if constexpr (needsAlloc<T>()) {
2030 T Result = S.allocAP<T>(Value.bitWidth());
2031 if constexpr (T::isSigned())
2032 Result.copy(
2033 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
2034 else
2035 Result.copy(
2036 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
2037
2038 Field.deref<T>() = Result;
2039 } else {
2040 Field.deref<T>() = Value.truncate(FieldBitWidth);
2041 }
2042 Field.activate();
2043 Field.initialize();
2044 return true;
2045}
2046
2047//===----------------------------------------------------------------------===//
2048// GetPtr Local/Param/Global/Field/This
2049//===----------------------------------------------------------------------===//
2050
2051inline bool GetPtrLocal(InterpState &S, uint32_t I) {
2052 S.Stk.push<Pointer>(Args: S.Current->getLocalPointer(Offset: I));
2053 return true;
2054}
2055
2056inline bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
2057 Block *LocalBlock = S.Current->getLocalBlock(Offset: I);
2058 return handleReference(S, OpPC, B: LocalBlock);
2059}
2060
2061inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
2062 Block *B = S.P.getGlobal(Idx: I);
2063
2064 // If we're currently evaluating this variable, use that in-flight value.
2065 // It will otherwise be diagnosed as non-initialized reference and we will
2066 // complain about a missing initializer.
2067 if (S.EvaluatingDecl && B->getDescriptor()->asVarDecl() == S.EvaluatingDecl) {
2068 S.Stk.push<Pointer>(Args&: B);
2069 return true;
2070 }
2071
2072 if (isConstexprUnknown(B)) {
2073 S.Stk.push<Pointer>(Args&: B);
2074 return true;
2075 }
2076
2077 const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
2078 if (Desc.InitState != GlobalInitState::Initialized)
2079 return diagnoseUninitialized(S, OpPC, Extern: B->isExtern(), B);
2080
2081 S.Stk.push<Pointer>(Args&: B->deref<Pointer>());
2082 return true;
2083}
2084
2085inline bool CheckRefInit(InterpState &S, CodePtr OpPC) {
2086 const Pointer &Ptr = S.Stk.peek<Pointer>();
2087 return CheckRange(S, OpPC, Ptr, AK: AK_Read);
2088}
2089
2090inline bool GetPtrParam(InterpState &S, uint32_t Index) {
2091 if (S.Current->isBottomFrame())
2092 return false;
2093 S.Stk.push<Pointer>(Args: S.Current->getParamPointer(Offset: Index));
2094 return true;
2095}
2096
2097inline bool GetPtrGlobal(InterpState &S, uint32_t I) {
2098 S.Stk.push<Pointer>(Args: S.P.getPtrGlobal(Idx: I));
2099 return true;
2100}
2101
2102/// 1) Peeks a Pointer
2103/// 2) Pushes Pointer.atField(Off) on the stack
2104bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
2105bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
2106
2107bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off);
2108bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK);
2109
2110bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK,
2111 const Type *TargetType);
2112
2113inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
2114 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
2115 return false;
2116 if (!CheckThis(S, OpPC))
2117 return false;
2118 const Pointer &This = S.Current->getThis();
2119 if (!This.isBlockPointer())
2120 return false;
2121 S.Stk.push<Pointer>(Args: This.atField(Off));
2122 return true;
2123}
2124
2125inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
2126 if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
2127 return false;
2128 if (!CheckThis(S, OpPC))
2129 return false;
2130 const Pointer &This = S.Current->getThis();
2131 S.Stk.push<Pointer>(Args: This.atField(Off));
2132 return true;
2133}
2134
2135inline bool FinishInitPop(InterpState &S) {
2136 const Pointer &Ptr = S.Stk.pop<Pointer>();
2137 if (Ptr.canBeInitialized())
2138 Ptr.initialize();
2139 return true;
2140}
2141
2142inline bool FinishInit(InterpState &S) {
2143 const Pointer &Ptr = S.Stk.peek<Pointer>();
2144 if (Ptr.canBeInitialized())
2145 Ptr.initialize();
2146 return true;
2147}
2148
2149inline bool FinishInitActivate(InterpState &S) {
2150 const Pointer &Ptr = S.Stk.peek<Pointer>();
2151 if (Ptr.canBeInitialized()) {
2152 Ptr.initialize();
2153 Ptr.activate();
2154 }
2155 return true;
2156}
2157
2158inline bool FinishInitActivatePop(InterpState &S) {
2159 const Pointer &Ptr = S.Stk.pop<Pointer>();
2160 if (Ptr.canBeInitialized()) {
2161 Ptr.initialize();
2162 Ptr.activate();
2163 }
2164 return true;
2165}
2166
2167bool FinishInitGlobal(InterpState &S);
2168
2169inline bool Dump(InterpState &S) {
2170 S.Stk.dump();
2171 return true;
2172}
2173
2174inline bool CheckNull(InterpState &S, CodePtr OpPC) {
2175 const auto &Ptr = S.Stk.peek<Pointer>();
2176 if (Ptr.isZero()) {
2177 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2178 DiagId: diag::note_constexpr_dereferencing_null);
2179 return S.noteUndefinedBehavior();
2180 }
2181 return true;
2182}
2183
2184bool virtBaseHelper(InterpState &S, const CXXRecordDecl *Decl,
2185 const Pointer &Ptr);
2186
2187inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
2188 const CXXRecordDecl *D) {
2189 assert(D);
2190 const Pointer &Ptr = S.Stk.pop<Pointer>();
2191 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
2192 return false;
2193 return virtBaseHelper(S, Decl: D, Ptr);
2194}
2195
2196inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC,
2197 const CXXRecordDecl *D) {
2198 assert(D);
2199 const Pointer &Ptr = S.Stk.peek<Pointer>();
2200 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
2201 return false;
2202 return virtBaseHelper(S, Decl: D, Ptr);
2203}
2204
2205inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
2206 const CXXRecordDecl *D) {
2207 assert(D);
2208 if (S.checkingPotentialConstantExpression())
2209 return false;
2210 if (!CheckThis(S, OpPC))
2211 return false;
2212 const Pointer &This = S.Current->getThis();
2213 return virtBaseHelper(S, Decl: D, Ptr: This);
2214}
2215
2216//===----------------------------------------------------------------------===//
2217// Load, Store, Init
2218//===----------------------------------------------------------------------===//
2219
2220template <PrimType Name, class T = typename PrimConv<Name>::T>
2221bool Load(InterpState &S, CodePtr OpPC) {
2222 const Pointer &Ptr = S.Stk.peek<Pointer>();
2223 if (!CheckLoad(S, OpPC, Ptr))
2224 return false;
2225 if (!Ptr.isReadablePointerType())
2226 return false;
2227 if (!Ptr.canDeref(T: Name))
2228 return false;
2229 S.Stk.push<T>(Ptr.load<T>());
2230 return true;
2231}
2232
2233template <PrimType Name, class T = typename PrimConv<Name>::T>
2234bool LoadPop(InterpState &S, CodePtr OpPC) {
2235 const Pointer &Ptr = S.Stk.pop<Pointer>();
2236 if (!CheckLoad(S, OpPC, Ptr))
2237 return false;
2238 if (!Ptr.isReadablePointerType())
2239 return false;
2240 if (!Ptr.canDeref(T: Name))
2241 return false;
2242 S.Stk.push<T>(Ptr.load<T>());
2243 return true;
2244}
2245
2246/// Like LoadPop above, but if any of the checks fail, we
2247/// turn the pointer into an opaque pointer of appropriate type.
2248inline bool LoadPopL(InterpState &S, CodePtr OpPC) {
2249 const Pointer &Ptr = S.Stk.pop<Pointer>();
2250 auto *P = S.getEvalStatus().Diag;
2251 S.getEvalStatus().Diag = nullptr;
2252
2253 bool Failed = false;
2254 if (!CheckLoad(S, OpPC, Ptr))
2255 Failed = true;
2256 if (!Ptr.isBlockPointer())
2257 Failed = true;
2258 if (!Failed && !Ptr.canDeref(T: PT_Ptr))
2259 Failed = true;
2260 S.getEvalStatus().Diag = P;
2261
2262 if (Failed) {
2263 if (Ptr.isOpaquePointer()) {
2264 const OpaquePointer &OP = Ptr.asOpaquePointer();
2265
2266 if (!Ptr.asOpaquePointer().Base.getType()->isPointerType())
2267 return false;
2268
2269 QualType T = Ptr.getType();
2270 S.Stk.push<Pointer>(Args: OP.withFieldType(FieldTy: T.getTypePtr()),
2271 Args: Ptr.getByteOffset());
2272 return true;
2273 }
2274
2275 // Convert the block pointer to an opaque pointer.
2276 if (!Ptr.isBlockPointer())
2277 return false;
2278 // FIXME: I *think* we need more information here than just the base.
2279 S.Stk.push<Pointer>(Args: Ptr.getDeclDesc()->asValueDecl());
2280 } else {
2281 S.Stk.push<Pointer>(Args&: Ptr.deref<Pointer>());
2282 }
2283 return true;
2284}
2285
2286template <PrimType Name, class T = typename PrimConv<Name>::T>
2287bool Store(InterpState &S, CodePtr OpPC) {
2288 const T &Value = S.Stk.pop<T>();
2289 const Pointer &Ptr = S.Stk.peek<Pointer>();
2290 if (!CheckStore(S, OpPC, Ptr))
2291 return false;
2292 if (!Ptr.canDeref(T: Name))
2293 return false;
2294 if (Ptr.canBeInitialized())
2295 Ptr.initialize();
2296 Ptr.deref<T>() = Value;
2297 return true;
2298}
2299
2300template <PrimType Name, class T = typename PrimConv<Name>::T>
2301bool StorePop(InterpState &S, CodePtr OpPC) {
2302 const T &Value = S.Stk.pop<T>();
2303 const Pointer &Ptr = S.Stk.pop<Pointer>();
2304 if (!CheckStore(S, OpPC, Ptr))
2305 return false;
2306 if (!Ptr.canDeref(T: Name))
2307 return false;
2308 if (Ptr.canBeInitialized())
2309 Ptr.initialize();
2310 Ptr.deref<T>() = Value;
2311 return true;
2312}
2313
2314static inline bool Activate(InterpState &S) {
2315 const Pointer &Ptr = S.Stk.peek<Pointer>();
2316 if (Ptr.canBeInitialized())
2317 Ptr.activate();
2318 return true;
2319}
2320
2321static inline bool ActivateThisField(InterpState &S, uint32_t I) {
2322 if (S.checkingPotentialConstantExpression())
2323 return false;
2324 if (!S.Current->hasThisPointer())
2325 return false;
2326
2327 const Pointer &Ptr = S.Current->getThis();
2328 assert(Ptr.atField(I).canBeInitialized());
2329 Ptr.atField(Off: I).activate();
2330 return true;
2331}
2332
2333template <PrimType Name, class T = typename PrimConv<Name>::T>
2334bool StoreActivate(InterpState &S, CodePtr OpPC) {
2335 const T &Value = S.Stk.pop<T>();
2336 const Pointer &Ptr = S.Stk.peek<Pointer>();
2337
2338 if (!CheckStore(S, OpPC, Ptr, AK: AK_Assign, /*WillBeActivated=*/WillBeActivated: true))
2339 return false;
2340 if (Ptr.canBeInitialized()) {
2341 Ptr.initialize();
2342 Ptr.activate();
2343 }
2344 Ptr.deref<T>() = Value;
2345 return true;
2346}
2347
2348template <PrimType Name, class T = typename PrimConv<Name>::T>
2349bool StoreActivatePop(InterpState &S, CodePtr OpPC) {
2350 const T &Value = S.Stk.pop<T>();
2351 const Pointer &Ptr = S.Stk.pop<Pointer>();
2352
2353 if (!CheckStore(S, OpPC, Ptr, AK: AK_Assign, /*WillBeActivated=*/WillBeActivated: true))
2354 return false;
2355 if (Ptr.canBeInitialized()) {
2356 Ptr.initialize();
2357 Ptr.activate();
2358 }
2359 Ptr.deref<T>() = Value;
2360 return true;
2361}
2362
2363template <PrimType Name, class T = typename PrimConv<Name>::T>
2364bool StoreBitField(InterpState &S, CodePtr OpPC) {
2365 const T &Value = S.Stk.pop<T>();
2366 const Pointer &Ptr = S.Stk.peek<Pointer>();
2367
2368 if (!CheckStore(S, OpPC, Ptr))
2369 return false;
2370 if (Ptr.canBeInitialized())
2371 Ptr.initialize();
2372 if (const auto *FD = Ptr.getField())
2373 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2374 else
2375 Ptr.deref<T>() = Value;
2376 return true;
2377}
2378
2379template <PrimType Name, class T = typename PrimConv<Name>::T>
2380bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
2381 const T &Value = S.Stk.pop<T>();
2382 const Pointer &Ptr = S.Stk.pop<Pointer>();
2383 if (!CheckStore(S, OpPC, Ptr))
2384 return false;
2385 if (Ptr.canBeInitialized())
2386 Ptr.initialize();
2387 if (const auto *FD = Ptr.getField())
2388 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2389 else
2390 Ptr.deref<T>() = Value;
2391 return true;
2392}
2393
2394template <PrimType Name, class T = typename PrimConv<Name>::T>
2395bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) {
2396 const T &Value = S.Stk.pop<T>();
2397 const Pointer &Ptr = S.Stk.peek<Pointer>();
2398
2399 if (!CheckStore(S, OpPC, Ptr, AK: AK_Assign, /*WillBeActivated=*/WillBeActivated: true))
2400 return false;
2401 if (Ptr.canBeInitialized()) {
2402 Ptr.initialize();
2403 Ptr.activate();
2404 }
2405 if (const auto *FD = Ptr.getField())
2406 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2407 else
2408 Ptr.deref<T>() = Value;
2409 return true;
2410}
2411
2412template <PrimType Name, class T = typename PrimConv<Name>::T>
2413bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC) {
2414 const T &Value = S.Stk.pop<T>();
2415 const Pointer &Ptr = S.Stk.pop<Pointer>();
2416
2417 if (!CheckStore(S, OpPC, Ptr, AK: AK_Assign, /*WillBeActivated=*/WillBeActivated: true))
2418 return false;
2419 if (Ptr.canBeInitialized()) {
2420 Ptr.initialize();
2421 Ptr.activate();
2422 }
2423 if (const auto *FD = Ptr.getField())
2424 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2425 else
2426 Ptr.deref<T>() = Value;
2427 return true;
2428}
2429
2430template <PrimType Name, class T = typename PrimConv<Name>::T>
2431bool Init(InterpState &S, CodePtr OpPC) {
2432 const T &Value = S.Stk.pop<T>();
2433 const Pointer &Ptr = S.Stk.peek<Pointer>();
2434 if (!CheckInit(S, OpPC, Ptr))
2435 return false;
2436 Ptr.initialize();
2437 new (&Ptr.deref<T>()) T(Value);
2438 return true;
2439}
2440
2441template <PrimType Name, class T = typename PrimConv<Name>::T>
2442bool InitPop(InterpState &S, CodePtr OpPC) {
2443 const T &Value = S.Stk.pop<T>();
2444 const Pointer &Ptr = S.Stk.pop<Pointer>();
2445 if (!CheckInit(S, OpPC, Ptr))
2446 return false;
2447 Ptr.initialize();
2448 new (&Ptr.deref<T>()) T(Value);
2449 return true;
2450}
2451
2452/// 1) Pops the value from the stack
2453/// 2) Peeks a pointer and gets its index \Idx
2454/// 3) Sets the value on the pointer, leaving the pointer on the stack.
2455template <PrimType Name, class T = typename PrimConv<Name>::T>
2456bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2457 const T &Value = S.Stk.pop<T>();
2458 const Pointer &Ptr = S.Stk.peek<Pointer>();
2459
2460 if (Ptr.isConstexprUnknown())
2461 return false;
2462
2463 const Descriptor *Desc = Ptr.getFieldDesc();
2464 if (Desc->isUnknownSizeArray())
2465 return false;
2466
2467 // In the unlikely event that we're initializing the first item of
2468 // a non-array, skip the atIndex().
2469 if (Idx == 0 && !Desc->isArray()) {
2470 Ptr.initialize();
2471 new (&Ptr.deref<T>()) T(Value);
2472 return true;
2473 }
2474
2475 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
2476 return false;
2477 if (Idx >= Desc->getNumElems()) {
2478 // CheckRange.
2479 if (S.getLangOpts().CPlusPlus) {
2480 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2481 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_access_past_end)
2482 << AK_Assign << S.Current->getRange(PC: OpPC);
2483 }
2484 return false;
2485 }
2486 Ptr.initializeElement(Index: Idx);
2487 new (&Ptr.elem<T>(Idx)) T(Value);
2488 return true;
2489}
2490
2491/// The same as InitElem, but pops the pointer as well.
2492template <PrimType Name, class T = typename PrimConv<Name>::T>
2493bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2494 const T &Value = S.Stk.pop<T>();
2495 const Pointer &Ptr = S.Stk.pop<Pointer>();
2496
2497 if (Ptr.isConstexprUnknown())
2498 return false;
2499
2500 const Descriptor *Desc = Ptr.getFieldDesc();
2501 if (Desc->isUnknownSizeArray())
2502 return false;
2503
2504 // In the unlikely event that we're initializing the first item of
2505 // a non-array, skip the atIndex().
2506 if (Idx == 0 && !Desc->isArray()) {
2507 Ptr.initialize();
2508 new (&Ptr.deref<T>()) T(Value);
2509 return true;
2510 }
2511
2512 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
2513 return false;
2514 if (Idx >= Desc->getNumElems()) {
2515 // CheckRange.
2516 if (S.getLangOpts().CPlusPlus) {
2517 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2518 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_access_past_end)
2519 << AK_Assign << S.Current->getRange(PC: OpPC);
2520 }
2521 return false;
2522 }
2523 Ptr.initializeElement(Index: Idx);
2524 new (&Ptr.elem<T>(Idx)) T(Value);
2525 return true;
2526}
2527
2528inline bool ToMemberPtr(InterpState &S) {
2529 const auto &Member = S.Stk.pop<MemberPointer>();
2530 const auto &Base = S.Stk.pop<Pointer>();
2531
2532 S.Stk.push<MemberPointer>(Args: Member.takeInstance(Instance: Base));
2533 return true;
2534}
2535
2536inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
2537 const auto &MP = S.Stk.pop<MemberPointer>();
2538
2539 if (std::optional<Pointer> Ptr = MP.toPointer(Ctx: S.Ctx)) {
2540 S.Stk.push<Pointer>(Args&: *Ptr);
2541 return true;
2542 }
2543 return Invalid(S, OpPC);
2544}
2545
2546bool Memcpy(InterpState &S, CodePtr OpPC);
2547bool TrivialCopy(InterpState &S, CodePtr OpPC, bool Activate,
2548 const Function *Func);
2549
2550//===----------------------------------------------------------------------===//
2551// AddOffset, SubOffset
2552//===----------------------------------------------------------------------===//
2553
2554template <class T, ArithOp Op>
2555std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
2556 const T &Offset, const Pointer &Ptr,
2557 bool IsPointerArith = false) {
2558 // A zero offset does not change the pointer.
2559 if (Offset.isZero())
2560 return Ptr;
2561
2562 if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK: CSK_ArrayIndex)) {
2563 // The CheckNull will have emitted a note already, but we only
2564 // abort in C++, since this is fine in C.
2565 if (S.getLangOpts().CPlusPlus)
2566 return std::nullopt;
2567 }
2568
2569 // Arrays of unknown bounds cannot have pointers into them.
2570 if (!CheckArray(S, OpPC, Ptr))
2571 return std::nullopt;
2572
2573 // This is much simpler for integral pointers, so handle them first.
2574 if (Ptr.isIntegralPointer()) {
2575 uint64_t V = Ptr.getIntegerRepresentation();
2576 QualType ElemType = Ptr.asIntPointer().getPointeeType();
2577 uint64_t ElemSize =
2578 (ElemType.isNull() || ElemType->isVoidType())
2579 ? 1u
2580 : S.getASTContext().getTypeSizeInChars(T: ElemType).getQuantity();
2581 uint64_t O = static_cast<uint64_t>(Offset) * ElemSize;
2582 if constexpr (Op == ArithOp::Add) {
2583 return Pointer(V + O, Ptr.asIntPointer().Ty);
2584 } else
2585 return Pointer(V - O, Ptr.asIntPointer().Ty);
2586 } else if (Ptr.isFunctionPointer()) {
2587 uint64_t O = static_cast<uint64_t>(Offset);
2588 uint64_t N;
2589 if constexpr (Op == ArithOp::Add)
2590 N = Ptr.getByteOffset() + O;
2591 else
2592 N = Ptr.getByteOffset() - O;
2593
2594 if (N > 1)
2595 diagnoseArrayIndex(S, OpPC, Index: APSInt::getUnsigned(X: N), NumElems: 0, /*IsArray=*/IsArray: false);
2596 return Pointer(Ptr.asFunctionPointer().Func, N);
2597 } else if (Ptr.isStringPointer()) {
2598 int64_t NewOffset;
2599 if constexpr (Op == ArithOp::Add)
2600 NewOffset = Ptr.getByteOffset() + static_cast<int64_t>(Offset);
2601 else
2602 NewOffset = Ptr.getByteOffset() - static_cast<int64_t>(Offset);
2603 if (NewOffset < 0 ||
2604 NewOffset > (Ptr.asStringPointer().getLiteral()->getLength() + 1)) {
2605 diagnoseArrayIndex(S, OpPC, Index: APSInt::get(X: NewOffset),
2606 NumElems: (Ptr.asStringPointer().getLiteral()->getLength() + 1));
2607 return std::nullopt;
2608 }
2609 return Pointer(Ptr.asStringPointer(), NewOffset);
2610 } else if (!Ptr.isBlockPointer()) {
2611 return std::nullopt;
2612 }
2613
2614 assert(Ptr.isBlockPointer());
2615
2616 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
2617 uint64_t Index;
2618 if (Ptr.isOnePastEnd())
2619 Index = MaxIndex;
2620 else
2621 Index = Ptr.getIndex();
2622
2623 bool Invalid = false;
2624 // Helper to report an invalid offset, computed as APSInt.
2625 auto DiagInvalidOffset = [&]() -> void {
2626 const unsigned Bits = Offset.bitWidth();
2627 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
2628 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
2629 /*IsUnsigned=*/false);
2630 APSInt NewIndex =
2631 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2632 diagnoseArrayIndex(S, OpPC, Index: NewIndex, NumElems: MaxIndex, IsArray: Ptr.inArray());
2633 Invalid = true;
2634 };
2635
2636 uint64_t IOffset = static_cast<uint64_t>(Offset);
2637 uint64_t MaxOffset = MaxIndex - Index;
2638
2639 if constexpr (Op == ArithOp::Add) {
2640 // If the new offset would be negative, bail out.
2641 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2642 DiagInvalidOffset();
2643
2644 // If the new offset would be out of bounds, bail out.
2645 if (Offset.isPositive() && IOffset > MaxOffset)
2646 DiagInvalidOffset();
2647 } else {
2648 // If the new offset would be negative, bail out.
2649 if (Offset.isPositive() && Index < IOffset)
2650 DiagInvalidOffset();
2651
2652 // If the new offset would be out of bounds, bail out.
2653 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2654 DiagInvalidOffset();
2655 }
2656
2657 if (Invalid && (S.getLangOpts().CPlusPlus || Ptr.inArray()))
2658 return std::nullopt;
2659
2660 // Offset is valid - compute it on unsigned.
2661 int64_t WideIndex = static_cast<int64_t>(Index);
2662 int64_t WideOffset = static_cast<int64_t>(Offset);
2663 int64_t Result;
2664 if constexpr (Op == ArithOp::Add)
2665 Result = WideIndex + WideOffset;
2666 else
2667 Result = WideIndex - WideOffset;
2668
2669 // When the pointer is one-past-end, going back to index 0 is the only
2670 // useful thing we can do. Any other index has been diagnosed before and
2671 // we don't get here.
2672 if (Result == 0 && Ptr.isOnePastEnd()) {
2673 if (Ptr.getFieldDesc()->isArray())
2674 return Ptr.atIndex(Idx: 0);
2675 return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2676 }
2677
2678 return Ptr.atIndex(Idx: static_cast<uint64_t>(Result));
2679}
2680
2681std::optional<Pointer> addSubOffsetOpaque(InterpState &S, CodePtr OpPC,
2682 const Pointer &Ptr, APSInt &&Offset,
2683 ArithOp Op);
2684template <PrimType Name, class T = typename PrimConv<Name>::T>
2685bool AddOffset(InterpState &S, CodePtr OpPC) {
2686 const T &Offset = S.Stk.pop<T>();
2687 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2688
2689 if (Ptr.isOpaquePointer()) {
2690 if (std::optional<Pointer> Result =
2691 addSubOffsetOpaque(S, OpPC, Ptr, Offset.toAPSInt(), ArithOp::Add)) {
2692 S.Stk.push<Pointer>(Args&: *Result);
2693 return true;
2694 }
2695 return false;
2696 }
2697
2698 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
2699 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2700 S.Stk.push<Pointer>(Args: Result->narrow());
2701 return true;
2702 }
2703 return false;
2704}
2705
2706template <PrimType Name, class T = typename PrimConv<Name>::T>
2707bool SubOffset(InterpState &S, CodePtr OpPC) {
2708 const T &Offset = S.Stk.pop<T>();
2709 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2710
2711 if (Ptr.isOpaquePointer()) {
2712 if (std::optional<Pointer> Result =
2713 addSubOffsetOpaque(S, OpPC, Ptr, Offset.toAPSInt(), ArithOp::Sub)) {
2714 S.Stk.push<Pointer>(Args&: *Result);
2715 return true;
2716 }
2717 return false;
2718 }
2719
2720 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
2721 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2722 S.Stk.push<Pointer>(Args: Result->narrow());
2723 return true;
2724 }
2725 return false;
2726}
2727
2728inline bool GetOpaquePtr(InterpState &S, DeclOrExpr DOE,
2729 bool ConstexprUnknown) {
2730 S.Stk.push<Pointer>(Args&: DOE, Args&: ConstexprUnknown);
2731 return true;
2732}
2733
2734template <ArithOp Op>
2735static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2736 const Pointer &Ptr) {
2737 if (!Ptr.isDereferencable())
2738 return false;
2739
2740 using OneT = Char<false>;
2741
2742 const Pointer &P = Ptr.deref<Pointer>();
2743 if (!CheckNull(S, OpPC, Ptr: P, CSK: CSK_ArrayIndex))
2744 return false;
2745
2746 // Get the current value on the stack.
2747 S.Stk.push<Pointer>(Args: P);
2748
2749 if (P.isOpaquePointer()) {
2750 if (std::optional<Pointer> Result =
2751 addSubOffsetOpaque(S, OpPC, Ptr: P, Offset: APSInt(APInt(1, 1), true), Op)) {
2752 Ptr.deref<Pointer>() = *Result;
2753 return true;
2754 }
2755 return false;
2756 }
2757
2758 // Now the current Ptr again and a constant 1.
2759 OneT One = OneT::from(t: 1);
2760 if (std::optional<Pointer> Result =
2761 OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {
2762 // Store the new value.
2763 Ptr.deref<Pointer>() = Result->narrow();
2764 return true;
2765 }
2766 return false;
2767}
2768
2769static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2770 const Pointer &Ptr = S.Stk.pop<Pointer>();
2771
2772 if (!Ptr.isInitialized())
2773 return diagnoseUninitialized(S, OpPC, Ptr, AK: AK_Increment);
2774
2775 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2776}
2777
2778static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2779 const Pointer &Ptr = S.Stk.pop<Pointer>();
2780
2781 if (!Ptr.isInitialized())
2782 return diagnoseUninitialized(S, OpPC, Ptr, AK: AK_Decrement);
2783
2784 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2785}
2786
2787/// 1) Pops a Pointer from the stack.
2788/// 2) Pops another Pointer from the stack.
2789/// 3) Pushes the difference of the indices of the two pointers on the stack.
2790template <PrimType Name, class T = typename PrimConv<Name>::T>
2791inline bool SubPtr(InterpState &S, CodePtr OpPC, uint32_t ElemSize) {
2792 const Pointer &LHS = S.Stk.pop<Pointer>().expand();
2793 const Pointer &RHS = S.Stk.pop<Pointer>().expand();
2794
2795 if (LHS.pointsToLabel() || RHS.pointsToLabel()) {
2796 if constexpr (isIntegralOrPointer<T>()) {
2797 const AddrLabelExpr *LHSAddrExpr = LHS.getPointedToLabel();
2798 const AddrLabelExpr *RHSAddrExpr = RHS.getPointedToLabel();
2799 if (!LHSAddrExpr || !RHSAddrExpr) {
2800 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2801 DiagId: diag::note_constexpr_pointer_arith_unspecified)
2802 << LHS.toDiagnosticString(Ctx: S.getASTContext())
2803 << RHS.toDiagnosticString(Ctx: S.getASTContext());
2804 return false;
2805 }
2806
2807 if (LHSAddrExpr->getLabel()->getDeclContext() !=
2808 RHSAddrExpr->getLabel()->getDeclContext())
2809 return Invalid(S, OpPC);
2810
2811 S.Stk.push<T>(LHSAddrExpr, RHSAddrExpr);
2812 return true;
2813 }
2814 // Can't represent an address-label-diff in these types.
2815 return false;
2816 }
2817
2818 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
2819 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2820 DiagId: diag::note_constexpr_pointer_arith_unspecified)
2821 << LHS.toDiagnosticString(Ctx: S.getASTContext())
2822 << RHS.toDiagnosticString(Ctx: S.getASTContext());
2823 return false;
2824 }
2825
2826 if (ElemSize == 0) {
2827 QualType PtrT = S.getASTContext().getBaseElementType(QT: LHS.getType());
2828 QualType ArrayTy = S.getASTContext().getConstantArrayType(
2829 EltTy: PtrT, ArySize: APInt::getZero(numBits: 1), SizeExpr: nullptr, ASM: ArraySizeModifier::Normal, IndexTypeQuals: 0);
2830 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2831 DiagId: diag::note_constexpr_pointer_subtraction_zero_size)
2832 << ArrayTy;
2833
2834 return false;
2835 }
2836
2837 if (LHS == RHS) {
2838 S.Stk.push<T>();
2839 return true;
2840 }
2841
2842 // C++11 [expr.add]p6:
2843 // Unless both pointers point to elements of the same array object, or
2844 // one past the last element of the array object, the behavior is
2845 // undefined.
2846 if (LHS.isBlockPointer() && !Pointer::elemsOfSameArray(A: LHS, B: RHS))
2847 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
2848 DiagId: diag::note_constexpr_pointer_subtraction_not_same_array);
2849
2850 std::optional<size_t> VL = LHS.computeLayoutOffset(ASTCtx: S.getASTContext());
2851 if (!VL)
2852 return false;
2853 std::optional<size_t> VR = RHS.computeLayoutOffset(ASTCtx: S.getASTContext());
2854 if (!VR)
2855 return false;
2856
2857 // We allow (VL - VR) / Elemsize to have non-zero remainder. This happens for
2858 // invalid expressions where LHS and RHS are of different types.
2859 int64_t R64 =
2860 (static_cast<int64_t>(*VL) - static_cast<int64_t>(*VR)) / ElemSize;
2861 if (static_cast<int64_t>(T::from(R64)) != R64)
2862 return handleOverflow(S, OpPC, SrcValue: R64);
2863
2864 S.Stk.push<T>(T::from(R64));
2865 return true;
2866}
2867
2868inline bool InitScope(InterpState &S, uint32_t I) {
2869 S.Current->initScope(Idx: I);
2870 return true;
2871}
2872
2873inline bool EnableLocal(InterpState &S, uint32_t I) {
2874 assert(!S.Current->isLocalEnabled(I));
2875 S.Current->enableLocal(Idx: I);
2876 return true;
2877}
2878
2879inline bool GetLocalEnabled(InterpState &S, uint32_t I) {
2880 assert(S.Current);
2881 S.Stk.push<bool>(Args: S.Current->isLocalEnabled(Idx: I));
2882 return true;
2883}
2884
2885//===----------------------------------------------------------------------===//
2886// Cast, CastFP
2887//===----------------------------------------------------------------------===//
2888
2889template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2890 using T = typename PrimConv<TIn>::T;
2891 using U = typename PrimConv<TOut>::T;
2892
2893 auto In = S.Stk.pop<T>();
2894
2895 if constexpr (isIntegralOrPointer<T>()) {
2896 if (In.getKind() != IntegralKind::Number &&
2897 In.getKind() != IntegralKind::AddrLabelDiff) {
2898 if (!CheckIntegralAddressCast(S, OpPC, U::bitWidth()))
2899 return Invalid(S, OpPC);
2900 } else if (In.getKind() == IntegralKind::AddrLabelDiff) {
2901 // Allow casts of address-of-label differences if they are no-ops
2902 // or narrowing, if the result is at least 32 bits wide.
2903 // (The narrowing case isn't actually guaranteed to
2904 // be constant-evaluatable except in some narrow cases which are hard
2905 // to detect here. We let it through on the assumption the user knows
2906 // what they are doing.)
2907 if (!(U::bitWidth() >= 32 && U::bitWidth() <= In.bitWidth()))
2908 return false;
2909 }
2910 }
2911
2912 S.Stk.push<U>(U::from(In));
2913 return true;
2914}
2915
2916/// 1) Pops a Floating from the stack.
2917/// 2) Pushes a new floating on the stack that uses the given semantics.
2918inline bool CastFP(InterpState &S, const llvm::fltSemantics *Sem,
2919 llvm::RoundingMode RM) {
2920 Floating F = S.Stk.pop<Floating>();
2921 Floating Result = S.allocFloat(Sem: *Sem);
2922 F.toSemantics(Sem, RM, Result: &Result);
2923 S.Stk.push<Floating>(Args&: Result);
2924 return true;
2925}
2926
2927inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2928 FixedPointSemantics TargetSemantics =
2929 FixedPointSemantics::getFromOpaqueInt(FPS);
2930 const auto &Source = S.Stk.pop<FixedPoint>();
2931
2932 bool Overflow;
2933 FixedPoint Result = Source.toSemantics(Sem: TargetSemantics, Overflow: &Overflow);
2934
2935 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
2936 return false;
2937
2938 S.Stk.push<FixedPoint>(Args&: Result);
2939 return true;
2940}
2941
2942/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2943/// to know what bitwidth the result should be.
2944template <PrimType Name, class T = typename PrimConv<Name>::T>
2945bool CastAP(InterpState &S, uint32_t BitWidth) {
2946 T Source = S.Stk.pop<T>();
2947
2948 if constexpr (isIntegralOrPointer<T>()) {
2949 if (!Source.isNumber())
2950 return false;
2951 }
2952
2953 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2954 // Copy data.
2955 {
2956 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2957 Result.copy(V: SourceInt);
2958 }
2959 S.Stk.push<IntegralAP<false>>(Args&: Result);
2960 return true;
2961}
2962
2963template <PrimType Name, class T = typename PrimConv<Name>::T>
2964bool CastAPS(InterpState &S, uint32_t BitWidth) {
2965 T Source = S.Stk.pop<T>();
2966
2967 if constexpr (isIntegralOrPointer<T>()) {
2968 if (!Source.isNumber())
2969 return false;
2970 }
2971
2972 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2973 // Copy data.
2974 {
2975 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2976 Result.copy(V: SourceInt);
2977 }
2978 S.Stk.push<IntegralAP<true>>(Args&: Result);
2979 return true;
2980}
2981
2982// Cast an AP integer to Sint64 for use as an offsetof array index, failing
2983// constant evaluation if the value is negative or too large to fit in Sint64
2984// (i.e. truncation would change the value).
2985template <PrimType Name, class T = typename PrimConv<Name>::T>
2986bool CastAPToOffsetIndex(InterpState &S, CodePtr OpPC) {
2987 T Source = S.Stk.pop<T>();
2988 APSInt Val = Source.toAPSInt();
2989 if (Val.isNegative() || Val.getActiveBits() > 63)
2990 return Invalid(S, OpPC);
2991 S.Stk.push<Integral<64, true>>(
2992 Args: Integral<64, true>::from(V: (int64_t)Val.getZExtValue()));
2993 return true;
2994}
2995
2996template <PrimType Name, class T = typename PrimConv<Name>::T>
2997bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
2998 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2999 const T &From = S.Stk.pop<T>();
3000
3001 if constexpr (isIntegralOrPointer<T>()) {
3002 if (!From.isNumber())
3003 return false;
3004 }
3005
3006 APSInt FromAP = From.toAPSInt();
3007
3008 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
3009 Floating Result = S.allocFloat(Sem: *Sem);
3010 auto Status =
3011 Floating::fromIntegral(Val: FromAP, Sem: *Sem, RM: getRoundingMode(FPO), Result: &Result);
3012 S.Stk.push<Floating>(Args&: Result);
3013
3014 return CheckFloatResult(S, OpPC, Result, Status, FPO);
3015}
3016
3017template <PrimType Name, class T = typename PrimConv<Name>::T>
3018bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
3019 const Floating &F = S.Stk.pop<Floating>();
3020
3021 if constexpr (std::is_same_v<T, Boolean>) {
3022 S.Stk.push<T>(T(F.isNonZero()));
3023 return true;
3024 } else {
3025 APSInt Result(std::max(8u, T::bitWidth()),
3026 /*IsUnsigned=*/!T::isSigned());
3027 auto Status = F.convertToInteger(Result);
3028
3029 // Float-to-Integral overflow check.
3030 if ((Status & APFloat::opStatus::opInvalidOp)) {
3031 const Expr *E = S.Current->getExpr(PC: OpPC);
3032 QualType Type = E->getType();
3033
3034 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << F.getAPFloat() << Type;
3035 if (S.noteUndefinedBehavior()) {
3036 S.Stk.push<T>(T(Result));
3037 return true;
3038 }
3039 return false;
3040 }
3041
3042 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
3043 S.Stk.push<T>(T(Result));
3044 return CheckFloatResult(S, OpPC, Result: F, Status, FPO);
3045 }
3046}
3047
3048inline bool AddrOf(InterpState &S, CodePtr OpPC) {
3049 const Pointer Ptr = S.Stk.pop<Pointer>();
3050
3051 if (Ptr.isOpaquePointer()) {
3052 const OpaquePointer &OP = Ptr.asOpaquePointer();
3053 QualType T = QualType(OP.FieldType.getPointer(), 0);
3054
3055 T = S.getASTContext().getPointerType(T);
3056 S.Stk.push<Pointer>(Args: OP.withFieldType(FieldTy: T.getTypePtr(), PastEnd: OP.isOnePastEnd()));
3057 } else {
3058 S.Stk.push<Pointer>(Args: Ptr);
3059 }
3060
3061 return true;
3062}
3063
3064bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
3065 const Pointer &Ptr, unsigned BitWidth);
3066bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth);
3067bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
3068bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
3069
3070template <PrimType Name, class T = typename PrimConv<Name>::T>
3071bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
3072 const Pointer &Ptr = S.Stk.pop<Pointer>();
3073 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
3074 return Invalid(S, OpPC);
3075
3076 if constexpr (std::is_same_v<T, Boolean>) {
3077 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
3078 } else if constexpr (isIntegralOrPointer<T>()) {
3079 if (Ptr.isBlockPointer()) {
3080 S.Stk.push<T>(IntegralKind::BlockAddress, Ptr.block(), /*Offset=*/0);
3081 } else if (Ptr.isOpaquePointer()) {
3082 if (const Expr *BaseExpr = Ptr.asOpaquePointer().getBaseExpr()) {
3083 IntegralKind Kind = IntegralKind::ExprAddress;
3084 if (isa<AddrLabelExpr>(Val: BaseExpr))
3085 Kind = IntegralKind::LabelAddress;
3086 S.Stk.push<T>(Kind, BaseExpr, 0);
3087 } else {
3088 S.Stk.push<T>(IntegralKind::Address,
3089 Ptr.asOpaquePointer().Base.asVarDecl(), 0);
3090 }
3091
3092 } else if (Ptr.isFunctionPointer()) {
3093 const void *FuncDecl = Ptr.asFunctionPointer().Func->getDecl();
3094 S.Stk.push<T>(IntegralKind::FunctionAddress, FuncDecl, /*Offset=*/0);
3095 } else if (Ptr.isStringPointer()) {
3096 S.Stk.push<T>(IntegralKind::ExprAddress,
3097 (const void *)Ptr.asStringPointer().getLiteral(), 0);
3098 } else {
3099 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
3100 }
3101 } else {
3102 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
3103 }
3104 return true;
3105}
3106
3107template <PrimType Name, class T = typename PrimConv<Name>::T>
3108static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
3109 uint32_t FPS) {
3110 const T &Int = S.Stk.pop<T>();
3111
3112 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
3113
3114 bool Overflow;
3115 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
3116
3117 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
3118 return false;
3119
3120 S.Stk.push<FixedPoint>(Args&: Result);
3121 return true;
3122}
3123
3124static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
3125 uint32_t FPS) {
3126 const auto &Float = S.Stk.pop<Floating>();
3127
3128 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
3129
3130 bool Overflow;
3131 FixedPoint Result = FixedPoint::from(I: Float.getAPFloat(), Sem, Overflow: &Overflow);
3132
3133 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
3134 return false;
3135
3136 S.Stk.push<FixedPoint>(Args&: Result);
3137 return true;
3138}
3139
3140static inline bool CastFixedPointFloating(InterpState &S,
3141 const llvm::fltSemantics *Sem) {
3142 const auto &Fixed = S.Stk.pop<FixedPoint>();
3143 Floating Result = S.allocFloat(Sem: *Sem);
3144 Result.copy(F: Fixed.toFloat(Sem));
3145 S.Stk.push<Floating>(Args&: Result);
3146 return true;
3147}
3148
3149template <PrimType Name, class T = typename PrimConv<Name>::T>
3150static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
3151 const auto &Fixed = S.Stk.pop<FixedPoint>();
3152
3153 bool Overflow;
3154 APSInt Int = Fixed.toInt(BitWidth: T::bitWidth(), Signed: T::isSigned(), Overflow: &Overflow);
3155
3156 if (Overflow && !handleOverflow(S, OpPC, SrcValue: Int))
3157 return false;
3158
3159 S.Stk.push<T>(Int);
3160 return true;
3161}
3162
3163static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) {
3164 const SourceInfo &E = S.Current->getSource(PC: OpPC);
3165 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
3166 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3167 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
3168 return true;
3169}
3170
3171bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr,
3172 const Type *TargetType);
3173
3174//===----------------------------------------------------------------------===//
3175// Zero, Nullptr
3176//===----------------------------------------------------------------------===//
3177
3178template <PrimType Name, class T = typename PrimConv<Name>::T>
3179bool Zero(InterpState &S) {
3180 S.Stk.push<T>(T::zero());
3181 return true;
3182}
3183
3184static inline bool ZeroIntAP(InterpState &S, uint32_t BitWidth) {
3185 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
3186 if (!Result.singleWord())
3187 std::memset(s: Result.Memory, c: 0, n: Result.numWords() * sizeof(uint64_t));
3188 S.Stk.push<IntegralAP<false>>(Args&: Result);
3189 return true;
3190}
3191
3192static inline bool ZeroIntAPS(InterpState &S, uint32_t BitWidth) {
3193 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
3194 if (!Result.singleWord())
3195 std::memset(s: Result.Memory, c: 0, n: Result.numWords() * sizeof(uint64_t));
3196 S.Stk.push<IntegralAP<true>>(Args&: Result);
3197 return true;
3198}
3199
3200template <PrimType Name, class T = typename PrimConv<Name>::T>
3201inline bool Null(InterpState &S, uint64_t Value, const Type *Ty) {
3202 // FIXME(perf): This is a somewhat often-used function and the value of a
3203 // null pointer is almost always 0.
3204 S.Stk.push<T>(Value, Ty);
3205 return true;
3206}
3207
3208template <PrimType Name, class T = typename PrimConv<Name>::T>
3209inline bool IsNonNull(InterpState &S) {
3210 const auto &P = S.Stk.pop<T>();
3211 if (P.isWeak())
3212 return false;
3213 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
3214 return true;
3215}
3216
3217//===----------------------------------------------------------------------===//
3218// This, ImplicitThis
3219//===----------------------------------------------------------------------===//
3220
3221inline bool This(InterpState &S, CodePtr OpPC) {
3222 // Cannot read 'this' in this mode.
3223 if (S.checkingPotentialConstantExpression())
3224 return false;
3225 if (!CheckThis(S, OpPC))
3226 return false;
3227 const Pointer &This = S.Current->getThis();
3228
3229 // Ensure the This pointer has been cast to the correct base.
3230 if (!This.isDummy()) {
3231 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
3232 if (!This.isTypeidPointer()) {
3233 [[maybe_unused]] const Record *R = This.getRecord();
3234 if (!R)
3235 R = This.narrow().getRecord();
3236 if (!R)
3237 return false;
3238 assert(R->getDecl() ==
3239 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())
3240 ->getParent());
3241 }
3242 }
3243
3244 S.Stk.push<Pointer>(Args: This);
3245 return true;
3246}
3247
3248inline bool RVOPtr(InterpState &S) {
3249 assert(S.Current->getFunction()->hasRVO());
3250 if (S.checkingPotentialConstantExpression())
3251 return false;
3252 S.Stk.push<Pointer>(Args: S.Current->getRVOPtr());
3253 return true;
3254}
3255
3256//===----------------------------------------------------------------------===//
3257// Shr, Shl
3258//===----------------------------------------------------------------------===//
3259
3260template <class LT, class RT, ShiftDir Dir>
3261inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
3262 LT *Result) {
3263 static_assert(!needsAlloc<LT>());
3264 const unsigned Bits = LHS.bitWidth();
3265
3266 // OpenCL 6.3j: shift values are effectively % word size of LHS.
3267 if (S.getLangOpts().OpenCL)
3268 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
3269 RHS.bitWidth(), &RHS);
3270
3271 if (RHS.isNegative()) {
3272 // During constant-folding, a negative shift is an opposite shift. Such a
3273 // shift is not a constant expression.
3274 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
3275 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS.toAPSInt();
3276 if (!S.noteUndefinedBehavior())
3277 return false;
3278
3279 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(numBits: RHS.bitWidth(), Unsigned: false)) : -RHS;
3280
3281 return DoShift<LT, RT,
3282 Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
3283 S, OpPC, LHS, RHS, Result);
3284 }
3285
3286 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
3287 return false;
3288
3289 // Limit the shift amount to Bits - 1. If this happened,
3290 // it has already been diagnosed by CheckShift() above,
3291 // but we still need to handle it.
3292 // Note that we have to be extra careful here since we're doing the shift in
3293 // any case, but we need to adjust the shift amount or the way we do the shift
3294 // for the potential error cases.
3295 typename LT::AsUnsigned R;
3296 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
3297 if constexpr (Dir == ShiftDir::Left) {
3298 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3299 ComparisonCategoryResult::Greater) {
3300 if (LHS.isNegative())
3301 R = LT::AsUnsigned::zero(LHS.bitWidth());
3302 else {
3303 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
3304 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3305 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
3306 }
3307 } else if (LHS.isNegative()) {
3308 if (LHS.isMin()) {
3309 R = LT::AsUnsigned::zero(LHS.bitWidth());
3310 } else {
3311 // If the LHS is negative, perform the cast and invert the result.
3312 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
3313 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
3314 &R);
3315 R = -R;
3316 }
3317 } else {
3318 // The good case, a simple left shift.
3319 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3320 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
3321 }
3322 S.Stk.push<LT>(LT::from(R));
3323 return true;
3324 }
3325
3326 // Right shift.
3327 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3328 ComparisonCategoryResult::Greater) {
3329 R = LT::AsUnsigned::from(0);
3330 } else {
3331 // Do the shift on potentially signed LT, then convert to unsigned type.
3332 LT A;
3333 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
3334 R = LT::AsUnsigned::from(A);
3335 }
3336
3337 S.Stk.push<LT>(LT::from(R));
3338 return true;
3339}
3340
3341/// A version of DoShift that works on IntegralAP.
3342template <class LT, class RT, ShiftDir Dir>
3343inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,
3344 APSInt RHS, LT *Result) {
3345 const unsigned Bits = LHS.getBitWidth();
3346
3347 // OpenCL 6.3j: shift values are effectively % word size of LHS.
3348 if (S.getLangOpts().OpenCL)
3349 RHS &=
3350 APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),
3351 RHS.isUnsigned());
3352
3353 if (RHS.isNegative()) {
3354 // During constant-folding, a negative shift is an opposite shift. Such a
3355 // shift is not a constant expression.
3356 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
3357 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();
3358 if (!S.noteUndefinedBehavior())
3359 return false;
3360 return DoShiftAP<LT, RT,
3361 Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
3362 S, OpPC, LHS, -(RHS.extend(width: RHS.getBitWidth() + 1)), Result);
3363 }
3364
3365 if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),
3366 Bits))
3367 return false;
3368
3369 unsigned SA = (unsigned)RHS.getLimitedValue(Limit: Bits - 1);
3370 if constexpr (Dir == ShiftDir::Left) {
3371 if constexpr (needsAlloc<LT>())
3372 Result->copy(LHS << SA);
3373 else
3374 *Result = LT(LHS << SA);
3375 } else {
3376 if constexpr (needsAlloc<LT>())
3377 Result->copy(LHS >> SA);
3378 else
3379 *Result = LT(LHS >> SA);
3380 }
3381
3382 S.Stk.push<LT>(*Result);
3383 return true;
3384}
3385
3386template <PrimType NameL, PrimType NameR>
3387inline bool Shr(InterpState &S, CodePtr OpPC) {
3388 using LT = typename PrimConv<NameL>::T;
3389 using RT = typename PrimConv<NameR>::T;
3390 auto RHS = S.Stk.pop<RT>();
3391 auto LHS = S.Stk.pop<LT>();
3392
3393 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3394 LT Result;
3395 if constexpr (needsAlloc<LT>())
3396 Result = S.allocAP<LT>(LHS.bitWidth());
3397 return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
3398 RHS.toAPSInt(), &Result);
3399 } else {
3400 LT Result;
3401 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
3402 }
3403}
3404
3405template <PrimType NameL, PrimType NameR>
3406inline bool Shl(InterpState &S, CodePtr OpPC) {
3407 using LT = typename PrimConv<NameL>::T;
3408 using RT = typename PrimConv<NameR>::T;
3409 auto RHS = S.Stk.pop<RT>();
3410 auto LHS = S.Stk.pop<LT>();
3411
3412 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3413 LT Result;
3414 if constexpr (needsAlloc<LT>())
3415 Result = S.allocAP<LT>(LHS.bitWidth());
3416 return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
3417 RHS.toAPSInt(), &Result);
3418 } else {
3419 LT Result;
3420 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
3421 }
3422}
3423
3424static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
3425 const auto &RHS = S.Stk.pop<FixedPoint>();
3426 const auto &LHS = S.Stk.pop<FixedPoint>();
3427 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
3428
3429 unsigned ShiftBitWidth =
3430 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
3431
3432 // Embedded-C 4.1.6.2.2:
3433 // The right operand must be nonnegative and less than the total number
3434 // of (nonpadding) bits of the fixed-point operand ...
3435 if (RHS.isNegative()) {
3436 S.CCEDiag(Loc: S.Current->getLocation(PC: OpPC), DiagId: diag::note_constexpr_negative_shift)
3437 << RHS.toAPSInt();
3438 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3439 Limit: ShiftBitWidth)) != RHS.toAPSInt()) {
3440 const Expr *E = S.Current->getExpr(PC: OpPC);
3441 S.CCEDiag(E, DiagId: diag::note_constexpr_large_shift)
3442 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
3443 }
3444
3445 FixedPoint Result;
3446 if (Left) {
3447 if (FixedPoint::shiftLeft(A: LHS, B: RHS, OpBits: ShiftBitWidth, R: &Result) &&
3448 !handleFixedPointOverflow(S, OpPC, FP: Result))
3449 return false;
3450 } else {
3451 if (FixedPoint::shiftRight(A: LHS, B: RHS, OpBits: ShiftBitWidth, R: &Result) &&
3452 !handleFixedPointOverflow(S, OpPC, FP: Result))
3453 return false;
3454 }
3455
3456 S.Stk.push<FixedPoint>(Args&: Result);
3457 return true;
3458}
3459
3460//===----------------------------------------------------------------------===//
3461// NoRet
3462//===----------------------------------------------------------------------===//
3463PRESERVE_NONE inline bool NoRet(InterpState &S) {
3464 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
3465 S.FFDiag(Loc: EndLoc, DiagId: diag::note_constexpr_no_return);
3466 return false;
3467}
3468
3469//===----------------------------------------------------------------------===//
3470// NarrowPtr, ExpandPtr
3471//===----------------------------------------------------------------------===//
3472
3473inline bool NarrowPtr(InterpState &S) {
3474 const Pointer &Ptr = S.Stk.pop<Pointer>();
3475 S.Stk.push<Pointer>(Args: Ptr.narrow());
3476 return true;
3477}
3478
3479inline bool ExpandPtr(InterpState &S) {
3480 const Pointer &Ptr = S.Stk.pop<Pointer>();
3481 if (Ptr.isBlockPointer())
3482 S.Stk.push<Pointer>(Args: Ptr.expand());
3483 else
3484 S.Stk.push<Pointer>(Args: Ptr);
3485 return true;
3486}
3487
3488// Implementation for ArrayElemPtr and ArrayElemPtrPop ops.
3489template <typename T>
3490inline bool arrayElemPtr(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
3491 const T &Offset) {
3492 if (Ptr.isOpaquePointer()) {
3493 if (S.inConstantContext() && !Offset.isZero() &&
3494 !CheckArray(S, OpPC, Ptr)) {
3495 return false;
3496 }
3497 return arrayElemPtrOpaque(S, OpPC, Ptr, Offset.toAPSInt());
3498 }
3499
3500 if (Offset.isZero()) {
3501 if (const Descriptor *Desc = Ptr.getFieldDesc();
3502 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3503 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0).narrow());
3504 return true;
3505 }
3506 S.Stk.push<Pointer>(Args: Ptr.narrow());
3507 return true;
3508 }
3509
3510 assert(!Offset.isZero());
3511
3512 if (std::optional<Pointer> Result =
3513 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3514 S.Stk.push<Pointer>(Args: Result->narrow());
3515 return true;
3516 }
3517 return false;
3518}
3519
3520// 1) Pops an integral value from the stack
3521// 2) Peeks a pointer
3522// 3) Pushes a new pointer that's a narrowed array
3523// element of the peeked pointer with the value
3524// from 1) added as offset.
3525//
3526// This leaves the original pointer on the stack and pushes a new one
3527// with the offset applied and narrowed.
3528template <PrimType Name, class T = typename PrimConv<Name>::T>
3529inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
3530 const T &Offset = S.Stk.pop<T>();
3531 const Pointer &Ptr = S.Stk.peek<Pointer>();
3532
3533 return arrayElemPtr<T>(S, OpPC, Ptr, Offset);
3534}
3535
3536template <PrimType Name, class T = typename PrimConv<Name>::T>
3537inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
3538 const T &Offset = S.Stk.pop<T>();
3539 const Pointer &Ptr = S.Stk.pop<Pointer>();
3540
3541 return arrayElemPtr<T>(S, OpPC, Ptr, Offset);
3542}
3543
3544template <PrimType Name, class T = typename PrimConv<Name>::T>
3545inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
3546 const Pointer &Ptr = S.Stk.peek<Pointer>();
3547
3548 if (!CheckLoad(S, OpPC, Ptr))
3549 return false;
3550
3551 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3552 S.Stk.push<T>(Ptr.elem<T>(Index));
3553 return true;
3554}
3555
3556template <PrimType Name, class T = typename PrimConv<Name>::T>
3557inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
3558 const Pointer &Ptr = S.Stk.pop<Pointer>();
3559
3560 if (!CheckLoad(S, OpPC, Ptr))
3561 return false;
3562
3563 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3564 S.Stk.push<T>(Ptr.elem<T>(Index));
3565 return true;
3566}
3567
3568template <PrimType Name, class T = typename PrimConv<Name>::T>
3569inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
3570 uint32_t DestIndex, uint32_t Size) {
3571 const auto &SrcPtr = S.Stk.pop<Pointer>();
3572 const auto &DestPtr = S.Stk.peek<Pointer>();
3573
3574 if (SrcPtr.isDummy() || DestPtr.isDummy())
3575 return false;
3576
3577 if (!SrcPtr.isBlockPointer() || !DestPtr.isBlockPointer())
3578 return false;
3579
3580 const Descriptor *SrcDesc = SrcPtr.getFieldDesc();
3581 const Descriptor *DestDesc = DestPtr.getFieldDesc();
3582 if (!SrcDesc->isPrimitiveArray() || !DestDesc->isPrimitiveArray() ||
3583 SrcDesc->getPrimType() != Name || DestDesc->getPrimType() != Name)
3584 return false;
3585
3586 for (uint32_t I = 0; I != Size; ++I) {
3587 const Pointer &SP = SrcPtr.atIndex(Idx: SrcIndex + I);
3588
3589 if (!CheckLoad(S, OpPC, Ptr: SP))
3590 return false;
3591
3592 DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);
3593 DestPtr.initializeElement(Index: DestIndex + I);
3594 }
3595 return true;
3596}
3597
3598/// Just takes a pointer and checks if it's an incomplete
3599/// array type.
3600inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
3601 const Pointer &Ptr = S.Stk.pop<Pointer>();
3602
3603 if (Ptr.isZero()) {
3604 S.Stk.push<Pointer>(Args: Ptr);
3605 return true;
3606 }
3607
3608 if (!Ptr.isZeroSizeArray()) {
3609 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_ArrayToPointer))
3610 return false;
3611 }
3612
3613 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || !S.inConstantContext()) {
3614 if (Ptr.isBlockPointer()) {
3615 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0).narrow());
3616 return true;
3617 }
3618
3619 if (Ptr.isStringPointer()) {
3620 S.Stk.push<Pointer>(Args: Ptr.asStringPointer().decay());
3621 return true;
3622 }
3623
3624 if (!Ptr.isOpaquePointer()) {
3625 S.Stk.push<Pointer>(Args: Ptr);
3626 return true;
3627 }
3628
3629 if (!Ptr.getType()->isArrayType()) {
3630 S.Stk.push<Pointer>(Args: Ptr);
3631 return true;
3632 }
3633 return arrayElemPtrOpaque(S, OpPC, Ptr,
3634 Index: APSInt(APInt::getZero(numBits: 1), /*IsUnsigned=*/true),
3635 /*AllowReplace=*/AllowReplace: false);
3636 }
3637
3638 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3639 DiagId: diag::note_constexpr_unsupported_unsized_array);
3640 return false;
3641}
3642
3643inline bool GetFnPtr(InterpState &S, const Function *Func) {
3644 assert(Func);
3645 S.Stk.push<Pointer>(Args&: Func);
3646 return true;
3647}
3648
3649template <PrimType Name, class T = typename PrimConv<Name>::T>
3650inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty) {
3651 const T &IntVal = S.Stk.pop<T>();
3652
3653 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_invalid_cast)
3654 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3655 << S.getLangOpts().CPlusPlus;
3656
3657 if constexpr (isIntegralOrPointer<T>()) {
3658 if (IntVal.getKind() == IntegralKind::Address) {
3659 if (IntVal.getOffset() != 0)
3660 return Invalid(S, OpPC);
3661 const VarDecl *VD = (const VarDecl *)IntVal.getPtr();
3662 unsigned GlobalIndex = *S.P.getOrCreateGlobal(VD);
3663 S.Stk.push<Pointer>(Args: S.P.getGlobal(Idx: GlobalIndex));
3664 } else if (IntVal.getKind() == IntegralKind::BlockAddress) {
3665 if (IntVal.getOffset() != 0)
3666 return Invalid(S, OpPC);
3667
3668 const Block *B = (const Block *)IntVal.getPtr();
3669 S.Stk.push<Pointer>(Args: const_cast<Block *>(B));
3670 } else if (IntVal.getKind() == IntegralKind::FunctionAddress) {
3671 const Function *F =
3672 S.P.getFunction(F: (const FunctionDecl *)IntVal.getPtr());
3673 S.Stk.push<Pointer>(F, IntVal.getOffset());
3674 } else {
3675 S.Stk.push<Pointer>(Args: static_cast<uint64_t>(IntVal), Args&: Ty);
3676 }
3677 } else {
3678 S.Stk.push<Pointer>(Args: static_cast<uint64_t>(IntVal), Args&: Ty);
3679 }
3680
3681 return true;
3682}
3683
3684inline bool GetStringPtr(InterpState &S, const Expr *Base) {
3685 S.Stk.push<Pointer>(Args&: Base, Args: S.newStringID());
3686 return true;
3687}
3688
3689bool GetMemberPtr(InterpState &S, const ValueDecl *D);
3690bool GetMemberPtrBase(InterpState &S);
3691bool GetMemberPtrDecl(InterpState &S);
3692bool CopyMemberPtrPath(InterpState &S, const RecordDecl *Entry, bool IsDerived);
3693
3694/// Just emit a diagnostic. The expression that caused emission of this
3695/// op is not valid in a constant context.
3696
3697inline bool Unsupported(InterpState &S, CodePtr OpPC) {
3698 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3699 S.FFDiag(Loc, DiagId: diag::note_constexpr_stmt_expr_unsupported)
3700 << S.Current->getRange(PC: OpPC);
3701 return false;
3702}
3703
3704inline bool PushIgnoreDiags(InterpState &S) {
3705 ++S.DiagIgnoreDepth;
3706 if (S.DiagIgnoreDepth != 1)
3707 return true;
3708 assert(S.PrevDiags == nullptr);
3709 S.PrevDiags = S.getEvalStatus().Diag;
3710 S.PrevDiagsEmitted = S.getEvalStatus().DiagEmitted;
3711 S.getEvalStatus().Diag = nullptr;
3712 assert(!S.diagnosing());
3713 return true;
3714}
3715
3716inline bool PopIgnoreDiags(InterpState &S) {
3717 assert(S.DiagIgnoreDepth != 0);
3718 --S.DiagIgnoreDepth;
3719 if (S.DiagIgnoreDepth == 0) {
3720 S.getEvalStatus().Diag = S.PrevDiags;
3721 S.getEvalStatus().DiagEmitted = S.PrevDiagsEmitted;
3722 S.PrevDiags = nullptr;
3723 }
3724 return true;
3725}
3726
3727inline bool StartSpeculation(InterpState &S) {
3728#ifndef NDEBUG
3729 ++S.SpeculationDepth;
3730#endif
3731 return true;
3732}
3733
3734inline bool StartInit(InterpState &S) {
3735 const Pointer &Ptr = S.Stk.peek<Pointer>();
3736 S.InitializingPtrs.push_back(Elt: Ptr.view());
3737 return true;
3738}
3739
3740inline bool EndInit(InterpState &S) {
3741 S.InitializingPtrs.pop_back();
3742 return true;
3743}
3744
3745// This is special-cased in the tablegen opcode emitter.
3746// Its dispatch function will NOT call InterpNext
3747// and instead simply return true.
3748PRESERVE_NONE inline bool EndSpeculation(InterpState &S) {
3749#ifndef NDEBUG
3750 assert(S.SpeculationDepth != 0);
3751 --S.SpeculationDepth;
3752#endif
3753 return true;
3754}
3755
3756inline bool PushCC(InterpState &S, bool Value) {
3757 S.ConstantContextOverride = Value;
3758 return true;
3759}
3760inline bool PopCC(InterpState &S) {
3761 S.ConstantContextOverride = std::nullopt;
3762 return true;
3763}
3764
3765inline bool PushMSVCCE(InterpState &S) {
3766 // This is a per-frame property.
3767 ++S.Current->MSVCConstexprAllowed;
3768 return true;
3769}
3770
3771inline bool PopMSVCCE(InterpState &S) {
3772 assert(S.Current->MSVCConstexprAllowed >= 1);
3773 // This is a per-frame property.
3774 --S.Current->MSVCConstexprAllowed;
3775 return true;
3776}
3777
3778/// Do nothing and just abort execution.
3779inline bool Error(InterpState &S) { return false; }
3780
3781inline bool SideEffect(InterpState &S) { return S.noteSideEffect(); }
3782
3783/// Abort without a diagnostic if we're checking for a potential constant
3784/// expression and this is not the bottom frame. This is used in constructors to
3785/// allow evaluating their initializers but abort if we encounter anything in
3786/// their body.
3787inline bool CtorCheck(InterpState &S) {
3788 if (S.checkingPotentialConstantExpression() && !S.Current->isBottomFrame())
3789 return false;
3790 return true;
3791}
3792
3793inline bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T) {
3794 if (S.getLangOpts().CPlusPlus) {
3795 QualType VolatileType = QualType(T, 0).withVolatile();
3796 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3797 DiagId: diag::note_constexpr_access_volatile_type)
3798 << AK_Assign << VolatileType;
3799 } else {
3800 S.FFDiag(SI: S.Current->getSource(PC: OpPC));
3801 }
3802 return false;
3803}
3804
3805inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
3806 if (S.inConstantContext()) {
3807 const SourceRange &ArgRange = S.Current->getRange(PC: OpPC);
3808 const Expr *E = S.Current->getExpr(PC: OpPC);
3809 S.CCEDiag(E, DiagId: diag::note_constexpr_non_const_vectorelements) << ArgRange;
3810 }
3811 return false;
3812}
3813
3814inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {
3815 if (!S.getLangOpts().CPlusPlus20)
3816 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
3817 DiagId: diag::note_constexpr_pseudo_destructor);
3818 return true;
3819}
3820
3821inline bool Assume(InterpState &S, CodePtr OpPC) {
3822 const auto Val = S.Stk.pop<Boolean>();
3823
3824 if (Val)
3825 return true;
3826
3827 // Else, diagnose.
3828 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3829 S.CCEDiag(Loc, DiagId: diag::note_constexpr_assumption_failed);
3830 return false;
3831}
3832
3833template <PrimType Name, class T = typename PrimConv<Name>::T>
3834inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
3835 llvm::SmallVector<int64_t> ArrayIndices;
3836 for (size_t I = 0; I != E->getNumExpressions(); ++I)
3837 ArrayIndices.emplace_back(
3838 Args: static_cast<int64_t>(S.Stk.pop<Integral<64, true>>()));
3839
3840 int64_t Result;
3841 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
3842 return false;
3843
3844 S.Stk.push<T>(T::from(Result));
3845
3846 return true;
3847}
3848
3849template <PrimType Name, class T = typename PrimConv<Name>::T>
3850inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
3851 const T &Arg = S.Stk.peek<T>();
3852 if (!Arg.isZero())
3853 return true;
3854
3855 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3856 S.CCEDiag(Loc, DiagId: diag::note_non_null_attribute_failed);
3857
3858 return false;
3859}
3860
3861void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
3862 const APSInt &Value);
3863
3864template <PrimType Name, class T = typename PrimConv<Name>::T>
3865inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
3866 assert(ED);
3867 assert(!ED->isFixed());
3868
3869 if (S.inConstantContext()) {
3870 const APSInt Val = S.Stk.peek<T>().toAPSInt();
3871 diagnoseEnumValue(S, OpPC, ED, Value: Val);
3872 }
3873 return true;
3874}
3875
3876/// OldPtr -> Integer -> NewPtr.
3877template <PrimType TIn, PrimType TOut> inline bool DecayPtr(InterpState &S) {
3878 static_assert(isPtrType(T: TIn) && isPtrType(T: TOut));
3879 using FromT = typename PrimConv<TIn>::T;
3880 using ToT = typename PrimConv<TOut>::T;
3881
3882 const FromT &OldPtr = S.Stk.pop<FromT>();
3883
3884 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3885 std::is_same_v<ToT, Pointer>) {
3886 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
3887 return true;
3888 } else if constexpr (std::is_same_v<FromT, Pointer> &&
3889 std::is_same_v<ToT, FunctionPointer>) {
3890 if (OldPtr.isFunctionPointer()) {
3891 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
3892 OldPtr.getByteOffset());
3893 return true;
3894 }
3895 }
3896
3897 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
3898 return true;
3899}
3900
3901inline bool CheckDecl(InterpState &S, const VarDecl *VD) {
3902 // An expression E is a core constant expression unless the evaluation of E
3903 // would evaluate one of the following: [C++23] - a control flow that passes
3904 // through a declaration of a variable with static or thread storage duration
3905 // unless that variable is usable in constant expressions.
3906 assert(VD->isLocalVarDecl() &&
3907 VD->isStaticLocal()); // Checked before emitting this.
3908
3909 if (VD == S.EvaluatingDecl)
3910 return true;
3911
3912 if (!VD->isUsableInConstantExpressions(C: S.getASTContext())) {
3913 S.CCEDiag(Loc: VD->getLocation(), DiagId: diag::note_constexpr_static_local)
3914 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
3915 return false;
3916 }
3917 return true;
3918}
3919
3920/// Check if the destination array we're initializing can hold the \p NumElems
3921/// elements.
3922inline bool CheckArrayDestSize(InterpState &S, CodePtr OpPC, size_t NumElems) {
3923 if (!CheckArraySize(S, OpPC, NumElems))
3924 return false;
3925
3926 const Pointer &Ptr = S.Stk.peek<Pointer>();
3927 if (!Ptr.isUnknownSizeArray() && NumElems > Ptr.getNumElems()) {
3928 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_too_small)
3929 << Ptr.getNumElems() << NumElems;
3930 return false;
3931 }
3932
3933 return true;
3934}
3935
3936inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3937 assert(Desc);
3938
3939 if (!CheckDynamicMemoryAllocation(S, OpPC))
3940 return false;
3941
3942 DynamicAllocator &Allocator = S.getAllocator();
3943 Block *B =
3944 Allocator.allocate(D: Desc, EvalID: S.EvalID, AllocForm: DynamicAllocator::Form::NonArray);
3945 assert(B);
3946 S.Stk.push<Pointer>(Args&: B);
3947 return true;
3948}
3949
3950template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3951inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
3952 bool IsNoThrow) {
3953 if (!CheckDynamicMemoryAllocation(S, OpPC))
3954 return false;
3955
3956 SizeT NumElements = S.Stk.pop<SizeT>();
3957 if (!CheckArraySize(S, OpPC, &NumElements, primSize(Type: T), IsNoThrow)) {
3958 if (!IsNoThrow)
3959 return false;
3960
3961 // If this failed and is nothrow, just return a null ptr.
3962 S.Stk.push<Pointer>();
3963 return true;
3964 }
3965 if (NumElements.isNegative()) {
3966 if (!IsNoThrow) {
3967 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_negative)
3968 << NumElements.toDiagnosticString(S.getASTContext());
3969 return false;
3970 }
3971 S.Stk.push<Pointer>();
3972 return true;
3973 }
3974
3975 if (!CheckArraySize(S, OpPC, NumElems: static_cast<uint64_t>(NumElements)))
3976 return false;
3977
3978 DynamicAllocator &Allocator = S.getAllocator();
3979 Block *B = Allocator.allocate(Source, T, NumElements: static_cast<size_t>(NumElements),
3980 EvalID: S.EvalID, AllocForm: DynamicAllocator::Form::Array);
3981 assert(B);
3982 if (NumElements.isZero())
3983 S.Stk.push<Pointer>(Args&: B);
3984 else
3985 S.Stk.push<Pointer>(Args: Pointer(B).atIndex(Idx: 0));
3986 return true;
3987}
3988
3989template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3990inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
3991 bool IsNoThrow) {
3992 if (!CheckDynamicMemoryAllocation(S, OpPC))
3993 return false;
3994
3995 if (!ElementDesc)
3996 return false;
3997
3998 SizeT NumElements = S.Stk.pop<SizeT>();
3999 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
4000 IsNoThrow)) {
4001 if (!IsNoThrow)
4002 return false;
4003
4004 // If this failed and is nothrow, just return a null ptr.
4005 S.Stk.push<Pointer>(Args: 0, Args: ElementDesc->getType().getTypePtr());
4006 return true;
4007 }
4008 if (NumElements.isNegative()) {
4009 if (!IsNoThrow) {
4010 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_negative)
4011 << NumElements.toDiagnosticString(S.getASTContext());
4012 return false;
4013 }
4014 S.Stk.push<Pointer>();
4015 return true;
4016 }
4017
4018 if (!CheckArraySize(S, OpPC, NumElems: static_cast<uint64_t>(NumElements)))
4019 return false;
4020
4021 DynamicAllocator &Allocator = S.getAllocator();
4022 Block *B = Allocator.allocate(D: ElementDesc, NumElements: static_cast<size_t>(NumElements),
4023 EvalID: S.EvalID, AllocForm: DynamicAllocator::Form::Array);
4024 assert(B);
4025 if (NumElements.isZero())
4026 S.Stk.push<Pointer>(Args&: B);
4027 else
4028 S.Stk.push<Pointer>(Args: Pointer(B).atIndex(Idx: 0));
4029
4030 return true;
4031}
4032
4033bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
4034 bool IsGlobalDelete);
4035
4036static inline bool IsConstantContext(InterpState &S) {
4037 S.Stk.push<Boolean>(Args: Boolean::from(Value: S.inConstantContext()));
4038 return true;
4039}
4040
4041static inline bool CheckAllocations(InterpState &S) {
4042 return S.maybeDiagnoseDanglingAllocations();
4043}
4044
4045/// Check if the initializer and storage types of a placement-new expression
4046/// match.
4047bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
4048 std::optional<uint64_t> ArraySize = std::nullopt);
4049
4050template <PrimType Name, class T = typename PrimConv<Name>::T>
4051bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
4052 const auto &Size = S.Stk.pop<T>();
4053 return CheckNewTypeMismatch(S, OpPC, E, ArraySize: static_cast<uint64_t>(Size));
4054}
4055bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
4056
4057template <PrimType Name, class T = typename PrimConv<Name>::T>
4058inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
4059 uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,
4060 const Type *TargetType) {
4061 const Pointer &FromPtr = S.Stk.pop<Pointer>();
4062
4063 if (!CheckLoad(S, OpPC, Ptr: FromPtr))
4064 return false;
4065
4066 if constexpr (std::is_same_v<T, Pointer>) {
4067 if (!TargetType->isNullPtrType()) {
4068 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
4069 DiagId: diag::note_constexpr_bit_cast_invalid_type)
4070 << /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;
4071 return false;
4072 }
4073 // The only pointer type we can validly bitcast to is nullptr_t.
4074 S.Stk.push<Pointer>();
4075 return true;
4076 } else if constexpr (std::is_same_v<T, MemberPointer>) {
4077 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
4078 DiagId: diag::note_constexpr_bit_cast_invalid_type)
4079 << /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;
4080 return false;
4081 } else {
4082
4083 size_t BuffSize = ResultBitWidth / 8;
4084 llvm::SmallVector<std::byte> Buff(BuffSize);
4085 bool HasIndeterminateBits = false;
4086
4087 Bits FullBitWidth(ResultBitWidth);
4088 Bits BitWidth = FullBitWidth;
4089
4090 if constexpr (std::is_same_v<T, Floating>) {
4091 assert(Sem);
4092 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(Sem: *Sem));
4093 }
4094
4095 if (!DoBitCast(S, OpPC, Ptr: FromPtr, Buff: Buff.data(), BitWidth, FullBitWidth,
4096 HasIndeterminateBits))
4097 return false;
4098
4099 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
4100 return false;
4101
4102 if constexpr (std::is_same_v<T, Floating>) {
4103 assert(Sem);
4104 Floating Result = S.allocFloat(Sem: *Sem);
4105 Floating::bitcastFromMemory(Buff: Buff.data(), Sem: *Sem, Result: &Result);
4106 S.Stk.push<Floating>(Args&: Result);
4107 } else if constexpr (needsAlloc<T>()) {
4108 T Result = S.allocAP<T>(ResultBitWidth);
4109 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);
4110 S.Stk.push<T>(Result);
4111 } else if constexpr (std::is_same_v<T, Boolean>) {
4112 // Only allow to cast single-byte integers to bool if they are either 0
4113 // or 1.
4114 assert(FullBitWidth.getQuantity() == 8);
4115 auto Val = static_cast<unsigned int>(Buff[0]);
4116 if (Val > 1) {
4117 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
4118 DiagId: diag::note_constexpr_bit_cast_unrepresentable_value)
4119 << S.getASTContext().BoolTy << Val;
4120 return false;
4121 }
4122 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4123 } else {
4124 assert(!Sem);
4125 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4126 }
4127 return true;
4128 }
4129}
4130
4131inline bool BitCast(InterpState &S, CodePtr OpPC) {
4132 Pointer FromPtr = S.Stk.pop<Pointer>();
4133 Pointer &ToPtr = S.Stk.peek<Pointer>();
4134
4135 // FIXME: Could allow reading from string pointers?
4136 if (!FromPtr.isBlockPointer() || !ToPtr.isBlockPointer())
4137 return false;
4138
4139 const Descriptor *D = FromPtr.getFieldDesc();
4140 if (D->isPrimitiveArray() && FromPtr.isArrayRoot())
4141 FromPtr = FromPtr.atIndex(Idx: 0);
4142
4143 if (!CheckLoad(S, OpPC, Ptr: FromPtr))
4144 return false;
4145
4146 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
4147 return false;
4148
4149 return true;
4150}
4151
4152/// Typeid support.
4153bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType);
4154bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
4155bool DiagTypeid(InterpState &S, CodePtr OpPC);
4156
4157inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
4158 const auto &Ptr = S.Stk.peek<Pointer>();
4159 return checkDestructor(S, OpPC, Ptr);
4160}
4161
4162inline bool IsBaseClass(InterpState &S) {
4163 S.Stk.push<bool>(Args: S.Stk.peek<Pointer>().isBaseClass());
4164 return true;
4165}
4166
4167//===----------------------------------------------------------------------===//
4168// Read opcode arguments
4169//===----------------------------------------------------------------------===//
4170
4171template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
4172 if constexpr (std::is_pointer<T>::value)
4173 return reinterpret_cast<T>(OpPC.read<uintptr_t>());
4174 else
4175 return OpPC.read<T>();
4176}
4177
4178template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
4179 auto &Semantics =
4180 llvm::APFloatBase::EnumToSemantics(S: Floating::deserializeSemantics(Buff: *OpPC));
4181
4182 auto F = S.allocFloat(Sem: Semantics);
4183 Floating::deserialize(Buff: *OpPC, Result: &F);
4184 OpPC += align(Size: F.bytesToSerialize());
4185 return F;
4186}
4187
4188template <>
4189inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
4190 CodePtr &OpPC) {
4191 uint32_t BitWidth = IntegralAP<false>::deserializeSize(Buff: *OpPC);
4192 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
4193 assert(Result.bitWidth() == BitWidth);
4194
4195 IntegralAP<false>::deserialize(Buff: *OpPC, Result: &Result);
4196 OpPC += align(Size: Result.bytesToSerialize());
4197 return Result;
4198}
4199
4200template <>
4201inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
4202 CodePtr &OpPC) {
4203 uint32_t BitWidth = IntegralAP<true>::deserializeSize(Buff: *OpPC);
4204 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
4205 assert(Result.bitWidth() == BitWidth);
4206
4207 IntegralAP<true>::deserialize(Buff: *OpPC, Result: &Result);
4208 OpPC += align(Size: Result.bytesToSerialize());
4209 return Result;
4210}
4211
4212template <>
4213inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {
4214 FixedPoint FP = FixedPoint::deserialize(Buff: *OpPC);
4215 OpPC += align(Size: FP.bytesToSerialize());
4216 return FP;
4217}
4218
4219} // namespace interp
4220} // namespace clang
4221
4222#endif
4223