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