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