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