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