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