Thanks to visit codestin.com
Credit goes to clang.llvm.org

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