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