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