clang 20.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"
23#include "FunctionPointer.h"
25#include "InterpFrame.h"
26#include "InterpStack.h"
27#include "InterpState.h"
28#include "MemberPointer.h"
29#include "Opcode.h"
30#include "PrimType.h"
31#include "Program.h"
32#include "State.h"
34#include "clang/AST/Expr.h"
35#include "llvm/ADT/APFloat.h"
36#include "llvm/ADT/APSInt.h"
37#include <type_traits>
38
39namespace clang {
40namespace interp {
41
42using APSInt = llvm::APSInt;
43using FixedPointSemantics = llvm::FixedPointSemantics;
44
45/// Checks if the variable has externally defined storage.
46bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
47
48/// Checks if the array is offsetable.
49bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50
51/// Checks if a pointer is live and accessible.
52bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
53 AccessKinds AK);
54
55/// Checks if a pointer is a dummy pointer.
56bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57 AccessKinds AK);
58
59/// Checks if a pointer is null.
60bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
62
63/// Checks if a pointer is in range.
64bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
65 AccessKinds AK);
66
67/// Checks if a field from which a pointer is going to be derived is valid.
68bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
70
71/// Checks if Ptr is a one-past-the-end pointer.
72bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
74
75/// Checks if the dowcast using the given offset is possible with the given
76/// pointer.
77bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
78 uint32_t Offset);
79
80/// Checks if a pointer points to const storage.
81bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82
83/// Checks if the Descriptor is of a constexpr or const global variable.
84bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
85
86/// Checks if a pointer points to a mutable field.
87bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88
89/// Checks if a value can be loaded from a block.
90bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
91 AccessKinds AK = AK_Read);
92bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93
94bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
95 AccessKinds AK);
96/// Check if a global variable is initialized.
97bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
98
99/// Checks if a value can be stored in a block.
100bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
101
102/// Checks if a method can be invoked on an object.
103bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
104
105/// Checks if a value can be initialized.
106bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
107
108/// Checks if a method can be called.
109bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
110
111/// Checks if calling the currently active function would exceed
112/// the allowed call depth.
113bool CheckCallDepth(InterpState &S, CodePtr OpPC);
114
115/// Checks the 'this' pointer.
116bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
117
118/// Checks if a method is pure virtual.
119bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
120
121/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
122bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
123 const CallExpr *CE, unsigned ArgSize);
124
125/// Checks if dynamic memory allocation is available in the current
126/// language mode.
128
129/// Diagnose mismatched new[]/delete or new/delete[] pairs.
131 DynamicAllocator::Form AllocForm,
132 DynamicAllocator::Form DeleteForm, const Descriptor *D,
133 const Expr *NewExpr);
134
135/// Check the source of the pointer passed to delete/delete[] has actually
136/// been heap allocated by us.
137bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
138 const Pointer &Ptr);
139
140/// Sets the given integral value to the pointer, which is of
141/// a std::{weak,partial,strong}_ordering type.
143 const Pointer &Ptr, const APSInt &IntValue);
144
145/// Copy the contents of Src into Dest.
146bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
147
148bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
149 uint32_t VarArgSize);
150bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
151 uint32_t VarArgSize);
152bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
153 uint32_t VarArgSize);
154bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func,
155 const CallExpr *CE, uint32_t BuiltinID);
156bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
157 const CallExpr *CE);
158bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
159bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
160bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
161 bool TargetIsUCharOrByte);
162
163template <typename T>
164static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
165 const Expr *E = S.Current->getExpr(OpPC);
166 S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
167 return S.noteUndefinedBehavior();
168}
169bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
170 const FixedPoint &FP);
171
172enum class ShiftDir { Left, Right };
173
174/// Checks if the shift operation is legal.
175template <ShiftDir Dir, typename LT, typename RT>
176bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
177 unsigned Bits) {
178 if (RHS.isNegative()) {
179 const SourceInfo &Loc = S.Current->getSource(OpPC);
180 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
181 if (!S.noteUndefinedBehavior())
182 return false;
183 }
184
185 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
186 // the shifted type.
187 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
188 const Expr *E = S.Current->getExpr(OpPC);
189 const APSInt Val = RHS.toAPSInt();
190 QualType Ty = E->getType();
191 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
192 if (!S.noteUndefinedBehavior())
193 return false;
194 }
195
196 if constexpr (Dir == ShiftDir::Left) {
197 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
198 const Expr *E = S.Current->getExpr(OpPC);
199 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
200 // operand, and must not overflow the corresponding unsigned type.
201 if (LHS.isNegative()) {
202 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
203 if (!S.noteUndefinedBehavior())
204 return false;
205 } else if (LHS.toUnsigned().countLeadingZeros() <
206 static_cast<unsigned>(RHS)) {
207 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
208 if (!S.noteUndefinedBehavior())
209 return false;
210 }
211 }
212 }
213
214 // C++2a [expr.shift]p2: [P0907R4]:
215 // E1 << E2 is the unique value congruent to
216 // E1 x 2^E2 module 2^N.
217 return true;
218}
219
220/// Checks if Div/Rem operation on LHS and RHS is valid.
221template <typename T>
222bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
223 if (RHS.isZero()) {
224 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
225 if constexpr (std::is_same_v<T, Floating>) {
226 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
227 << Op->getRHS()->getSourceRange();
228 return true;
229 }
230
231 S.FFDiag(Op, diag::note_expr_divide_by_zero)
232 << Op->getRHS()->getSourceRange();
233 return false;
234 }
235
236 if constexpr (!std::is_same_v<T, FixedPoint>) {
237 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
238 APSInt LHSInt = LHS.toAPSInt();
239 SmallString<32> Trunc;
240 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
241 const SourceInfo &Loc = S.Current->getSource(OpPC);
242 const Expr *E = S.Current->getExpr(OpPC);
243 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
244 return false;
245 }
246 }
247 return true;
248}
249
250template <typename SizeT>
251bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
252 unsigned ElemSize, bool IsNoThrow) {
253 // FIXME: Both the SizeT::from() as well as the
254 // NumElements.toAPSInt() in this function are rather expensive.
255
256 // Can't be too many elements if the bitwidth of NumElements is lower than
257 // that of Descriptor::MaxArrayElemBytes.
258 if ((NumElements->bitWidth() - NumElements->isSigned()) <
259 (sizeof(Descriptor::MaxArrayElemBytes) * 8))
260 return true;
261
262 // FIXME: GH63562
263 // APValue stores array extents as unsigned,
264 // so anything that is greater that unsigned would overflow when
265 // constructing the array, we catch this here.
266 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
267 assert(MaxElements.isPositive());
268 if (NumElements->toAPSInt().getActiveBits() >
270 *NumElements > MaxElements) {
271 if (!IsNoThrow) {
272 const SourceInfo &Loc = S.Current->getSource(OpPC);
273
274 if (NumElements->isSigned() && NumElements->isNegative()) {
275 S.FFDiag(Loc, diag::note_constexpr_new_negative)
276 << NumElements->toDiagnosticString(S.getASTContext());
277 } else {
278 S.FFDiag(Loc, diag::note_constexpr_new_too_large)
279 << NumElements->toDiagnosticString(S.getASTContext());
280 }
281 }
282 return false;
283 }
284 return true;
285}
286
287/// Checks if the result of a floating-point operation is valid
288/// in the current context.
289bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
290 APFloat::opStatus Status, FPOptions FPO);
291
292/// Checks why the given DeclRefExpr is invalid.
293bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
294
295/// Interpreter entry point.
296bool Interpret(InterpState &S);
297
298/// Interpret a builtin function.
299bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
300 const CallExpr *Call, uint32_t BuiltinID);
301
302/// Interpret an offsetof operation.
303bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
304 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
305
306inline bool Invalid(InterpState &S, CodePtr OpPC);
307
308enum class ArithOp { Add, Sub };
309
310//===----------------------------------------------------------------------===//
311// Returning values
312//===----------------------------------------------------------------------===//
313
314void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
315 const Function *Func);
316
317template <PrimType Name, class T = typename PrimConv<Name>::T>
318bool Ret(InterpState &S, CodePtr &PC) {
319 const T &Ret = S.Stk.pop<T>();
320
321 assert(S.Current);
322 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
323 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
324 cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
325
326 if (InterpFrame *Caller = S.Current->Caller) {
327 PC = S.Current->getRetPC();
328 delete S.Current;
329 S.Current = Caller;
330 S.Stk.push<T>(Ret);
331 } else {
332 delete S.Current;
333 S.Current = nullptr;
334 // The topmost frame should come from an EvalEmitter,
335 // which has its own implementation of the Ret<> instruction.
336 }
337 return true;
338}
339
340inline bool RetVoid(InterpState &S, CodePtr &PC) {
341 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
342
343 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
344 cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
345
346 if (InterpFrame *Caller = S.Current->Caller) {
347 PC = S.Current->getRetPC();
348 delete S.Current;
349 S.Current = Caller;
350 } else {
351 delete S.Current;
352 S.Current = nullptr;
353 }
354 return true;
355}
356
357//===----------------------------------------------------------------------===//
358// Add, Sub, Mul
359//===----------------------------------------------------------------------===//
360
361template <typename T, bool (*OpFW)(T, T, unsigned, T *),
362 template <typename U> class OpAP>
363bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
364 const T &RHS) {
365 // Fast path - add the numbers with fixed width.
366 T Result;
367 if (!OpFW(LHS, RHS, Bits, &Result)) {
368 S.Stk.push<T>(Result);
369 return true;
370 }
371 // If for some reason evaluation continues, use the truncated results.
372 S.Stk.push<T>(Result);
373
374 // Short-circuit fixed-points here since the error handling is easier.
375 if constexpr (std::is_same_v<T, FixedPoint>)
376 return handleFixedPointOverflow(S, OpPC, Result);
377
378 // Slow path - compute the result using another bit of precision.
379 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
380
381 // Report undefined behaviour, stopping if required.
382 const Expr *E = S.Current->getExpr(OpPC);
383 QualType Type = E->getType();
384 if (S.checkingForUndefinedBehavior()) {
385 SmallString<32> Trunc;
386 Value.trunc(Result.bitWidth())
387 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
388 /*UpperCase=*/true, /*InsertSeparators=*/true);
389 auto Loc = E->getExprLoc();
390 S.report(Loc, diag::warn_integer_constant_overflow)
391 << Trunc << Type << E->getSourceRange();
392 }
393
394 if (!handleOverflow(S, OpPC, Value)) {
395 S.Stk.pop<T>();
396 return false;
397 }
398 return true;
399}
400
401template <PrimType Name, class T = typename PrimConv<Name>::T>
402bool Add(InterpState &S, CodePtr OpPC) {
403 const T &RHS = S.Stk.pop<T>();
404 const T &LHS = S.Stk.pop<T>();
405 const unsigned Bits = RHS.bitWidth() + 1;
406 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
407}
408
409static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
410 auto RM = FPO.getRoundingMode();
411 if (RM == llvm::RoundingMode::Dynamic)
412 return llvm::RoundingMode::NearestTiesToEven;
413 return RM;
414}
415
416inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
417 const Floating &RHS = S.Stk.pop<Floating>();
418 const Floating &LHS = S.Stk.pop<Floating>();
419
422 auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
423 S.Stk.push<Floating>(Result);
424 return CheckFloatResult(S, OpPC, Result, Status, FPO);
425}
426
427template <PrimType Name, class T = typename PrimConv<Name>::T>
428bool Sub(InterpState &S, CodePtr OpPC) {
429 const T &RHS = S.Stk.pop<T>();
430 const T &LHS = S.Stk.pop<T>();
431 const unsigned Bits = RHS.bitWidth() + 1;
432 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
433}
434
435inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
436 const Floating &RHS = S.Stk.pop<Floating>();
437 const Floating &LHS = S.Stk.pop<Floating>();
438
441 auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
442 S.Stk.push<Floating>(Result);
443 return CheckFloatResult(S, OpPC, Result, Status, FPO);
444}
445
446template <PrimType Name, class T = typename PrimConv<Name>::T>
447bool Mul(InterpState &S, CodePtr OpPC) {
448 const T &RHS = S.Stk.pop<T>();
449 const T &LHS = S.Stk.pop<T>();
450 const unsigned Bits = RHS.bitWidth() * 2;
451 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
452}
453
454inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
455 const Floating &RHS = S.Stk.pop<Floating>();
456 const Floating &LHS = S.Stk.pop<Floating>();
457
460 auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
461 S.Stk.push<Floating>(Result);
462 return CheckFloatResult(S, OpPC, Result, Status, FPO);
463}
464
465template <PrimType Name, class T = typename PrimConv<Name>::T>
466inline bool Mulc(InterpState &S, CodePtr OpPC) {
467 const Pointer &RHS = S.Stk.pop<Pointer>();
468 const Pointer &LHS = S.Stk.pop<Pointer>();
469 const Pointer &Result = S.Stk.peek<Pointer>();
470
471 if constexpr (std::is_same_v<T, Floating>) {
472 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
473 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
474 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
475 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
476
477 APFloat ResR(A.getSemantics());
478 APFloat ResI(A.getSemantics());
479 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
480
481 // Copy into the result.
482 Result.atIndex(0).deref<Floating>() = Floating(ResR);
483 Result.atIndex(0).initialize();
484 Result.atIndex(1).deref<Floating>() = Floating(ResI);
485 Result.atIndex(1).initialize();
486 Result.initialize();
487 } else {
488 // Integer element type.
489 const T &LHSR = LHS.atIndex(0).deref<T>();
490 const T &LHSI = LHS.atIndex(1).deref<T>();
491 const T &RHSR = RHS.atIndex(0).deref<T>();
492 const T &RHSI = RHS.atIndex(1).deref<T>();
493 unsigned Bits = LHSR.bitWidth();
494
495 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
496 T A;
497 if (T::mul(LHSR, RHSR, Bits, &A))
498 return false;
499 T B;
500 if (T::mul(LHSI, RHSI, Bits, &B))
501 return false;
502 if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
503 return false;
504 Result.atIndex(0).initialize();
505
506 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
507 if (T::mul(LHSR, RHSI, Bits, &A))
508 return false;
509 if (T::mul(LHSI, RHSR, Bits, &B))
510 return false;
511 if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
512 return false;
513 Result.atIndex(1).initialize();
514 Result.initialize();
515 }
516
517 return true;
518}
519
520template <PrimType Name, class T = typename PrimConv<Name>::T>
521inline bool Divc(InterpState &S, CodePtr OpPC) {
522 const Pointer &RHS = S.Stk.pop<Pointer>();
523 const Pointer &LHS = S.Stk.pop<Pointer>();
524 const Pointer &Result = S.Stk.peek<Pointer>();
525
526 if constexpr (std::is_same_v<T, Floating>) {
527 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
528 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
529 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
530 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
531
532 APFloat ResR(A.getSemantics());
533 APFloat ResI(A.getSemantics());
534 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
535
536 // Copy into the result.
537 Result.atIndex(0).deref<Floating>() = Floating(ResR);
538 Result.atIndex(0).initialize();
539 Result.atIndex(1).deref<Floating>() = Floating(ResI);
540 Result.atIndex(1).initialize();
541 Result.initialize();
542 } else {
543 // Integer element type.
544 const T &LHSR = LHS.atIndex(0).deref<T>();
545 const T &LHSI = LHS.atIndex(1).deref<T>();
546 const T &RHSR = RHS.atIndex(0).deref<T>();
547 const T &RHSI = RHS.atIndex(1).deref<T>();
548 unsigned Bits = LHSR.bitWidth();
549 const T Zero = T::from(0, Bits);
550
553 const SourceInfo &E = S.Current->getSource(OpPC);
554 S.FFDiag(E, diag::note_expr_divide_by_zero);
555 return false;
556 }
557
558 // Den = real(RHS)² + imag(RHS)²
559 T A, B;
560 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
561 // Ignore overflow here, because that's what the current interpeter does.
562 }
563 T Den;
564 if (T::add(A, B, Bits, &Den))
565 return false;
566
568 const SourceInfo &E = S.Current->getSource(OpPC);
569 S.FFDiag(E, diag::note_expr_divide_by_zero);
570 return false;
571 }
572
573 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
574 T &ResultR = Result.atIndex(0).deref<T>();
575 T &ResultI = Result.atIndex(1).deref<T>();
576
577 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
578 return false;
579 if (T::add(A, B, Bits, &ResultR))
580 return false;
581 if (T::div(ResultR, Den, Bits, &ResultR))
582 return false;
583 Result.atIndex(0).initialize();
584
585 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
586 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
587 return false;
588 if (T::sub(A, B, Bits, &ResultI))
589 return false;
590 if (T::div(ResultI, Den, Bits, &ResultI))
591 return false;
592 Result.atIndex(1).initialize();
593 Result.initialize();
594 }
595
596 return true;
597}
598
599/// 1) Pops the RHS from the stack.
600/// 2) Pops the LHS from the stack.
601/// 3) Pushes 'LHS & RHS' on the stack
602template <PrimType Name, class T = typename PrimConv<Name>::T>
603bool BitAnd(InterpState &S, CodePtr OpPC) {
604 const T &RHS = S.Stk.pop<T>();
605 const T &LHS = S.Stk.pop<T>();
606
607 unsigned Bits = RHS.bitWidth();
608 T Result;
609 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
610 S.Stk.push<T>(Result);
611 return true;
612 }
613 return false;
614}
615
616/// 1) Pops the RHS from the stack.
617/// 2) Pops the LHS from the stack.
618/// 3) Pushes 'LHS | RHS' on the stack
619template <PrimType Name, class T = typename PrimConv<Name>::T>
620bool BitOr(InterpState &S, CodePtr OpPC) {
621 const T &RHS = S.Stk.pop<T>();
622 const T &LHS = S.Stk.pop<T>();
623
624 unsigned Bits = RHS.bitWidth();
625 T Result;
626 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
627 S.Stk.push<T>(Result);
628 return true;
629 }
630 return false;
631}
632
633/// 1) Pops the RHS from the stack.
634/// 2) Pops the LHS from the stack.
635/// 3) Pushes 'LHS ^ RHS' on the stack
636template <PrimType Name, class T = typename PrimConv<Name>::T>
637bool BitXor(InterpState &S, CodePtr OpPC) {
638 const T &RHS = S.Stk.pop<T>();
639 const T &LHS = S.Stk.pop<T>();
640
641 unsigned Bits = RHS.bitWidth();
642 T Result;
643 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
644 S.Stk.push<T>(Result);
645 return true;
646 }
647 return false;
648}
649
650/// 1) Pops the RHS from the stack.
651/// 2) Pops the LHS from the stack.
652/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
653template <PrimType Name, class T = typename PrimConv<Name>::T>
654bool Rem(InterpState &S, CodePtr OpPC) {
655 const T &RHS = S.Stk.pop<T>();
656 const T &LHS = S.Stk.pop<T>();
657
658 if (!CheckDivRem(S, OpPC, LHS, RHS))
659 return false;
660
661 const unsigned Bits = RHS.bitWidth() * 2;
662 T Result;
663 if (!T::rem(LHS, RHS, Bits, &Result)) {
664 S.Stk.push<T>(Result);
665 return true;
666 }
667 return false;
668}
669
670/// 1) Pops the RHS from the stack.
671/// 2) Pops the LHS from the stack.
672/// 3) Pushes 'LHS / RHS' on the stack
673template <PrimType Name, class T = typename PrimConv<Name>::T>
674bool Div(InterpState &S, CodePtr OpPC) {
675 const T &RHS = S.Stk.pop<T>();
676 const T &LHS = S.Stk.pop<T>();
677
678 if (!CheckDivRem(S, OpPC, LHS, RHS))
679 return false;
680
681 const unsigned Bits = RHS.bitWidth() * 2;
682 T Result;
683 if (!T::div(LHS, RHS, Bits, &Result)) {
684 S.Stk.push<T>(Result);
685 return true;
686 }
687
688 if constexpr (std::is_same_v<T, FixedPoint>) {
689 if (handleFixedPointOverflow(S, OpPC, Result)) {
690 S.Stk.push<T>(Result);
691 return true;
692 }
693 }
694 return false;
695}
696
697inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
698 const Floating &RHS = S.Stk.pop<Floating>();
699 const Floating &LHS = S.Stk.pop<Floating>();
700
701 if (!CheckDivRem(S, OpPC, LHS, RHS))
702 return false;
703
706 auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
707 S.Stk.push<Floating>(Result);
708 return CheckFloatResult(S, OpPC, Result, Status, FPO);
709}
710
711//===----------------------------------------------------------------------===//
712// Inv
713//===----------------------------------------------------------------------===//
714
715inline bool Inv(InterpState &S, CodePtr OpPC) {
716 const auto &Val = S.Stk.pop<Boolean>();
717 S.Stk.push<Boolean>(!Val);
718 return true;
719}
720
721//===----------------------------------------------------------------------===//
722// Neg
723//===----------------------------------------------------------------------===//
724
725template <PrimType Name, class T = typename PrimConv<Name>::T>
726bool Neg(InterpState &S, CodePtr OpPC) {
727 const T &Value = S.Stk.pop<T>();
728 T Result;
729
730 if (!T::neg(Value, &Result)) {
731 S.Stk.push<T>(Result);
732 return true;
733 }
734
735 assert(isIntegralType(Name) &&
736 "don't expect other types to fail at constexpr negation");
737 S.Stk.push<T>(Result);
738
739 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
740 const Expr *E = S.Current->getExpr(OpPC);
741 QualType Type = E->getType();
742
743 if (S.checkingForUndefinedBehavior()) {
744 SmallString<32> Trunc;
745 NegatedValue.trunc(Result.bitWidth())
746 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
747 /*UpperCase=*/true, /*InsertSeparators=*/true);
748 auto Loc = E->getExprLoc();
749 S.report(Loc, diag::warn_integer_constant_overflow)
750 << Trunc << Type << E->getSourceRange();
751 return true;
752 }
753
754 return handleOverflow(S, OpPC, NegatedValue);
755}
756
757enum class PushVal : bool {
758 No,
759 Yes,
760};
761enum class IncDecOp {
762 Inc,
763 Dec,
764};
765
766template <typename T, IncDecOp Op, PushVal DoPush>
767bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
768 assert(!Ptr.isDummy());
769
770 if constexpr (std::is_same_v<T, Boolean>) {
771 if (!S.getLangOpts().CPlusPlus14)
772 return Invalid(S, OpPC);
773 }
774
775 const T &Value = Ptr.deref<T>();
776 T Result;
777
778 if constexpr (DoPush == PushVal::Yes)
779 S.Stk.push<T>(Value);
780
781 if constexpr (Op == IncDecOp::Inc) {
782 if (!T::increment(Value, &Result)) {
783 Ptr.deref<T>() = Result;
784 return true;
785 }
786 } else {
787 if (!T::decrement(Value, &Result)) {
788 Ptr.deref<T>() = Result;
789 return true;
790 }
791 }
792
793 // Something went wrong with the previous operation. Compute the
794 // result with another bit of precision.
795 unsigned Bits = Value.bitWidth() + 1;
796 APSInt APResult;
797 if constexpr (Op == IncDecOp::Inc)
798 APResult = ++Value.toAPSInt(Bits);
799 else
800 APResult = --Value.toAPSInt(Bits);
801
802 // Report undefined behaviour, stopping if required.
803 const Expr *E = S.Current->getExpr(OpPC);
804 QualType Type = E->getType();
805 if (S.checkingForUndefinedBehavior()) {
806 SmallString<32> Trunc;
807 APResult.trunc(Result.bitWidth())
808 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
809 /*UpperCase=*/true, /*InsertSeparators=*/true);
810 auto Loc = E->getExprLoc();
811 S.report(Loc, diag::warn_integer_constant_overflow)
812 << Trunc << Type << E->getSourceRange();
813 return true;
814 }
815
816 return handleOverflow(S, OpPC, APResult);
817}
818
819/// 1) Pops a pointer from the stack
820/// 2) Load the value from the pointer
821/// 3) Writes the value increased by one back to the pointer
822/// 4) Pushes the original (pre-inc) value on the stack.
823template <PrimType Name, class T = typename PrimConv<Name>::T>
824bool Inc(InterpState &S, CodePtr OpPC) {
825 const Pointer &Ptr = S.Stk.pop<Pointer>();
826 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
827 return false;
828
829 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
830}
831
832/// 1) Pops a pointer from the stack
833/// 2) Load the value from the pointer
834/// 3) Writes the value increased by one back to the pointer
835template <PrimType Name, class T = typename PrimConv<Name>::T>
836bool IncPop(InterpState &S, CodePtr OpPC) {
837 const Pointer &Ptr = S.Stk.pop<Pointer>();
838 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
839 return false;
840
841 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
842}
843
844/// 1) Pops a pointer from the stack
845/// 2) Load the value from the pointer
846/// 3) Writes the value decreased by one back to the pointer
847/// 4) Pushes the original (pre-dec) value on the stack.
848template <PrimType Name, class T = typename PrimConv<Name>::T>
849bool Dec(InterpState &S, CodePtr OpPC) {
850 const Pointer &Ptr = S.Stk.pop<Pointer>();
851 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
852 return false;
853
854 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
855}
856
857/// 1) Pops a pointer from the stack
858/// 2) Load the value from the pointer
859/// 3) Writes the value decreased by one back to the pointer
860template <PrimType Name, class T = typename PrimConv<Name>::T>
861bool DecPop(InterpState &S, CodePtr OpPC) {
862 const Pointer &Ptr = S.Stk.pop<Pointer>();
863 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
864 return false;
865
866 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
867}
868
869template <IncDecOp Op, PushVal DoPush>
871 uint32_t FPOI) {
872 Floating Value = Ptr.deref<Floating>();
874
875 if constexpr (DoPush == PushVal::Yes)
876 S.Stk.push<Floating>(Value);
877
879 llvm::APFloat::opStatus Status;
880 if constexpr (Op == IncDecOp::Inc)
882 else
884
885 Ptr.deref<Floating>() = Result;
886
887 return CheckFloatResult(S, OpPC, Result, Status, FPO);
888}
889
890inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
891 const Pointer &Ptr = S.Stk.pop<Pointer>();
892 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
893 return false;
894
895 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
896}
897
898inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
899 const Pointer &Ptr = S.Stk.pop<Pointer>();
900 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
901 return false;
902
903 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
904}
905
906inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
907 const Pointer &Ptr = S.Stk.pop<Pointer>();
908 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
909 return false;
910
911 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
912}
913
914inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
915 const Pointer &Ptr = S.Stk.pop<Pointer>();
916 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
917 return false;
918
919 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
920}
921
922/// 1) Pops the value from the stack.
923/// 2) Pushes the bitwise complemented value on the stack (~V).
924template <PrimType Name, class T = typename PrimConv<Name>::T>
925bool Comp(InterpState &S, CodePtr OpPC) {
926 const T &Val = S.Stk.pop<T>();
927 T Result;
928 if (!T::comp(Val, &Result)) {
929 S.Stk.push<T>(Result);
930 return true;
931 }
932
933 return false;
934}
935
936//===----------------------------------------------------------------------===//
937// EQ, NE, GT, GE, LT, LE
938//===----------------------------------------------------------------------===//
939
940using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
941
942template <typename T>
944 assert((!std::is_same_v<T, MemberPointer>) &&
945 "Non-equality comparisons on member pointer types should already be "
946 "rejected in Sema.");
947 using BoolT = PrimConv<PT_Bool>::T;
948 const T &RHS = S.Stk.pop<T>();
949 const T &LHS = S.Stk.pop<T>();
950 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
951 return true;
952}
953
954template <typename T>
956 return CmpHelper<T>(S, OpPC, Fn);
957}
958
959/// Function pointers cannot be compared in an ordered way.
960template <>
962 CompareFn Fn) {
963 const auto &RHS = S.Stk.pop<FunctionPointer>();
964 const auto &LHS = S.Stk.pop<FunctionPointer>();
965
966 const SourceInfo &Loc = S.Current->getSource(OpPC);
967 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
969 << RHS.toDiagnosticString(S.getASTContext());
970 return false;
971}
972
973template <>
975 CompareFn Fn) {
976 const auto &RHS = S.Stk.pop<FunctionPointer>();
977 const auto &LHS = S.Stk.pop<FunctionPointer>();
978
979 // We cannot compare against weak declarations at compile time.
980 for (const auto &FP : {LHS, RHS}) {
981 if (FP.isWeak()) {
982 const SourceInfo &Loc = S.Current->getSource(OpPC);
983 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
984 << FP.toDiagnosticString(S.getASTContext());
985 return false;
986 }
987 }
988
989 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
990 return true;
991}
992
993template <>
995 using BoolT = PrimConv<PT_Bool>::T;
996 const Pointer &RHS = S.Stk.pop<Pointer>();
997 const Pointer &LHS = S.Stk.pop<Pointer>();
998
999 if (!Pointer::hasSameBase(LHS, RHS)) {
1000 const SourceInfo &Loc = S.Current->getSource(OpPC);
1001 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1002 << LHS.toDiagnosticString(S.getASTContext())
1004 return false;
1005 } else {
1006 unsigned VL = LHS.getByteOffset();
1007 unsigned VR = RHS.getByteOffset();
1008 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1009 return true;
1010 }
1011}
1012
1013template <>
1015 using BoolT = PrimConv<PT_Bool>::T;
1016 const Pointer &RHS = S.Stk.pop<Pointer>();
1017 const Pointer &LHS = S.Stk.pop<Pointer>();
1018
1019 if (LHS.isZero() && RHS.isZero()) {
1020 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
1021 return true;
1022 }
1023
1024 // Reject comparisons to weak pointers.
1025 for (const auto &P : {LHS, RHS}) {
1026 if (P.isZero())
1027 continue;
1028 if (P.isWeak()) {
1029 const SourceInfo &Loc = S.Current->getSource(OpPC);
1030 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1031 << P.toDiagnosticString(S.getASTContext());
1032 return false;
1033 }
1034 }
1035
1036 if (Pointer::hasSameBase(LHS, RHS)) {
1037 unsigned VL = LHS.getByteOffset();
1038 unsigned VR = RHS.getByteOffset();
1039
1040 // In our Pointer class, a pointer to an array and a pointer to the first
1041 // element in the same array are NOT equal. They have the same Base value,
1042 // but a different Offset. This is a pretty rare case, so we fix this here
1043 // by comparing pointers to the first elements.
1044 if (!LHS.isZero() && LHS.isArrayRoot())
1045 VL = LHS.atIndex(0).getByteOffset();
1046 if (!RHS.isZero() && RHS.isArrayRoot())
1047 VR = RHS.atIndex(0).getByteOffset();
1048
1049 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1050 return true;
1051 }
1052 // Otherwise we need to do a bunch of extra checks before returning Unordered.
1053 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
1054 RHS.getOffset() == 0) {
1055 const SourceInfo &Loc = S.Current->getSource(OpPC);
1056 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1057 << LHS.toDiagnosticString(S.getASTContext());
1058 return false;
1059 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1060 LHS.getOffset() == 0) {
1061 const SourceInfo &Loc = S.Current->getSource(OpPC);
1062 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1064 return false;
1065 }
1066
1067 bool BothNonNull = !LHS.isZero() && !RHS.isZero();
1068 // Reject comparisons to literals.
1069 for (const auto &P : {LHS, RHS}) {
1070 if (P.isZero())
1071 continue;
1072 if (BothNonNull && P.pointsToLiteral()) {
1073 const SourceInfo &Loc = S.Current->getSource(OpPC);
1074 S.FFDiag(Loc, diag::note_constexpr_literal_comparison);
1075 return false;
1076 }
1077 }
1078
1079 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1080 return true;
1081}
1082
1083template <>
1085 CompareFn Fn) {
1086 const auto &RHS = S.Stk.pop<MemberPointer>();
1087 const auto &LHS = S.Stk.pop<MemberPointer>();
1088
1089 // If either operand is a pointer to a weak function, the comparison is not
1090 // constant.
1091 for (const auto &MP : {LHS, RHS}) {
1092 if (MP.isWeak()) {
1093 const SourceInfo &Loc = S.Current->getSource(OpPC);
1094 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1095 << MP.getMemberFunction();
1096 return false;
1097 }
1098 }
1099
1100 // C++11 [expr.eq]p2:
1101 // If both operands are null, they compare equal. Otherwise if only one is
1102 // null, they compare unequal.
1103 if (LHS.isZero() && RHS.isZero()) {
1105 return true;
1106 }
1107 if (LHS.isZero() || RHS.isZero()) {
1109 return true;
1110 }
1111
1112 // We cannot compare against virtual declarations at compile time.
1113 for (const auto &MP : {LHS, RHS}) {
1114 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1115 MD && MD->isVirtual()) {
1116 const SourceInfo &Loc = S.Current->getSource(OpPC);
1117 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1118 }
1119 }
1120
1121 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1122 return true;
1123}
1124
1125template <PrimType Name, class T = typename PrimConv<Name>::T>
1126bool EQ(InterpState &S, CodePtr OpPC) {
1127 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1129 });
1130}
1131
1132template <PrimType Name, class T = typename PrimConv<Name>::T>
1133bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1134 const T &RHS = S.Stk.pop<T>();
1135 const T &LHS = S.Stk.pop<T>();
1136 const Pointer &P = S.Stk.peek<Pointer>();
1137
1138 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1139 if (CmpResult == ComparisonCategoryResult::Unordered) {
1140 // This should only happen with pointers.
1141 const SourceInfo &Loc = S.Current->getSource(OpPC);
1142 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1143 << LHS.toDiagnosticString(S.getASTContext())
1144 << RHS.toDiagnosticString(S.getASTContext());
1145 return false;
1146 }
1147
1148 assert(CmpInfo);
1149 const auto *CmpValueInfo =
1150 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1151 assert(CmpValueInfo);
1152 assert(CmpValueInfo->hasValidIntValue());
1153 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1154}
1155
1156template <PrimType Name, class T = typename PrimConv<Name>::T>
1157bool NE(InterpState &S, CodePtr OpPC) {
1158 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1160 });
1161}
1162
1163template <PrimType Name, class T = typename PrimConv<Name>::T>
1164bool LT(InterpState &S, CodePtr OpPC) {
1165 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1167 });
1168}
1169
1170template <PrimType Name, class T = typename PrimConv<Name>::T>
1171bool LE(InterpState &S, CodePtr OpPC) {
1172 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1173 return R == ComparisonCategoryResult::Less ||
1175 });
1176}
1177
1178template <PrimType Name, class T = typename PrimConv<Name>::T>
1179bool GT(InterpState &S, CodePtr OpPC) {
1180 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1182 });
1183}
1184
1185template <PrimType Name, class T = typename PrimConv<Name>::T>
1186bool GE(InterpState &S, CodePtr OpPC) {
1187 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1190 });
1191}
1192
1193//===----------------------------------------------------------------------===//
1194// InRange
1195//===----------------------------------------------------------------------===//
1196
1197template <PrimType Name, class T = typename PrimConv<Name>::T>
1199 const T RHS = S.Stk.pop<T>();
1200 const T LHS = S.Stk.pop<T>();
1201 const T Value = S.Stk.pop<T>();
1202
1203 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1204 return true;
1205}
1206
1207//===----------------------------------------------------------------------===//
1208// Dup, Pop, Test
1209//===----------------------------------------------------------------------===//
1210
1211template <PrimType Name, class T = typename PrimConv<Name>::T>
1212bool Dup(InterpState &S, CodePtr OpPC) {
1213 S.Stk.push<T>(S.Stk.peek<T>());
1214 return true;
1215}
1216
1217template <PrimType Name, class T = typename PrimConv<Name>::T>
1218bool Pop(InterpState &S, CodePtr OpPC) {
1219 S.Stk.pop<T>();
1220 return true;
1221}
1222
1223/// [Value1, Value2] -> [Value2, Value1]
1224template <PrimType TopName, PrimType BottomName>
1225bool Flip(InterpState &S, CodePtr OpPC) {
1226 using TopT = typename PrimConv<TopName>::T;
1227 using BottomT = typename PrimConv<BottomName>::T;
1228
1229 const auto &Top = S.Stk.pop<TopT>();
1230 const auto &Bottom = S.Stk.pop<BottomT>();
1231
1232 S.Stk.push<TopT>(Top);
1233 S.Stk.push<BottomT>(Bottom);
1234
1235 return true;
1236}
1237
1238//===----------------------------------------------------------------------===//
1239// Const
1240//===----------------------------------------------------------------------===//
1241
1242template <PrimType Name, class T = typename PrimConv<Name>::T>
1243bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1244 S.Stk.push<T>(Arg);
1245 return true;
1246}
1247
1248//===----------------------------------------------------------------------===//
1249// Get/Set Local/Param/Global/This
1250//===----------------------------------------------------------------------===//
1251
1252template <PrimType Name, class T = typename PrimConv<Name>::T>
1253bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1254 const Pointer &Ptr = S.Current->getLocalPointer(I);
1255 if (!CheckLoad(S, OpPC, Ptr))
1256 return false;
1257 S.Stk.push<T>(Ptr.deref<T>());
1258 return true;
1259}
1260
1261/// 1) Pops the value from the stack.
1262/// 2) Writes the value to the local variable with the
1263/// given offset.
1264template <PrimType Name, class T = typename PrimConv<Name>::T>
1265bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1266 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1267 return true;
1268}
1269
1270template <PrimType Name, class T = typename PrimConv<Name>::T>
1271bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1272 if (S.checkingPotentialConstantExpression()) {
1273 return false;
1274 }
1275 S.Stk.push<T>(S.Current->getParam<T>(I));
1276 return true;
1277}
1278
1279template <PrimType Name, class T = typename PrimConv<Name>::T>
1280bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1281 S.Current->setParam<T>(I, S.Stk.pop<T>());
1282 return true;
1283}
1284
1285/// 1) Peeks a pointer on the stack
1286/// 2) Pushes the value of the pointer's field on the stack
1287template <PrimType Name, class T = typename PrimConv<Name>::T>
1288bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1289 const Pointer &Obj = S.Stk.peek<Pointer>();
1290 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1291 return false;
1292 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1293 return false;
1294 const Pointer &Field = Obj.atField(I);
1295 if (!CheckLoad(S, OpPC, Field))
1296 return false;
1297 S.Stk.push<T>(Field.deref<T>());
1298 return true;
1299}
1300
1301template <PrimType Name, class T = typename PrimConv<Name>::T>
1302bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1303 const T &Value = S.Stk.pop<T>();
1304 const Pointer &Obj = S.Stk.peek<Pointer>();
1305 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1306 return false;
1307 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1308 return false;
1309 const Pointer &Field = Obj.atField(I);
1310 if (!CheckStore(S, OpPC, Field))
1311 return false;
1312 Field.initialize();
1313 Field.deref<T>() = Value;
1314 return true;
1315}
1316
1317/// 1) Pops a pointer from the stack
1318/// 2) Pushes the value of the pointer's field on the stack
1319template <PrimType Name, class T = typename PrimConv<Name>::T>
1320bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1321 const Pointer &Obj = S.Stk.pop<Pointer>();
1322 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1323 return false;
1324 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1325 return false;
1326 const Pointer &Field = Obj.atField(I);
1327 if (!CheckLoad(S, OpPC, Field))
1328 return false;
1329 S.Stk.push<T>(Field.deref<T>());
1330 return true;
1331}
1332
1333template <PrimType Name, class T = typename PrimConv<Name>::T>
1334bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1335 if (S.checkingPotentialConstantExpression())
1336 return false;
1337 const Pointer &This = S.Current->getThis();
1338 if (!CheckThis(S, OpPC, This))
1339 return false;
1340 const Pointer &Field = This.atField(I);
1341 if (!CheckLoad(S, OpPC, Field))
1342 return false;
1343 S.Stk.push<T>(Field.deref<T>());
1344 return true;
1345}
1346
1347template <PrimType Name, class T = typename PrimConv<Name>::T>
1348bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1349 if (S.checkingPotentialConstantExpression())
1350 return false;
1351 const T &Value = S.Stk.pop<T>();
1352 const Pointer &This = S.Current->getThis();
1353 if (!CheckThis(S, OpPC, This))
1354 return false;
1355 const Pointer &Field = This.atField(I);
1356 if (!CheckStore(S, OpPC, Field))
1357 return false;
1358 Field.deref<T>() = Value;
1359 return true;
1360}
1361
1362template <PrimType Name, class T = typename PrimConv<Name>::T>
1363bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1364 const Pointer &Ptr = S.P.getPtrGlobal(I);
1365 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1366 return false;
1367 if (Ptr.isExtern())
1368 return false;
1369
1370 // If a global variable is uninitialized, that means the initializer we've
1371 // compiled for it wasn't a constant expression. Diagnose that.
1372 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1373 return false;
1374
1375 S.Stk.push<T>(Ptr.deref<T>());
1376 return true;
1377}
1378
1379/// Same as GetGlobal, but without the checks.
1380template <PrimType Name, class T = typename PrimConv<Name>::T>
1381bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1382 const Pointer &Ptr = S.P.getPtrGlobal(I);
1383 if (!Ptr.isInitialized())
1384 return false;
1385 S.Stk.push<T>(Ptr.deref<T>());
1386 return true;
1387}
1388
1389template <PrimType Name, class T = typename PrimConv<Name>::T>
1390bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1391 // TODO: emit warning.
1392 return false;
1393}
1394
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1396bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1397 const Pointer &P = S.P.getGlobal(I);
1398 P.deref<T>() = S.Stk.pop<T>();
1399 P.initialize();
1400 return true;
1401}
1402
1403/// 1) Converts the value on top of the stack to an APValue
1404/// 2) Sets that APValue on \Temp
1405/// 3) Initializes global with index \I with that
1406template <PrimType Name, class T = typename PrimConv<Name>::T>
1407bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1408 const LifetimeExtendedTemporaryDecl *Temp) {
1409 const Pointer &Ptr = S.P.getGlobal(I);
1410
1411 const T Value = S.Stk.peek<T>();
1412 APValue APV = Value.toAPValue(S.getASTContext());
1413 APValue *Cached = Temp->getOrCreateValue(true);
1414 *Cached = APV;
1415
1416 assert(Ptr.getDeclDesc()->asExpr());
1417
1418 S.SeenGlobalTemporaries.push_back(
1419 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1420
1421 Ptr.deref<T>() = S.Stk.pop<T>();
1422 Ptr.initialize();
1423 return true;
1424}
1425
1426/// 1) Converts the value on top of the stack to an APValue
1427/// 2) Sets that APValue on \Temp
1428/// 3) Initialized global with index \I with that
1430 const LifetimeExtendedTemporaryDecl *Temp) {
1431 assert(Temp);
1432 const Pointer &P = S.Stk.peek<Pointer>();
1433 APValue *Cached = Temp->getOrCreateValue(true);
1434
1435 S.SeenGlobalTemporaries.push_back(
1436 std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1437
1438 if (std::optional<APValue> APV =
1439 P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) {
1440 *Cached = *APV;
1441 return true;
1442 }
1443
1444 return false;
1445}
1446
1447template <PrimType Name, class T = typename PrimConv<Name>::T>
1448bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1449 if (S.checkingPotentialConstantExpression())
1450 return false;
1451 const Pointer &This = S.Current->getThis();
1452 if (!CheckThis(S, OpPC, This))
1453 return false;
1454 const Pointer &Field = This.atField(I);
1455 Field.deref<T>() = S.Stk.pop<T>();
1456 Field.activate();
1457 Field.initialize();
1458 return true;
1459}
1460
1461// FIXME: The Field pointer here is too much IMO and we could instead just
1462// pass an Offset + BitWidth pair.
1463template <PrimType Name, class T = typename PrimConv<Name>::T>
1464bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1465 uint32_t FieldOffset) {
1466 assert(F->isBitField());
1467 if (S.checkingPotentialConstantExpression())
1468 return false;
1469 const Pointer &This = S.Current->getThis();
1470 if (!CheckThis(S, OpPC, This))
1471 return false;
1472 const Pointer &Field = This.atField(FieldOffset);
1473 const auto &Value = S.Stk.pop<T>();
1474 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1475 Field.initialize();
1476 return true;
1477}
1478
1479/// 1) Pops the value from the stack
1480/// 2) Peeks a pointer from the stack
1481/// 3) Pushes the value to field I of the pointer on the stack
1482template <PrimType Name, class T = typename PrimConv<Name>::T>
1483bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1484 const T &Value = S.Stk.pop<T>();
1485 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1486 Field.deref<T>() = Value;
1487 Field.activate();
1488 Field.initialize();
1489 return true;
1490}
1491
1492template <PrimType Name, class T = typename PrimConv<Name>::T>
1493bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1494 assert(F->isBitField());
1495 const T &Value = S.Stk.pop<T>();
1496 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1497 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1498 Field.activate();
1499 Field.initialize();
1500 return true;
1501}
1502
1503//===----------------------------------------------------------------------===//
1504// GetPtr Local/Param/Global/Field/This
1505//===----------------------------------------------------------------------===//
1506
1507inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1508 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1509 return true;
1510}
1511
1512inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1513 if (S.checkingPotentialConstantExpression()) {
1514 return false;
1515 }
1516 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1517 return true;
1518}
1519
1520inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1521 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1522 return true;
1523}
1524
1525/// 1) Peeks a Pointer
1526/// 2) Pushes Pointer.atField(Off) on the stack
1527bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1528bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
1529
1530inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1531 if (S.checkingPotentialConstantExpression())
1532 return false;
1533 const Pointer &This = S.Current->getThis();
1534 if (!CheckThis(S, OpPC, This))
1535 return false;
1536 S.Stk.push<Pointer>(This.atField(Off));
1537 return true;
1538}
1539
1540inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1541 const Pointer &Ptr = S.Stk.pop<Pointer>();
1542 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1543 return false;
1544 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1545 return false;
1546 Pointer Field = Ptr.atField(Off);
1547 Ptr.deactivate();
1548 Field.activate();
1549 S.Stk.push<Pointer>(std::move(Field));
1550 return true;
1551}
1552
1553inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1554 if (S.checkingPotentialConstantExpression())
1555 return false;
1556 const Pointer &This = S.Current->getThis();
1557 if (!CheckThis(S, OpPC, This))
1558 return false;
1559 Pointer Field = This.atField(Off);
1560 This.deactivate();
1561 Field.activate();
1562 S.Stk.push<Pointer>(std::move(Field));
1563 return true;
1564}
1565
1566inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1567 const Pointer &Ptr = S.Stk.pop<Pointer>();
1568 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1569 return false;
1570 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1571 return false;
1572 if (!CheckDowncast(S, OpPC, Ptr, Off))
1573 return false;
1574
1575 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1576 return true;
1577}
1578
1579inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1580 const Pointer &Ptr = S.Stk.peek<Pointer>();
1581 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1582 return false;
1583
1584 if (!Ptr.isBlockPointer()) {
1585 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1586 return true;
1587 }
1588
1589 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1590 return false;
1591 const Pointer &Result = Ptr.atField(Off);
1592 if (Result.isPastEnd() || !Result.isBaseClass())
1593 return false;
1594 S.Stk.push<Pointer>(Result);
1595 return true;
1596}
1597
1598inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1599 const Pointer &Ptr = S.Stk.pop<Pointer>();
1600
1601 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1602 return false;
1603
1604 if (!Ptr.isBlockPointer()) {
1605 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1606 return true;
1607 }
1608
1609 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1610 return false;
1611 const Pointer &Result = Ptr.atField(Off);
1612 if (Result.isPastEnd() || !Result.isBaseClass())
1613 return false;
1614 S.Stk.push<Pointer>(Result);
1615 return true;
1616}
1617
1618inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1619 const auto &Ptr = S.Stk.pop<MemberPointer>();
1620 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1621 return true;
1622}
1623
1624inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1625 if (S.checkingPotentialConstantExpression())
1626 return false;
1627 const Pointer &This = S.Current->getThis();
1628 if (!CheckThis(S, OpPC, This))
1629 return false;
1630 S.Stk.push<Pointer>(This.atField(Off));
1631 return true;
1632}
1633
1634inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1635 const Pointer &Ptr = S.Stk.pop<Pointer>();
1636 if (Ptr.canBeInitialized()) {
1637 Ptr.initialize();
1638 Ptr.activate();
1639 }
1640 return true;
1641}
1642
1643inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1644 const Pointer &Ptr = S.Stk.peek<Pointer>();
1645 if (Ptr.canBeInitialized()) {
1646 Ptr.initialize();
1647 Ptr.activate();
1648 }
1649 return true;
1650}
1651
1652inline bool Dump(InterpState &S, CodePtr OpPC) {
1653 S.Stk.dump();
1654 return true;
1655}
1656
1657inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1658 const Pointer &Ptr) {
1659 Pointer Base = Ptr;
1660 while (Base.isBaseClass())
1661 Base = Base.getBase();
1662
1663 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1664 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1665 return true;
1666}
1667
1669 const RecordDecl *D) {
1670 assert(D);
1671 const Pointer &Ptr = S.Stk.pop<Pointer>();
1672 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1673 return false;
1674 return VirtBaseHelper(S, OpPC, D, Ptr);
1675}
1676
1678 const RecordDecl *D) {
1679 assert(D);
1680 if (S.checkingPotentialConstantExpression())
1681 return false;
1682 const Pointer &This = S.Current->getThis();
1683 if (!CheckThis(S, OpPC, This))
1684 return false;
1685 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1686}
1687
1688//===----------------------------------------------------------------------===//
1689// Load, Store, Init
1690//===----------------------------------------------------------------------===//
1691
1692template <PrimType Name, class T = typename PrimConv<Name>::T>
1693bool Load(InterpState &S, CodePtr OpPC) {
1694 const Pointer &Ptr = S.Stk.peek<Pointer>();
1695 if (!CheckLoad(S, OpPC, Ptr))
1696 return false;
1697 if (!Ptr.isBlockPointer())
1698 return false;
1699 S.Stk.push<T>(Ptr.deref<T>());
1700 return true;
1701}
1702
1703template <PrimType Name, class T = typename PrimConv<Name>::T>
1705 const Pointer &Ptr = S.Stk.pop<Pointer>();
1706 if (!CheckLoad(S, OpPC, Ptr))
1707 return false;
1708 if (!Ptr.isBlockPointer())
1709 return false;
1710 S.Stk.push<T>(Ptr.deref<T>());
1711 return true;
1712}
1713
1714template <PrimType Name, class T = typename PrimConv<Name>::T>
1715bool Store(InterpState &S, CodePtr OpPC) {
1716 const T &Value = S.Stk.pop<T>();
1717 const Pointer &Ptr = S.Stk.peek<Pointer>();
1718 if (!CheckStore(S, OpPC, Ptr))
1719 return false;
1720 if (Ptr.canBeInitialized()) {
1721 Ptr.initialize();
1722 Ptr.activate();
1723 }
1724 Ptr.deref<T>() = Value;
1725 return true;
1726}
1727
1728template <PrimType Name, class T = typename PrimConv<Name>::T>
1730 const T &Value = S.Stk.pop<T>();
1731 const Pointer &Ptr = S.Stk.pop<Pointer>();
1732 if (!CheckStore(S, OpPC, Ptr))
1733 return false;
1734 if (Ptr.canBeInitialized()) {
1735 Ptr.initialize();
1736 Ptr.activate();
1737 }
1738 Ptr.deref<T>() = Value;
1739 return true;
1740}
1741
1742template <PrimType Name, class T = typename PrimConv<Name>::T>
1744 const T &Value = S.Stk.pop<T>();
1745 const Pointer &Ptr = S.Stk.peek<Pointer>();
1746 if (!CheckStore(S, OpPC, Ptr))
1747 return false;
1748 if (Ptr.canBeInitialized())
1749 Ptr.initialize();
1750 if (const auto *FD = Ptr.getField())
1751 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1752 else
1753 Ptr.deref<T>() = Value;
1754 return true;
1755}
1756
1757template <PrimType Name, class T = typename PrimConv<Name>::T>
1759 const T &Value = S.Stk.pop<T>();
1760 const Pointer &Ptr = S.Stk.pop<Pointer>();
1761 if (!CheckStore(S, OpPC, Ptr))
1762 return false;
1763 if (Ptr.canBeInitialized())
1764 Ptr.initialize();
1765 if (const auto *FD = Ptr.getField())
1766 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1767 else
1768 Ptr.deref<T>() = Value;
1769 return true;
1770}
1771
1772template <PrimType Name, class T = typename PrimConv<Name>::T>
1773bool Init(InterpState &S, CodePtr OpPC) {
1774 const T &Value = S.Stk.pop<T>();
1775 const Pointer &Ptr = S.Stk.peek<Pointer>();
1776 if (!CheckInit(S, OpPC, Ptr)) {
1777 assert(false);
1778 return false;
1779 }
1780 Ptr.activate();
1781 Ptr.initialize();
1782 new (&Ptr.deref<T>()) T(Value);
1783 return true;
1784}
1785
1786template <PrimType Name, class T = typename PrimConv<Name>::T>
1788 const T &Value = S.Stk.pop<T>();
1789 const Pointer &Ptr = S.Stk.pop<Pointer>();
1790 if (!CheckInit(S, OpPC, Ptr))
1791 return false;
1792 Ptr.activate();
1793 Ptr.initialize();
1794 new (&Ptr.deref<T>()) T(Value);
1795 return true;
1796}
1797
1798/// 1) Pops the value from the stack
1799/// 2) Peeks a pointer and gets its index \Idx
1800/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1801template <PrimType Name, class T = typename PrimConv<Name>::T>
1802bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1803 const T &Value = S.Stk.pop<T>();
1804 const Pointer &Ptr = S.Stk.peek<Pointer>();
1805
1806 if (Ptr.isUnknownSizeArray())
1807 return false;
1808
1809 // In the unlikely event that we're initializing the first item of
1810 // a non-array, skip the atIndex().
1811 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1812 Ptr.initialize();
1813 new (&Ptr.deref<T>()) T(Value);
1814 return true;
1815 }
1816
1817 const Pointer &ElemPtr = Ptr.atIndex(Idx);
1818 if (!CheckInit(S, OpPC, ElemPtr))
1819 return false;
1820 ElemPtr.initialize();
1821 new (&ElemPtr.deref<T>()) T(Value);
1822 return true;
1823}
1824
1825/// The same as InitElem, but pops the pointer as well.
1826template <PrimType Name, class T = typename PrimConv<Name>::T>
1827bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1828 const T &Value = S.Stk.pop<T>();
1829 const Pointer &Ptr = S.Stk.pop<Pointer>();
1830 if (Ptr.isUnknownSizeArray())
1831 return false;
1832
1833 // In the unlikely event that we're initializing the first item of
1834 // a non-array, skip the atIndex().
1835 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1836 Ptr.initialize();
1837 new (&Ptr.deref<T>()) T(Value);
1838 return true;
1839 }
1840
1841 const Pointer &ElemPtr = Ptr.atIndex(Idx);
1842 if (!CheckInit(S, OpPC, ElemPtr))
1843 return false;
1844 ElemPtr.initialize();
1845 new (&ElemPtr.deref<T>()) T(Value);
1846 return true;
1847}
1848
1849inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1850 const Pointer &Src = S.Stk.pop<Pointer>();
1851 Pointer &Dest = S.Stk.peek<Pointer>();
1852
1853 if (!CheckLoad(S, OpPC, Src))
1854 return false;
1855
1856 return DoMemcpy(S, OpPC, Src, Dest);
1857}
1858
1859inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1860 const auto &Member = S.Stk.pop<MemberPointer>();
1861 const auto &Base = S.Stk.pop<Pointer>();
1862
1863 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1864 return true;
1865}
1866
1867inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1868 const auto &MP = S.Stk.pop<MemberPointer>();
1869
1870 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1871 S.Stk.push<Pointer>(*Ptr);
1872 return true;
1873 }
1874 return false;
1875}
1876
1877//===----------------------------------------------------------------------===//
1878// AddOffset, SubOffset
1879//===----------------------------------------------------------------------===//
1880
1881template <class T, ArithOp Op>
1882bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1883 const Pointer &Ptr, bool IsPointerArith = false) {
1884 // A zero offset does not change the pointer.
1885 if (Offset.isZero()) {
1886 S.Stk.push<Pointer>(Ptr);
1887 return true;
1888 }
1889
1890 if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1891 // The CheckNull will have emitted a note already, but we only
1892 // abort in C++, since this is fine in C.
1893 if (S.getLangOpts().CPlusPlus)
1894 return false;
1895 }
1896
1897 // Arrays of unknown bounds cannot have pointers into them.
1898 if (!CheckArray(S, OpPC, Ptr))
1899 return false;
1900
1901 // This is much simpler for integral pointers, so handle them first.
1902 if (Ptr.isIntegralPointer()) {
1903 uint64_t V = Ptr.getIntegerRepresentation();
1904 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
1905 if constexpr (Op == ArithOp::Add)
1906 S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
1907 else
1908 S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
1909 return true;
1910 } else if (Ptr.isFunctionPointer()) {
1911 uint64_t O = static_cast<uint64_t>(Offset);
1912 uint64_t N;
1913 if constexpr (Op == ArithOp::Add)
1914 N = Ptr.getByteOffset() + O;
1915 else
1916 N = Ptr.getByteOffset() - O;
1917
1918 if (N > 1)
1919 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1920 << N << /*non-array*/ true << 0;
1921 S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N);
1922 return true;
1923 }
1924
1925 assert(Ptr.isBlockPointer());
1926
1927 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1928 uint64_t Index;
1929 if (Ptr.isOnePastEnd())
1930 Index = MaxIndex;
1931 else
1932 Index = Ptr.getIndex();
1933
1934 bool Invalid = false;
1935 // Helper to report an invalid offset, computed as APSInt.
1936 auto DiagInvalidOffset = [&]() -> void {
1937 const unsigned Bits = Offset.bitWidth();
1938 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1939 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1940 /*IsUnsigned=*/false);
1941 APSInt NewIndex =
1942 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1943 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1944 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1945 Invalid = true;
1946 };
1947
1948 if (Ptr.isBlockPointer()) {
1949 uint64_t IOffset = static_cast<uint64_t>(Offset);
1950 uint64_t MaxOffset = MaxIndex - Index;
1951
1952 if constexpr (Op == ArithOp::Add) {
1953 // If the new offset would be negative, bail out.
1954 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1955 DiagInvalidOffset();
1956
1957 // If the new offset would be out of bounds, bail out.
1958 if (Offset.isPositive() && IOffset > MaxOffset)
1959 DiagInvalidOffset();
1960 } else {
1961 // If the new offset would be negative, bail out.
1962 if (Offset.isPositive() && Index < IOffset)
1963 DiagInvalidOffset();
1964
1965 // If the new offset would be out of bounds, bail out.
1966 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1967 DiagInvalidOffset();
1968 }
1969 }
1970
1971 if (Invalid && S.getLangOpts().CPlusPlus)
1972 return false;
1973
1974 // Offset is valid - compute it on unsigned.
1975 int64_t WideIndex = static_cast<int64_t>(Index);
1976 int64_t WideOffset = static_cast<int64_t>(Offset);
1977 int64_t Result;
1978 if constexpr (Op == ArithOp::Add)
1979 Result = WideIndex + WideOffset;
1980 else
1981 Result = WideIndex - WideOffset;
1982
1983 // When the pointer is one-past-end, going back to index 0 is the only
1984 // useful thing we can do. Any other index has been diagnosed before and
1985 // we don't get here.
1986 if (Result == 0 && Ptr.isOnePastEnd()) {
1987 S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
1988 Ptr.asBlockPointer().Base);
1989 return true;
1990 }
1991
1992 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1993 return true;
1994}
1995
1996template <PrimType Name, class T = typename PrimConv<Name>::T>
1998 const T &Offset = S.Stk.pop<T>();
1999 Pointer Ptr = S.Stk.pop<Pointer>();
2000 if (Ptr.isBlockPointer())
2001 Ptr = Ptr.expand();
2002 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
2003 /*IsPointerArith=*/true);
2004}
2005
2006template <PrimType Name, class T = typename PrimConv<Name>::T>
2008 const T &Offset = S.Stk.pop<T>();
2009 const Pointer &Ptr = S.Stk.pop<Pointer>();
2010 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
2011 /*IsPointerArith=*/true);
2012}
2013
2014template <ArithOp Op>
2015static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2016 const Pointer &Ptr) {
2017 if (Ptr.isDummy())
2018 return false;
2019
2020 using OneT = Integral<8, false>;
2021
2022 const Pointer &P = Ptr.deref<Pointer>();
2023 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
2024 return false;
2025
2026 // Get the current value on the stack.
2027 S.Stk.push<Pointer>(P);
2028
2029 // Now the current Ptr again and a constant 1.
2030 OneT One = OneT::from(1);
2031 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true))
2032 return false;
2033
2034 // Store the new value.
2035 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
2036 return true;
2037}
2038
2039static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2040 const Pointer &Ptr = S.Stk.pop<Pointer>();
2041
2042 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
2043 return false;
2044
2045 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2046}
2047
2048static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2049 const Pointer &Ptr = S.Stk.pop<Pointer>();
2050
2051 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
2052 return false;
2053
2054 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2055}
2056
2057/// 1) Pops a Pointer from the stack.
2058/// 2) Pops another Pointer from the stack.
2059/// 3) Pushes the different of the indices of the two pointers on the stack.
2060template <PrimType Name, class T = typename PrimConv<Name>::T>
2061inline bool SubPtr(InterpState &S, CodePtr OpPC) {
2062 const Pointer &LHS = S.Stk.pop<Pointer>();
2063 const Pointer &RHS = S.Stk.pop<Pointer>();
2064
2065 for (const Pointer &P : {LHS, RHS}) {
2066 if (P.isZeroSizeArray()) {
2067 QualType PtrT = P.getType();
2068 while (auto *AT = dyn_cast<ArrayType>(PtrT))
2069 PtrT = AT->getElementType();
2070
2072 PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2073 S.FFDiag(S.Current->getSource(OpPC),
2074 diag::note_constexpr_pointer_subtraction_zero_size)
2075 << ArrayTy;
2076
2077 return false;
2078 }
2079 }
2080
2081 if (RHS.isZero()) {
2082 S.Stk.push<T>(T::from(LHS.getIndex()));
2083 return true;
2084 }
2085
2086 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2087 // TODO: Diagnose.
2088 return false;
2089 }
2090
2091 if (LHS.isZero() && RHS.isZero()) {
2092 S.Stk.push<T>();
2093 return true;
2094 }
2095
2096 T A = LHS.isBlockPointer()
2097 ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
2098 : T::from(LHS.getIndex()))
2099 : T::from(LHS.getIntegerRepresentation());
2100 T B = RHS.isBlockPointer()
2101 ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2102 : T::from(RHS.getIndex()))
2103 : T::from(RHS.getIntegerRepresentation());
2104
2105 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2106}
2107
2108//===----------------------------------------------------------------------===//
2109// Destroy
2110//===----------------------------------------------------------------------===//
2111
2112inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2113 S.Current->destroy(I);
2114 return true;
2115}
2116
2117inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2118 S.Current->initScope(I);
2119 return true;
2120}
2121
2122//===----------------------------------------------------------------------===//
2123// Cast, CastFP
2124//===----------------------------------------------------------------------===//
2125
2126template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2127 using T = typename PrimConv<TIn>::T;
2128 using U = typename PrimConv<TOut>::T;
2129 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2130 return true;
2131}
2132
2133/// 1) Pops a Floating from the stack.
2134/// 2) Pushes a new floating on the stack that uses the given semantics.
2135inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2136 llvm::RoundingMode RM) {
2137 Floating F = S.Stk.pop<Floating>();
2138 Floating Result = F.toSemantics(Sem, RM);
2139 S.Stk.push<Floating>(Result);
2140 return true;
2141}
2142
2143inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2144 FixedPointSemantics TargetSemantics(0, 0, false, false, false);
2145 std::memcpy(&TargetSemantics, &FPS, sizeof(TargetSemantics));
2146
2147 const auto &Source = S.Stk.pop<FixedPoint>();
2148
2149 bool Overflow;
2150 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2151
2152 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2153 return false;
2154
2155 S.Stk.push<FixedPoint>(Result);
2156 return true;
2157}
2158
2159/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2160/// to know what bitwidth the result should be.
2161template <PrimType Name, class T = typename PrimConv<Name>::T>
2162bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2163 S.Stk.push<IntegralAP<false>>(
2164 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2165 return true;
2166}
2167
2168template <PrimType Name, class T = typename PrimConv<Name>::T>
2169bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2170 S.Stk.push<IntegralAP<true>>(
2171 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2172 return true;
2173}
2174
2175template <PrimType Name, class T = typename PrimConv<Name>::T>
2177 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2178 const T &From = S.Stk.pop<T>();
2179 APSInt FromAP = From.toAPSInt();
2181
2183 auto Status =
2184 Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
2185 S.Stk.push<Floating>(Result);
2186
2187 return CheckFloatResult(S, OpPC, Result, Status, FPO);
2188}
2189
2190template <PrimType Name, class T = typename PrimConv<Name>::T>
2191bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2192 const Floating &F = S.Stk.pop<Floating>();
2193
2194 if constexpr (std::is_same_v<T, Boolean>) {
2195 S.Stk.push<T>(T(F.isNonZero()));
2196 return true;
2197 } else {
2198 APSInt Result(std::max(8u, T::bitWidth()),
2199 /*IsUnsigned=*/!T::isSigned());
2200 auto Status = F.convertToInteger(Result);
2201
2202 // Float-to-Integral overflow check.
2203 if ((Status & APFloat::opStatus::opInvalidOp)) {
2204 const Expr *E = S.Current->getExpr(OpPC);
2205 QualType Type = E->getType();
2206
2207 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2208 if (S.noteUndefinedBehavior()) {
2209 S.Stk.push<T>(T(Result));
2210 return true;
2211 }
2212 return false;
2213 }
2214
2216 S.Stk.push<T>(T(Result));
2217 return CheckFloatResult(S, OpPC, F, Status, FPO);
2218 }
2219}
2220
2221static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2222 uint32_t BitWidth, uint32_t FPOI) {
2223 const Floating &F = S.Stk.pop<Floating>();
2224
2225 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2226 auto Status = F.convertToInteger(Result);
2227
2228 // Float-to-Integral overflow check.
2229 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2230 return handleOverflow(S, OpPC, F.getAPFloat());
2231
2234 return CheckFloatResult(S, OpPC, F, Status, FPO);
2235}
2236
2237static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2238 uint32_t BitWidth, uint32_t FPOI) {
2239 const Floating &F = S.Stk.pop<Floating>();
2240
2241 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2242 auto Status = F.convertToInteger(Result);
2243
2244 // Float-to-Integral overflow check.
2245 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2246 return handleOverflow(S, OpPC, F.getAPFloat());
2247
2250 return CheckFloatResult(S, OpPC, F, Status, FPO);
2251}
2252
2253bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2254 const Pointer &Ptr, unsigned BitWidth);
2255bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2256bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2257
2258template <PrimType Name, class T = typename PrimConv<Name>::T>
2260 const Pointer &Ptr = S.Stk.pop<Pointer>();
2261
2262 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2263 return false;
2264
2265 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2266 return true;
2267}
2268
2269template <PrimType Name, class T = typename PrimConv<Name>::T>
2270static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2271 uint32_t FPS) {
2272 const T &Int = S.Stk.pop<T>();
2273
2274 FixedPointSemantics Sem(0, 0, false, false, false);
2275 std::memcpy(&Sem, &FPS, sizeof(Sem));
2276
2277 bool Overflow;
2278 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2279
2280 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2281 return false;
2282
2283 S.Stk.push<FixedPoint>(Result);
2284 return true;
2285}
2286
2287static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2288 uint32_t FPS) {
2289 const auto &Float = S.Stk.pop<Floating>();
2290
2291 FixedPointSemantics Sem(0, 0, false, false, false);
2292 std::memcpy(&Sem, &FPS, sizeof(Sem));
2293
2294 bool Overflow;
2295 FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
2296
2297 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2298 return false;
2299
2300 S.Stk.push<FixedPoint>(Result);
2301 return true;
2302}
2303
2304static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2305 const llvm::fltSemantics *Sem) {
2306 const auto &Fixed = S.Stk.pop<FixedPoint>();
2307
2308 S.Stk.push<Floating>(Fixed.toFloat(Sem));
2309 return true;
2310}
2311
2312template <PrimType Name, class T = typename PrimConv<Name>::T>
2313static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2314 const auto &Fixed = S.Stk.pop<FixedPoint>();
2315
2316 bool Overflow;
2317 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2318
2319 if (Overflow && !handleOverflow(S, OpPC, Int))
2320 return false;
2321
2322 S.Stk.push<T>(Int);
2323 return true;
2324}
2325
2326static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2327 const auto &Ptr = S.Stk.peek<Pointer>();
2328
2329 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2330 bool HasValidResult = !Ptr.isZero();
2331
2332 if (HasValidResult) {
2333 // FIXME: note_constexpr_invalid_void_star_cast
2334 } else if (!S.getLangOpts().CPlusPlus26) {
2335 const SourceInfo &E = S.Current->getSource(OpPC);
2336 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2337 << 3 << "'void *'" << S.Current->getRange(OpPC);
2338 }
2339 } else {
2340 const SourceInfo &E = S.Current->getSource(OpPC);
2341 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2342 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2343 }
2344
2345 return true;
2346}
2347
2348//===----------------------------------------------------------------------===//
2349// Zero, Nullptr
2350//===----------------------------------------------------------------------===//
2351
2352template <PrimType Name, class T = typename PrimConv<Name>::T>
2353bool Zero(InterpState &S, CodePtr OpPC) {
2354 S.Stk.push<T>(T::zero());
2355 return true;
2356}
2357
2358static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2359 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2360 return true;
2361}
2362
2363static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2364 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2365 return true;
2366}
2367
2368template <PrimType Name, class T = typename PrimConv<Name>::T>
2369inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2370 const Descriptor *Desc) {
2371 // FIXME(perf): This is a somewhat often-used function and the value of a
2372 // null pointer is almost always 0.
2373 S.Stk.push<T>(Value, Desc);
2374 return true;
2375}
2376
2377template <PrimType Name, class T = typename PrimConv<Name>::T>
2378inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2379 const auto &P = S.Stk.pop<T>();
2380 if (P.isWeak())
2381 return false;
2382 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2383 return true;
2384}
2385
2386//===----------------------------------------------------------------------===//
2387// This, ImplicitThis
2388//===----------------------------------------------------------------------===//
2389
2390inline bool This(InterpState &S, CodePtr OpPC) {
2391 // Cannot read 'this' in this mode.
2392 if (S.checkingPotentialConstantExpression()) {
2393 return false;
2394 }
2395
2396 const Pointer &This = S.Current->getThis();
2397 if (!CheckThis(S, OpPC, This))
2398 return false;
2399
2400 // Ensure the This pointer has been cast to the correct base.
2401 if (!This.isDummy()) {
2402 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2403 assert(This.getRecord());
2404 assert(
2405 This.getRecord()->getDecl() ==
2406 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2407 }
2408
2409 S.Stk.push<Pointer>(This);
2410 return true;
2411}
2412
2413inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2414 assert(S.Current->getFunction()->hasRVO());
2415 if (S.checkingPotentialConstantExpression())
2416 return false;
2417 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2418 return true;
2419}
2420
2421//===----------------------------------------------------------------------===//
2422// Shr, Shl
2423//===----------------------------------------------------------------------===//
2424
2425template <class LT, class RT, ShiftDir Dir>
2426inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2427 const unsigned Bits = LHS.bitWidth();
2428
2429 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2430 if (S.getLangOpts().OpenCL)
2431 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2432 RHS.bitWidth(), &RHS);
2433
2434 if (RHS.isNegative()) {
2435 // During constant-folding, a negative shift is an opposite shift. Such a
2436 // shift is not a constant expression.
2437 const SourceInfo &Loc = S.Current->getSource(OpPC);
2438 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2439 if (!S.noteUndefinedBehavior())
2440 return false;
2441 RHS = -RHS;
2442 return DoShift<LT, RT,
2444 S, OpPC, LHS, RHS);
2445 }
2446
2447 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2448 return false;
2449
2450 // Limit the shift amount to Bits - 1. If this happened,
2451 // it has already been diagnosed by CheckShift() above,
2452 // but we still need to handle it.
2453 // Note that we have to be extra careful here since we're doing the shift in
2454 // any case, but we need to adjust the shift amount or the way we do the shift
2455 // for the potential error cases.
2456 typename LT::AsUnsigned R;
2457 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2458 if constexpr (Dir == ShiftDir::Left) {
2459 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2461 if (LHS.isNegative())
2462 R = LT::AsUnsigned::zero(LHS.bitWidth());
2463 else {
2464 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2465 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2466 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2467 }
2468 } else if (LHS.isNegative()) {
2469 if (LHS.isMin()) {
2470 R = LT::AsUnsigned::zero(LHS.bitWidth());
2471 } else {
2472 // If the LHS is negative, perform the cast and invert the result.
2473 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2474 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2475 &R);
2476 R = -R;
2477 }
2478 } else {
2479 // The good case, a simple left shift.
2480 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2481 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2482 }
2483 } else {
2484 // Right shift.
2485 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2487 R = LT::AsUnsigned::from(-1);
2488 } else {
2489 // Do the shift on potentially signed LT, then convert to unsigned type.
2490 LT A;
2491 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2492 R = LT::AsUnsigned::from(A);
2493 }
2494 }
2495
2496 S.Stk.push<LT>(LT::from(R));
2497 return true;
2498}
2499
2500template <PrimType NameL, PrimType NameR>
2501inline bool Shr(InterpState &S, CodePtr OpPC) {
2502 using LT = typename PrimConv<NameL>::T;
2503 using RT = typename PrimConv<NameR>::T;
2504 auto RHS = S.Stk.pop<RT>();
2505 auto LHS = S.Stk.pop<LT>();
2506
2507 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2508}
2509
2510template <PrimType NameL, PrimType NameR>
2511inline bool Shl(InterpState &S, CodePtr OpPC) {
2512 using LT = typename PrimConv<NameL>::T;
2513 using RT = typename PrimConv<NameR>::T;
2514 auto RHS = S.Stk.pop<RT>();
2515 auto LHS = S.Stk.pop<LT>();
2516
2517 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2518}
2519
2520static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
2521 const auto &RHS = S.Stk.pop<FixedPoint>();
2522 const auto &LHS = S.Stk.pop<FixedPoint>();
2523 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
2524
2525 unsigned ShiftBitWidth =
2526 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
2527
2528 // Embedded-C 4.1.6.2.2:
2529 // The right operand must be nonnegative and less than the total number
2530 // of (nonpadding) bits of the fixed-point operand ...
2531 if (RHS.isNegative()) {
2532 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2533 << RHS.toAPSInt();
2534 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2535 ShiftBitWidth)) != RHS.toAPSInt()) {
2536 const Expr *E = S.Current->getExpr(OpPC);
2537 S.CCEDiag(E, diag::note_constexpr_large_shift)
2538 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
2539 }
2540
2542 if (Left) {
2543 if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
2545 return false;
2546 } else {
2547 if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
2549 return false;
2550 }
2551
2552 S.Stk.push<FixedPoint>(Result);
2553 return true;
2554}
2555
2556//===----------------------------------------------------------------------===//
2557// NoRet
2558//===----------------------------------------------------------------------===//
2559
2560inline bool NoRet(InterpState &S, CodePtr OpPC) {
2561 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2562 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2563 return false;
2564}
2565
2566//===----------------------------------------------------------------------===//
2567// NarrowPtr, ExpandPtr
2568//===----------------------------------------------------------------------===//
2569
2570inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2571 const Pointer &Ptr = S.Stk.pop<Pointer>();
2572 S.Stk.push<Pointer>(Ptr.narrow());
2573 return true;
2574}
2575
2576inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2577 const Pointer &Ptr = S.Stk.pop<Pointer>();
2578 S.Stk.push<Pointer>(Ptr.expand());
2579 return true;
2580}
2581
2582// 1) Pops an integral value from the stack
2583// 2) Peeks a pointer
2584// 3) Pushes a new pointer that's a narrowed array
2585// element of the peeked pointer with the value
2586// from 1) added as offset.
2587//
2588// This leaves the original pointer on the stack and pushes a new one
2589// with the offset applied and narrowed.
2590template <PrimType Name, class T = typename PrimConv<Name>::T>
2591inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2592 const T &Offset = S.Stk.pop<T>();
2593 const Pointer &Ptr = S.Stk.peek<Pointer>();
2594
2595 if (!Ptr.isZero() && !Offset.isZero()) {
2596 if (!CheckArray(S, OpPC, Ptr))
2597 return false;
2598 }
2599
2600 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2601 return false;
2602
2603 return NarrowPtr(S, OpPC);
2604}
2605
2606template <PrimType Name, class T = typename PrimConv<Name>::T>
2607inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2608 const T &Offset = S.Stk.pop<T>();
2609 const Pointer &Ptr = S.Stk.pop<Pointer>();
2610
2611 if (!Ptr.isZero() && !Offset.isZero()) {
2612 if (!CheckArray(S, OpPC, Ptr))
2613 return false;
2614 }
2615
2616 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2617 return false;
2618
2619 return NarrowPtr(S, OpPC);
2620}
2621
2622template <PrimType Name, class T = typename PrimConv<Name>::T>
2623inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2624 const Pointer &Ptr = S.Stk.peek<Pointer>();
2625
2626 if (!CheckLoad(S, OpPC, Ptr))
2627 return false;
2628
2629 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2630 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2631 return true;
2632}
2633
2634template <PrimType Name, class T = typename PrimConv<Name>::T>
2635inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2636 const Pointer &Ptr = S.Stk.pop<Pointer>();
2637
2638 if (!CheckLoad(S, OpPC, Ptr))
2639 return false;
2640
2641 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2642 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2643 return true;
2644}
2645
2646template <PrimType Name, class T = typename PrimConv<Name>::T>
2647inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2648 uint32_t DestIndex, uint32_t Size) {
2649 const auto &SrcPtr = S.Stk.pop<Pointer>();
2650 const auto &DestPtr = S.Stk.peek<Pointer>();
2651
2652 for (uint32_t I = 0; I != Size; ++I) {
2653 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2654
2655 if (!CheckLoad(S, OpPC, SP))
2656 return false;
2657
2658 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2659 DP.deref<T>() = SP.deref<T>();
2660 DP.initialize();
2661 }
2662 return true;
2663}
2664
2665/// Just takes a pointer and checks if it's an incomplete
2666/// array type.
2667inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2668 const Pointer &Ptr = S.Stk.pop<Pointer>();
2669
2670 if (Ptr.isZero()) {
2671 S.Stk.push<Pointer>(Ptr);
2672 return true;
2673 }
2674
2675 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2676 return false;
2677
2678 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
2679 S.Stk.push<Pointer>(Ptr.atIndex(0));
2680 return true;
2681 }
2682
2683 const SourceInfo &E = S.Current->getSource(OpPC);
2684 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2685
2686 return false;
2687}
2688
2689inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2690 assert(Func);
2691 S.Stk.push<FunctionPointer>(Func);
2692 return true;
2693}
2694
2695template <PrimType Name, class T = typename PrimConv<Name>::T>
2696inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2697 const T &IntVal = S.Stk.pop<T>();
2698
2699 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2700 return true;
2701}
2702
2703inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
2704 S.Stk.push<MemberPointer>(D);
2705 return true;
2706}
2707
2708inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2709 const auto &MP = S.Stk.pop<MemberPointer>();
2710
2711 S.Stk.push<Pointer>(MP.getBase());
2712 return true;
2713}
2714
2715inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2716 const auto &MP = S.Stk.pop<MemberPointer>();
2717
2718 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2719 const auto *Func = S.getContext().getOrCreateFunction(FD);
2720
2721 S.Stk.push<FunctionPointer>(Func);
2722 return true;
2723}
2724
2725/// Just emit a diagnostic. The expression that caused emission of this
2726/// op is not valid in a constant context.
2727inline bool Invalid(InterpState &S, CodePtr OpPC) {
2728 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2729 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2730 << S.Current->getRange(OpPC);
2731 return false;
2732}
2733
2734inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2735 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2736 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2737 << S.Current->getRange(OpPC);
2738 return false;
2739}
2740
2741/// Do nothing and just abort execution.
2742inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2743inline bool SideEffect(InterpState &S, CodePtr OpPC) {
2744 return S.noteSideEffect();
2745}
2746
2747/// Same here, but only for casts.
2748inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2749 bool Fatal) {
2750 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2751
2752 // FIXME: Support diagnosing other invalid cast kinds.
2753 if (Kind == CastKind::Reinterpret) {
2754 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2755 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2756 return !Fatal;
2757 }
2758 return false;
2759}
2760
2761inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
2762 bool InitializerFailed) {
2763 assert(DR);
2764
2765 if (InitializerFailed) {
2766 const SourceInfo &Loc = S.Current->getSource(OpPC);
2767 const auto *VD = cast<VarDecl>(DR->getDecl());
2768 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2769 S.Note(VD->getLocation(), diag::note_declared_at);
2770 return false;
2771 }
2772
2773 return CheckDeclRef(S, OpPC, DR);
2774}
2775
2777 if (S.inConstantContext()) {
2778 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2779 const Expr *E = S.Current->getExpr(OpPC);
2780 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2781 }
2782 return false;
2783}
2784
2785inline bool Assume(InterpState &S, CodePtr OpPC) {
2786 const auto Val = S.Stk.pop<Boolean>();
2787
2788 if (Val)
2789 return true;
2790
2791 // Else, diagnose.
2792 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2793 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2794 return false;
2795}
2796
2797template <PrimType Name, class T = typename PrimConv<Name>::T>
2798inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2799 llvm::SmallVector<int64_t> ArrayIndices;
2800 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2801 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2802
2803 int64_t Result;
2804 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2805 return false;
2806
2807 S.Stk.push<T>(T::from(Result));
2808
2809 return true;
2810}
2811
2812template <PrimType Name, class T = typename PrimConv<Name>::T>
2813inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2814 const T &Arg = S.Stk.peek<T>();
2815 if (!Arg.isZero())
2816 return true;
2817
2818 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2819 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2820
2821 return false;
2822}
2823
2824void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2825 const APSInt &Value);
2826
2827template <PrimType Name, class T = typename PrimConv<Name>::T>
2828inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2829 assert(ED);
2830 assert(!ED->isFixed());
2831 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2832
2833 if (S.inConstantContext())
2834 diagnoseEnumValue(S, OpPC, ED, Val);
2835 return true;
2836}
2837
2838/// OldPtr -> Integer -> NewPtr.
2839template <PrimType TIn, PrimType TOut>
2840inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2841 static_assert(isPtrType(TIn) && isPtrType(TOut));
2842 using FromT = typename PrimConv<TIn>::T;
2843 using ToT = typename PrimConv<TOut>::T;
2844
2845 const FromT &OldPtr = S.Stk.pop<FromT>();
2846
2847 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2848 std::is_same_v<ToT, Pointer>) {
2849 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2850 return true;
2851 } else if constexpr (std::is_same_v<FromT, Pointer> &&
2852 std::is_same_v<ToT, FunctionPointer>) {
2853 if (OldPtr.isFunctionPointer()) {
2854 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2855 OldPtr.getByteOffset());
2856 return true;
2857 }
2858 }
2859
2860 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2861 return true;
2862}
2863
2864inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2865 // An expression E is a core constant expression unless the evaluation of E
2866 // would evaluate one of the following: [C++23] - a control flow that passes
2867 // through a declaration of a variable with static or thread storage duration
2868 // unless that variable is usable in constant expressions.
2869 assert(VD->isLocalVarDecl() &&
2870 VD->isStaticLocal()); // Checked before emitting this.
2871
2872 if (VD == S.EvaluatingDecl)
2873 return true;
2874
2876 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2877 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2878 return false;
2879 }
2880 return true;
2881}
2882
2883inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2884 assert(Desc);
2885
2886 if (!CheckDynamicMemoryAllocation(S, OpPC))
2887 return false;
2888
2889 DynamicAllocator &Allocator = S.getAllocator();
2890 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2892 assert(B);
2893
2894 S.Stk.push<Pointer>(B);
2895
2896 return true;
2897}
2898
2899template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2900inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2901 bool IsNoThrow) {
2902 if (!CheckDynamicMemoryAllocation(S, OpPC))
2903 return false;
2904
2905 SizeT NumElements = S.Stk.pop<SizeT>();
2906 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2907 if (!IsNoThrow)
2908 return false;
2909
2910 // If this failed and is nothrow, just return a null ptr.
2911 S.Stk.push<Pointer>(0, nullptr);
2912 return true;
2913 }
2914
2915 DynamicAllocator &Allocator = S.getAllocator();
2916 Block *B =
2917 Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2918 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2919 assert(B);
2920 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2921
2922 return true;
2923}
2924
2925template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2926inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2927 bool IsNoThrow) {
2928 if (!CheckDynamicMemoryAllocation(S, OpPC))
2929 return false;
2930
2931 SizeT NumElements = S.Stk.pop<SizeT>();
2932 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2933 IsNoThrow)) {
2934 if (!IsNoThrow)
2935 return false;
2936
2937 // If this failed and is nothrow, just return a null ptr.
2938 S.Stk.push<Pointer>(0, ElementDesc);
2939 return true;
2940 }
2941
2942 DynamicAllocator &Allocator = S.getAllocator();
2943 Block *B =
2944 Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2945 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2946 assert(B);
2947
2948 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2949
2950 return true;
2951}
2952
2953bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
2954 bool IsGlobalDelete);
2955
2956static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
2957 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
2958 return true;
2959}
2960
2961static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
2962 return S.maybeDiagnoseDanglingAllocations();
2963}
2964
2965/// Check if the initializer and storage types of a placement-new expression
2966/// match.
2967bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
2968 std::optional<uint64_t> ArraySize = std::nullopt);
2969
2970template <PrimType Name, class T = typename PrimConv<Name>::T>
2972 const auto &Size = S.Stk.pop<T>();
2973 return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
2974}
2975bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
2976
2977template <PrimType Name, class T = typename PrimConv<Name>::T>
2978inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
2979 uint32_t ResultBitWidth,
2980 const llvm::fltSemantics *Sem) {
2981 const Pointer &FromPtr = S.Stk.pop<Pointer>();
2982
2983 if (!CheckLoad(S, OpPC, FromPtr))
2984 return false;
2985
2986 if constexpr (std::is_same_v<T, Pointer>) {
2987 // The only pointer type we can validly bitcast to is nullptr_t.
2988 S.Stk.push<Pointer>();
2989 return true;
2990 } else {
2991
2992 size_t BuffSize = ResultBitWidth / 8;
2993 llvm::SmallVector<std::byte> Buff(BuffSize);
2994 bool HasIndeterminateBits = false;
2995
2996 Bits FullBitWidth(ResultBitWidth);
2997 Bits BitWidth = FullBitWidth;
2998
2999 if constexpr (std::is_same_v<T, Floating>) {
3000 assert(Sem);
3001 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3002 }
3003
3004 if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3005 HasIndeterminateBits))
3006 return false;
3007
3008 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3009 return false;
3010
3011 if constexpr (std::is_same_v<T, Floating>) {
3012 assert(Sem);
3013 S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3014 } else {
3015 assert(!Sem);
3016 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3017 }
3018 return true;
3019 }
3020}
3021
3022inline bool BitCast(InterpState &S, CodePtr OpPC) {
3023 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3024 Pointer &ToPtr = S.Stk.peek<Pointer>();
3025
3026 if (!CheckLoad(S, OpPC, FromPtr))
3027 return false;
3028
3029 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3030 return false;
3031
3032 return true;
3033}
3034
3035/// Typeid support.
3036bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3037 const Type *TypeInfoType);
3038bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3039bool DiagTypeid(InterpState &S, CodePtr OpPC);
3040
3041//===----------------------------------------------------------------------===//
3042// Read opcode arguments
3043//===----------------------------------------------------------------------===//
3044
3045template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3046 if constexpr (std::is_pointer<T>::value) {
3047 uint32_t ID = OpPC.read<uint32_t>();
3048 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3049 } else {
3050 return OpPC.read<T>();
3051 }
3052}
3053
3054template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3056 OpPC += align(F.bytesToSerialize());
3057 return F;
3058}
3059
3060template <>
3061inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3062 CodePtr &OpPC) {
3063 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3064 OpPC += align(I.bytesToSerialize());
3065 return I;
3066}
3067
3068template <>
3069inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3070 CodePtr &OpPC) {
3071 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3072 OpPC += align(I.bytesToSerialize());
3073 return I;
3074}
3075
3076} // namespace interp
3077} // namespace clang
3078
3079#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3453
ASTImporterLookupTable & LT
StringRef P
const Decl * D
Expr * E
llvm::APSInt APSInt
Definition: Compiler.cpp:23
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)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
SourceLocation Loc
Definition: SemaObjC.cpp:759
#define bool
Definition: amdgpuintrin.h:20
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
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.
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2078
bool isVirtual() const
Definition: DeclCXX.h:2133
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2874
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:245
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
ValueDecl * getDecl()
Definition: Expr.h:1333
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
SourceLocation getLocation() const
Definition: DeclBase.h:442
Represents an enum.
Definition: Decl.h:3861
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
Definition: Decl.h:4075
This represents one expression.
Definition: Expr.h:110
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:276
QualType getType() const
Definition: Expr.h:142
static FPOptions getFromOpaqueInt(storage_type Value)
Definition: LangOptions.h:942
RoundingMode getRoundingMode() const
Definition: LangOptions.h:912
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3252
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3170
Expr * getTemporaryExpr()
Retrieve the expression to which the temporary materialization conversion was applied.
Definition: DeclCXX.h:3298
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2519
A (possibly-)qualified type.
Definition: Type.h:929
Represents a struct/union/class.
Definition: Decl.h:4162
ASTContext & getASTContext() const
Definition: Sema.h:532
const LangOptions & getLangOpts() const
Definition: Sema.h:525
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:333
The base class of the type hierarchy.
Definition: Type.h:1828
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:671
Represents a variable declaration or definition.
Definition: Decl.h:882
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition: Decl.h:1159
ThreadStorageClassSpecifier getTSCSpec() const
Definition: Decl.h:1128
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition: Decl.h:1204
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:2500
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
Wrapper around boolean types.
Definition: Boolean.h:25
static Boolean from(T Value)
Definition: Boolean.h:103
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:60
Manages dynamic memory allocations done during bytecode interpretation.
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:132
static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
Definition: FixedPoint.h:125
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
Definition: FixedPoint.h:40
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:205
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:158
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:186
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:179
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:119
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
size_t bytesToSerialize() const
Definition: Floating.h:144
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:173
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:199
bool isNonZero() const
Definition: Floating.h:92
bool isFinite() const
Definition: Floating.h:98
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:192
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition: Floating.h:50
const Function * getFunction() const
ComparisonCategoryResult compare(const FunctionPointer &RHS) const
std::string toDiagnosticString(const ASTContext &Ctx) const
Bytecode function.
Definition: Function.h:81
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:300
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:118
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
Wrapper around numeric types.
Definition: Integral.h:66
Frame storing local variables.
Definition: InterpFrame.h:26
Interpreter context.
Definition: InterpState.h:36
ComparisonCategoryResult compare(const MemberPointer &RHS) const
A pointer to a memory block, live or dead.
Definition: Pointer.h:88
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:459
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:195
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:455
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:335
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:161
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:560
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:188
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:501
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:605
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:180
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:658
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:596
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:432
void activate() const
Activats a field.
Definition: Pointer.cpp:419
bool isIntegralPointer() const
Definition: Pointer.h:483
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:409
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:414
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:587
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:325
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:271
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:692
const IntPointer & asIntPointer() const
Definition: Pointer.h:473
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:454
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:296
unsigned getOffset() const
Returns the offset into an array.
Definition: Pointer.h:391
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:623
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:148
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:237
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:646
bool isBlockPointer() const
Definition: Pointer.h:482
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:477
bool isFunctionPointer() const
Definition: Pointer.h:484
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:341
size_t elemSize() const
Returns the element size of the innermost field.
Definition: Pointer.h:373
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:462
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:469
void initialize() const
Initializes a field.
Definition: Pointer.cpp:371
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:77
static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)
Definition: Interp.h:2520
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.cpp:1199
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1787
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2501
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:1407
llvm::APFloat APFloat
Definition: Floating.h:23
bool IncPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
Definition: Interp.h:836
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2635
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1598
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1617
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2623
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1179
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1606
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:671
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition: Interp.h:2221
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2708
bool DecPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition: Interp.h:861
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1334
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2570
llvm::APInt APInt
Definition: FixedPoint.h:19
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
Definition: Interp.h:1618
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1448
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3054
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:890
bool SideEffect(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2743
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2363
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1271
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
Definition: Interp.cpp:1651
bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:454
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1827
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1743
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:446
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:844
bool BitCast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:3022
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1704
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
Definition: Interp.h:2369
static llvm::RoundingMode getRoundingMode(FPOptions FPO)
Definition: Interp.h:409
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2039
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:896
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
Definition: Interp.cpp:1645
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1212
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:750
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:761
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1302
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2813
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
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}_ordering type.
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:2015
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1507
bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:416
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)
Checks if Div/Rem operation on LHS and RHS is valid.
Definition: Interp.h:222
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition: Interp.cpp:340
bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)
Definition: Interp.h:2864
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition: Interp.cpp:1588
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:363
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
Definition: Interp.cpp:1194
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:674
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:494
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2689
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1381
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1553
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:2061
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:435
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1520
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
Definition: Interp.cpp:1567
bool Mulc(InterpState &S, CodePtr OpPC)
Definition: Interp.h:466
bool RetVoid(InterpState &S, CodePtr &PC)
Definition: Interp.h:340
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2591
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1157
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2560
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2696
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:589
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2358
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)
Definition: Interp.h:2978
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2511
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2413
llvm::FixedPointSemantics FixedPointSemantics
Definition: Interp.h:43
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:533
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2259
constexpr bool isPtrType(PrimType T)
Definition: PrimType.h:53
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr, bool IsPointerArith=false)
Definition: Interp.h:1882
bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:914
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2007
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:131
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:637
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:415
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2169
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2576
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:779
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1715
bool Divc(InterpState &S, CodePtr OpPC)
Definition: Interp.h:521
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:1288
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2607
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2390
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2117
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition: Interp.cpp:835
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:1483
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:955
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:940
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3045
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:306
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:2191
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2667
bool DiagTypeid(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:1672
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition: Interp.cpp:618
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:1429
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:767
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
Definition: Interp.cpp:1628
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1253
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2798
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:603
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:176
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
Definition: Interp.h:164
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2287
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition: Interp.cpp:1101
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1171
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:34
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.h:2971
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2353
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1464
bool Unsupported(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2734
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
Definition: Interp.h:2761
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:643
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:404
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:872
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:788
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:2135
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1348
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1758
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1223
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2048
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2961
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2883
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.cpp:1580
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1859
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2270
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:654
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1657
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:1477
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
Definition: Interp.h:2703
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1652
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2776
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition: Interp.h:2326
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.cpp:1126
bool IsNonNull(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2378
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1530
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1540
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:298
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:559
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1566
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
Definition: Interp.cpp:922
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1579
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1280
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:901
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2715
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:961
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:925
static bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem)
Definition: Interp.h:2304
bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:697
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition: Interp.h:2840
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1668
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1729
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.cpp:230
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:1265
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1643
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition: Interp.h:2237
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:447
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
Definition: Interp.h:2426
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:1802
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2112
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1218
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:1493
bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID)
Definition: Interp.cpp:1408
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition: Interp.cpp:1008
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.cpp:1530
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1634
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1198
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:974
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:726
llvm::APSInt APSInt
Definition: FixedPoint.h:20
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:283
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:620
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:715
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1693
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1390
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2126
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1126
bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:898
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:1320
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1084
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:679
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1997
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:1243
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool Memcpy(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1849
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1186
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, unsigned ElemSize, bool IsNoThrow)
Definition: Interp.h:251
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.cpp:1434
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1014
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2313
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:74
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1334
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
Definition: Interp.h:2176
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:943
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:466
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2143
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1512
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
Definition: Interp.h:2926
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1363
bool Interpret(InterpState &S)
Interpreter entry point.
Definition: Interp.cpp:1684
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:435
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1677
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1396
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Same here, but only for casts.
Definition: Interp.h:2748
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1867
bool Ret(InterpState &S, CodePtr &PC)
Definition: Interp.h:318
bool Flip(InterpState &S, CodePtr OpPC)
[Value1, Value2] -> [Value2, Value1]
Definition: Interp.h:1225
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:1133
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:2162
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:994
bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:906
bool Assume(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2785
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:659
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1624
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)
Definition: Interp.h:870
static bool IsConstantContext(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2956
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition: Interp.h:2900
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition: Interp.h:2828
The JSON file list parser is used to communicate input to InstallAPI.
@ 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:41
@ CSK_ArrayToPointer
Definition: State.h:45
@ CSK_Derived
Definition: State.h:43
@ CSK_Base
Definition: State.h:42
@ CSK_ArrayIndex
Definition: State.h:46
@ CSK_Field
Definition: State.h:44
@ Result
The result type of a method or function.
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_Decrement
Definition: State.h:31
const FunctionProtoType * T
A quantity in bits.
Definition: BitcastBuffer.h:24
unsigned Base
Start of the current subfield.
Definition: Pointer.h:41
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:39
Describes a memory block created by an allocation site.
Definition: Descriptor.h:116
unsigned getSize() const
Returns the size of the object without metadata.
Definition: Descriptor.h:225
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition: Descriptor.h:141
PrimType getPrimType() const
Definition: Descriptor.h:230
const Expr * asExpr() const
Definition: Descriptor.h:205
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:70
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
Definition: Pointer.cpp:697
const Descriptor * Desc
Definition: Pointer.h:45
Mapping from primitive types to their representation.
Definition: PrimType.h:77