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