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