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