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