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