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