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 =
2145 FixedPointSemantics::getFromOpaqueInt(FPS);
2146 const auto &Source = S.Stk.pop<FixedPoint>();
2147
2148 bool Overflow;
2149 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2150
2151 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2152 return false;
2153
2154 S.Stk.push<FixedPoint>(Result);
2155 return true;
2156}
2157
2158/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2159/// to know what bitwidth the result should be.
2160template <PrimType Name, class T = typename PrimConv<Name>::T>
2161bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2162 S.Stk.push<IntegralAP<false>>(
2163 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2164 return true;
2165}
2166
2167template <PrimType Name, class T = typename PrimConv<Name>::T>
2168bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2169 S.Stk.push<IntegralAP<true>>(
2170 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2171 return true;
2172}
2173
2174template <PrimType Name, class T = typename PrimConv<Name>::T>
2176 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2177 const T &From = S.Stk.pop<T>();
2178 APSInt FromAP = From.toAPSInt();
2180
2182 auto Status =
2183 Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
2184 S.Stk.push<Floating>(Result);
2185
2186 return CheckFloatResult(S, OpPC, Result, Status, FPO);
2187}
2188
2189template <PrimType Name, class T = typename PrimConv<Name>::T>
2190bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2191 const Floating &F = S.Stk.pop<Floating>();
2192
2193 if constexpr (std::is_same_v<T, Boolean>) {
2194 S.Stk.push<T>(T(F.isNonZero()));
2195 return true;
2196 } else {
2197 APSInt Result(std::max(8u, T::bitWidth()),
2198 /*IsUnsigned=*/!T::isSigned());
2199 auto Status = F.convertToInteger(Result);
2200
2201 // Float-to-Integral overflow check.
2202 if ((Status & APFloat::opStatus::opInvalidOp)) {
2203 const Expr *E = S.Current->getExpr(OpPC);
2204 QualType Type = E->getType();
2205
2206 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2207 if (S.noteUndefinedBehavior()) {
2208 S.Stk.push<T>(T(Result));
2209 return true;
2210 }
2211 return false;
2212 }
2213
2215 S.Stk.push<T>(T(Result));
2216 return CheckFloatResult(S, OpPC, F, Status, FPO);
2217 }
2218}
2219
2220static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2221 uint32_t BitWidth, uint32_t FPOI) {
2222 const Floating &F = S.Stk.pop<Floating>();
2223
2224 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2225 auto Status = F.convertToInteger(Result);
2226
2227 // Float-to-Integral overflow check.
2228 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2229 return handleOverflow(S, OpPC, F.getAPFloat());
2230
2233 return CheckFloatResult(S, OpPC, F, Status, FPO);
2234}
2235
2236static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2237 uint32_t BitWidth, uint32_t FPOI) {
2238 const Floating &F = S.Stk.pop<Floating>();
2239
2240 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2241 auto Status = F.convertToInteger(Result);
2242
2243 // Float-to-Integral overflow check.
2244 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2245 return handleOverflow(S, OpPC, F.getAPFloat());
2246
2249 return CheckFloatResult(S, OpPC, F, Status, FPO);
2250}
2251
2252bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2253 const Pointer &Ptr, unsigned BitWidth);
2254bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2255bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2256
2257template <PrimType Name, class T = typename PrimConv<Name>::T>
2259 const Pointer &Ptr = S.Stk.pop<Pointer>();
2260
2261 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2262 return false;
2263
2264 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2265 return true;
2266}
2267
2268template <PrimType Name, class T = typename PrimConv<Name>::T>
2269static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2270 uint32_t FPS) {
2271 const T &Int = S.Stk.pop<T>();
2272
2273 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2274
2275 bool Overflow;
2276 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2277
2278 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2279 return false;
2280
2281 S.Stk.push<FixedPoint>(Result);
2282 return true;
2283}
2284
2285static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2286 uint32_t FPS) {
2287 const auto &Float = S.Stk.pop<Floating>();
2288
2289 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2290
2291 bool Overflow;
2292 FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
2293
2294 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2295 return false;
2296
2297 S.Stk.push<FixedPoint>(Result);
2298 return true;
2299}
2300
2301static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2302 const llvm::fltSemantics *Sem) {
2303 const auto &Fixed = S.Stk.pop<FixedPoint>();
2304
2305 S.Stk.push<Floating>(Fixed.toFloat(Sem));
2306 return true;
2307}
2308
2309template <PrimType Name, class T = typename PrimConv<Name>::T>
2310static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2311 const auto &Fixed = S.Stk.pop<FixedPoint>();
2312
2313 bool Overflow;
2314 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2315
2316 if (Overflow && !handleOverflow(S, OpPC, Int))
2317 return false;
2318
2319 S.Stk.push<T>(Int);
2320 return true;
2321}
2322
2323static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2324 const auto &Ptr = S.Stk.peek<Pointer>();
2325
2326 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2327 bool HasValidResult = !Ptr.isZero();
2328
2329 if (HasValidResult) {
2330 // FIXME: note_constexpr_invalid_void_star_cast
2331 } else if (!S.getLangOpts().CPlusPlus26) {
2332 const SourceInfo &E = S.Current->getSource(OpPC);
2333 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2334 << 3 << "'void *'" << S.Current->getRange(OpPC);
2335 }
2336 } else {
2337 const SourceInfo &E = S.Current->getSource(OpPC);
2338 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2339 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2340 }
2341
2342 return true;
2343}
2344
2345//===----------------------------------------------------------------------===//
2346// Zero, Nullptr
2347//===----------------------------------------------------------------------===//
2348
2349template <PrimType Name, class T = typename PrimConv<Name>::T>
2350bool Zero(InterpState &S, CodePtr OpPC) {
2351 S.Stk.push<T>(T::zero());
2352 return true;
2353}
2354
2355static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2356 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2357 return true;
2358}
2359
2360static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2361 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2362 return true;
2363}
2364
2365template <PrimType Name, class T = typename PrimConv<Name>::T>
2366inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2367 const Descriptor *Desc) {
2368 // FIXME(perf): This is a somewhat often-used function and the value of a
2369 // null pointer is almost always 0.
2370 S.Stk.push<T>(Value, Desc);
2371 return true;
2372}
2373
2374template <PrimType Name, class T = typename PrimConv<Name>::T>
2375inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2376 const auto &P = S.Stk.pop<T>();
2377 if (P.isWeak())
2378 return false;
2379 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2380 return true;
2381}
2382
2383//===----------------------------------------------------------------------===//
2384// This, ImplicitThis
2385//===----------------------------------------------------------------------===//
2386
2387inline bool This(InterpState &S, CodePtr OpPC) {
2388 // Cannot read 'this' in this mode.
2389 if (S.checkingPotentialConstantExpression()) {
2390 return false;
2391 }
2392
2393 const Pointer &This = S.Current->getThis();
2394 if (!CheckThis(S, OpPC, This))
2395 return false;
2396
2397 // Ensure the This pointer has been cast to the correct base.
2398 if (!This.isDummy()) {
2399 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2400 assert(This.getRecord());
2401 assert(
2402 This.getRecord()->getDecl() ==
2403 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2404 }
2405
2406 S.Stk.push<Pointer>(This);
2407 return true;
2408}
2409
2410inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2411 assert(S.Current->getFunction()->hasRVO());
2412 if (S.checkingPotentialConstantExpression())
2413 return false;
2414 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2415 return true;
2416}
2417
2418//===----------------------------------------------------------------------===//
2419// Shr, Shl
2420//===----------------------------------------------------------------------===//
2421
2422template <class LT, class RT, ShiftDir Dir>
2423inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2424 const unsigned Bits = LHS.bitWidth();
2425
2426 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2427 if (S.getLangOpts().OpenCL)
2428 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2429 RHS.bitWidth(), &RHS);
2430
2431 if (RHS.isNegative()) {
2432 // During constant-folding, a negative shift is an opposite shift. Such a
2433 // shift is not a constant expression.
2434 const SourceInfo &Loc = S.Current->getSource(OpPC);
2435 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2436 if (!S.noteUndefinedBehavior())
2437 return false;
2438 RHS = -RHS;
2439 return DoShift<LT, RT,
2441 S, OpPC, LHS, RHS);
2442 }
2443
2444 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2445 return false;
2446
2447 // Limit the shift amount to Bits - 1. If this happened,
2448 // it has already been diagnosed by CheckShift() above,
2449 // but we still need to handle it.
2450 // Note that we have to be extra careful here since we're doing the shift in
2451 // any case, but we need to adjust the shift amount or the way we do the shift
2452 // for the potential error cases.
2453 typename LT::AsUnsigned R;
2454 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2455 if constexpr (Dir == ShiftDir::Left) {
2456 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2458 if (LHS.isNegative())
2459 R = LT::AsUnsigned::zero(LHS.bitWidth());
2460 else {
2461 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2462 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2463 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2464 }
2465 } else if (LHS.isNegative()) {
2466 if (LHS.isMin()) {
2467 R = LT::AsUnsigned::zero(LHS.bitWidth());
2468 } else {
2469 // If the LHS is negative, perform the cast and invert the result.
2470 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2471 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2472 &R);
2473 R = -R;
2474 }
2475 } else {
2476 // The good case, a simple left shift.
2477 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2478 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2479 }
2480 } else {
2481 // Right shift.
2482 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2484 R = LT::AsUnsigned::from(-1);
2485 } else {
2486 // Do the shift on potentially signed LT, then convert to unsigned type.
2487 LT A;
2488 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2489 R = LT::AsUnsigned::from(A);
2490 }
2491 }
2492
2493 S.Stk.push<LT>(LT::from(R));
2494 return true;
2495}
2496
2497template <PrimType NameL, PrimType NameR>
2498inline bool Shr(InterpState &S, CodePtr OpPC) {
2499 using LT = typename PrimConv<NameL>::T;
2500 using RT = typename PrimConv<NameR>::T;
2501 auto RHS = S.Stk.pop<RT>();
2502 auto LHS = S.Stk.pop<LT>();
2503
2504 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2505}
2506
2507template <PrimType NameL, PrimType NameR>
2508inline bool Shl(InterpState &S, CodePtr OpPC) {
2509 using LT = typename PrimConv<NameL>::T;
2510 using RT = typename PrimConv<NameR>::T;
2511 auto RHS = S.Stk.pop<RT>();
2512 auto LHS = S.Stk.pop<LT>();
2513
2514 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2515}
2516
2517static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
2518 const auto &RHS = S.Stk.pop<FixedPoint>();
2519 const auto &LHS = S.Stk.pop<FixedPoint>();
2520 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
2521
2522 unsigned ShiftBitWidth =
2523 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
2524
2525 // Embedded-C 4.1.6.2.2:
2526 // The right operand must be nonnegative and less than the total number
2527 // of (nonpadding) bits of the fixed-point operand ...
2528 if (RHS.isNegative()) {
2529 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2530 << RHS.toAPSInt();
2531 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2532 ShiftBitWidth)) != RHS.toAPSInt()) {
2533 const Expr *E = S.Current->getExpr(OpPC);
2534 S.CCEDiag(E, diag::note_constexpr_large_shift)
2535 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
2536 }
2537
2539 if (Left) {
2540 if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
2542 return false;
2543 } else {
2544 if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
2546 return false;
2547 }
2548
2549 S.Stk.push<FixedPoint>(Result);
2550 return true;
2551}
2552
2553//===----------------------------------------------------------------------===//
2554// NoRet
2555//===----------------------------------------------------------------------===//
2556
2557inline bool NoRet(InterpState &S, CodePtr OpPC) {
2558 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2559 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2560 return false;
2561}
2562
2563//===----------------------------------------------------------------------===//
2564// NarrowPtr, ExpandPtr
2565//===----------------------------------------------------------------------===//
2566
2567inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2568 const Pointer &Ptr = S.Stk.pop<Pointer>();
2569 S.Stk.push<Pointer>(Ptr.narrow());
2570 return true;
2571}
2572
2573inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2574 const Pointer &Ptr = S.Stk.pop<Pointer>();
2575 S.Stk.push<Pointer>(Ptr.expand());
2576 return true;
2577}
2578
2579// 1) Pops an integral value from the stack
2580// 2) Peeks a pointer
2581// 3) Pushes a new pointer that's a narrowed array
2582// element of the peeked pointer with the value
2583// from 1) added as offset.
2584//
2585// This leaves the original pointer on the stack and pushes a new one
2586// with the offset applied and narrowed.
2587template <PrimType Name, class T = typename PrimConv<Name>::T>
2588inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2589 const T &Offset = S.Stk.pop<T>();
2590 const Pointer &Ptr = S.Stk.peek<Pointer>();
2591
2592 if (!Ptr.isZero() && !Offset.isZero()) {
2593 if (!CheckArray(S, OpPC, Ptr))
2594 return false;
2595 }
2596
2597 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2598 return false;
2599
2600 return NarrowPtr(S, OpPC);
2601}
2602
2603template <PrimType Name, class T = typename PrimConv<Name>::T>
2604inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2605 const T &Offset = S.Stk.pop<T>();
2606 const Pointer &Ptr = S.Stk.pop<Pointer>();
2607
2608 if (!Ptr.isZero() && !Offset.isZero()) {
2609 if (!CheckArray(S, OpPC, Ptr))
2610 return false;
2611 }
2612
2613 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2614 return false;
2615
2616 return NarrowPtr(S, OpPC);
2617}
2618
2619template <PrimType Name, class T = typename PrimConv<Name>::T>
2620inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2621 const Pointer &Ptr = S.Stk.peek<Pointer>();
2622
2623 if (!CheckLoad(S, OpPC, Ptr))
2624 return false;
2625
2626 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2627 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2628 return true;
2629}
2630
2631template <PrimType Name, class T = typename PrimConv<Name>::T>
2632inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2633 const Pointer &Ptr = S.Stk.pop<Pointer>();
2634
2635 if (!CheckLoad(S, OpPC, Ptr))
2636 return false;
2637
2638 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2639 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2640 return true;
2641}
2642
2643template <PrimType Name, class T = typename PrimConv<Name>::T>
2644inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2645 uint32_t DestIndex, uint32_t Size) {
2646 const auto &SrcPtr = S.Stk.pop<Pointer>();
2647 const auto &DestPtr = S.Stk.peek<Pointer>();
2648
2649 for (uint32_t I = 0; I != Size; ++I) {
2650 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2651
2652 if (!CheckLoad(S, OpPC, SP))
2653 return false;
2654
2655 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2656 DP.deref<T>() = SP.deref<T>();
2657 DP.initialize();
2658 }
2659 return true;
2660}
2661
2662/// Just takes a pointer and checks if it's an incomplete
2663/// array type.
2664inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2665 const Pointer &Ptr = S.Stk.pop<Pointer>();
2666
2667 if (Ptr.isZero()) {
2668 S.Stk.push<Pointer>(Ptr);
2669 return true;
2670 }
2671
2672 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2673 return false;
2674
2675 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
2676 S.Stk.push<Pointer>(Ptr.atIndex(0));
2677 return true;
2678 }
2679
2680 const SourceInfo &E = S.Current->getSource(OpPC);
2681 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2682
2683 return false;
2684}
2685
2686inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2687 assert(Func);
2688 S.Stk.push<FunctionPointer>(Func);
2689 return true;
2690}
2691
2692template <PrimType Name, class T = typename PrimConv<Name>::T>
2693inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2694 const T &IntVal = S.Stk.pop<T>();
2695
2696 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2697 return true;
2698}
2699
2700inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
2701 S.Stk.push<MemberPointer>(D);
2702 return true;
2703}
2704
2705inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2706 const auto &MP = S.Stk.pop<MemberPointer>();
2707
2708 S.Stk.push<Pointer>(MP.getBase());
2709 return true;
2710}
2711
2712inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2713 const auto &MP = S.Stk.pop<MemberPointer>();
2714
2715 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2716 const auto *Func = S.getContext().getOrCreateFunction(FD);
2717
2718 S.Stk.push<FunctionPointer>(Func);
2719 return true;
2720}
2721
2722/// Just emit a diagnostic. The expression that caused emission of this
2723/// op is not valid in a constant context.
2724inline bool Invalid(InterpState &S, CodePtr OpPC) {
2725 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2726 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2727 << S.Current->getRange(OpPC);
2728 return false;
2729}
2730
2731inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2732 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2733 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2734 << S.Current->getRange(OpPC);
2735 return false;
2736}
2737
2738/// Do nothing and just abort execution.
2739inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2740inline bool SideEffect(InterpState &S, CodePtr OpPC) {
2741 return S.noteSideEffect();
2742}
2743
2744/// Same here, but only for casts.
2745inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2746 bool Fatal) {
2747 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2748
2749 // FIXME: Support diagnosing other invalid cast kinds.
2750 if (Kind == CastKind::Reinterpret) {
2751 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2752 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2753 return !Fatal;
2754 }
2755 return false;
2756}
2757
2758inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
2759 bool InitializerFailed) {
2760 assert(DR);
2761
2762 if (InitializerFailed) {
2763 const SourceInfo &Loc = S.Current->getSource(OpPC);
2764 const auto *VD = cast<VarDecl>(DR->getDecl());
2765 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2766 S.Note(VD->getLocation(), diag::note_declared_at);
2767 return false;
2768 }
2769
2770 return CheckDeclRef(S, OpPC, DR);
2771}
2772
2774 if (S.inConstantContext()) {
2775 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2776 const Expr *E = S.Current->getExpr(OpPC);
2777 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2778 }
2779 return false;
2780}
2781
2782inline bool Assume(InterpState &S, CodePtr OpPC) {
2783 const auto Val = S.Stk.pop<Boolean>();
2784
2785 if (Val)
2786 return true;
2787
2788 // Else, diagnose.
2789 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2790 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2791 return false;
2792}
2793
2794template <PrimType Name, class T = typename PrimConv<Name>::T>
2795inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2796 llvm::SmallVector<int64_t> ArrayIndices;
2797 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2798 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2799
2800 int64_t Result;
2801 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2802 return false;
2803
2804 S.Stk.push<T>(T::from(Result));
2805
2806 return true;
2807}
2808
2809template <PrimType Name, class T = typename PrimConv<Name>::T>
2810inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2811 const T &Arg = S.Stk.peek<T>();
2812 if (!Arg.isZero())
2813 return true;
2814
2815 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2816 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2817
2818 return false;
2819}
2820
2821void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2822 const APSInt &Value);
2823
2824template <PrimType Name, class T = typename PrimConv<Name>::T>
2825inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2826 assert(ED);
2827 assert(!ED->isFixed());
2828 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2829
2830 if (S.inConstantContext())
2831 diagnoseEnumValue(S, OpPC, ED, Val);
2832 return true;
2833}
2834
2835/// OldPtr -> Integer -> NewPtr.
2836template <PrimType TIn, PrimType TOut>
2837inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2838 static_assert(isPtrType(TIn) && isPtrType(TOut));
2839 using FromT = typename PrimConv<TIn>::T;
2840 using ToT = typename PrimConv<TOut>::T;
2841
2842 const FromT &OldPtr = S.Stk.pop<FromT>();
2843
2844 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2845 std::is_same_v<ToT, Pointer>) {
2846 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2847 return true;
2848 } else if constexpr (std::is_same_v<FromT, Pointer> &&
2849 std::is_same_v<ToT, FunctionPointer>) {
2850 if (OldPtr.isFunctionPointer()) {
2851 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2852 OldPtr.getByteOffset());
2853 return true;
2854 }
2855 }
2856
2857 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2858 return true;
2859}
2860
2861inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2862 // An expression E is a core constant expression unless the evaluation of E
2863 // would evaluate one of the following: [C++23] - a control flow that passes
2864 // through a declaration of a variable with static or thread storage duration
2865 // unless that variable is usable in constant expressions.
2866 assert(VD->isLocalVarDecl() &&
2867 VD->isStaticLocal()); // Checked before emitting this.
2868
2869 if (VD == S.EvaluatingDecl)
2870 return true;
2871
2873 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2874 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2875 return false;
2876 }
2877 return true;
2878}
2879
2880inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2881 assert(Desc);
2882
2883 if (!CheckDynamicMemoryAllocation(S, OpPC))
2884 return false;
2885
2886 DynamicAllocator &Allocator = S.getAllocator();
2887 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2889 assert(B);
2890
2891 S.Stk.push<Pointer>(B);
2892
2893 return true;
2894}
2895
2896template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2897inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2898 bool IsNoThrow) {
2899 if (!CheckDynamicMemoryAllocation(S, OpPC))
2900 return false;
2901
2902 SizeT NumElements = S.Stk.pop<SizeT>();
2903 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2904 if (!IsNoThrow)
2905 return false;
2906
2907 // If this failed and is nothrow, just return a null ptr.
2908 S.Stk.push<Pointer>(0, nullptr);
2909 return true;
2910 }
2911
2912 DynamicAllocator &Allocator = S.getAllocator();
2913 Block *B =
2914 Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2915 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2916 assert(B);
2917 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2918
2919 return true;
2920}
2921
2922template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2923inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2924 bool IsNoThrow) {
2925 if (!CheckDynamicMemoryAllocation(S, OpPC))
2926 return false;
2927
2928 SizeT NumElements = S.Stk.pop<SizeT>();
2929 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2930 IsNoThrow)) {
2931 if (!IsNoThrow)
2932 return false;
2933
2934 // If this failed and is nothrow, just return a null ptr.
2935 S.Stk.push<Pointer>(0, ElementDesc);
2936 return true;
2937 }
2938
2939 DynamicAllocator &Allocator = S.getAllocator();
2940 Block *B =
2941 Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2942 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2943 assert(B);
2944
2945 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2946
2947 return true;
2948}
2949
2950bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
2951 bool IsGlobalDelete);
2952
2953static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
2954 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
2955 return true;
2956}
2957
2958static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
2959 return S.maybeDiagnoseDanglingAllocations();
2960}
2961
2962/// Check if the initializer and storage types of a placement-new expression
2963/// match.
2964bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
2965 std::optional<uint64_t> ArraySize = std::nullopt);
2966
2967template <PrimType Name, class T = typename PrimConv<Name>::T>
2969 const auto &Size = S.Stk.pop<T>();
2970 return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
2971}
2972bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
2973
2974template <PrimType Name, class T = typename PrimConv<Name>::T>
2975inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
2976 uint32_t ResultBitWidth,
2977 const llvm::fltSemantics *Sem) {
2978 const Pointer &FromPtr = S.Stk.pop<Pointer>();
2979
2980 if (!CheckLoad(S, OpPC, FromPtr))
2981 return false;
2982
2983 if constexpr (std::is_same_v<T, Pointer>) {
2984 // The only pointer type we can validly bitcast to is nullptr_t.
2985 S.Stk.push<Pointer>();
2986 return true;
2987 } else {
2988
2989 size_t BuffSize = ResultBitWidth / 8;
2990 llvm::SmallVector<std::byte> Buff(BuffSize);
2991 bool HasIndeterminateBits = false;
2992
2993 Bits FullBitWidth(ResultBitWidth);
2994 Bits BitWidth = FullBitWidth;
2995
2996 if constexpr (std::is_same_v<T, Floating>) {
2997 assert(Sem);
2998 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
2999 }
3000
3001 if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3002 HasIndeterminateBits))
3003 return false;
3004
3005 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3006 return false;
3007
3008 if constexpr (std::is_same_v<T, Floating>) {
3009 assert(Sem);
3010 S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3011 } else {
3012 assert(!Sem);
3013 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3014 }
3015 return true;
3016 }
3017}
3018
3019inline bool BitCast(InterpState &S, CodePtr OpPC) {
3020 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3021 Pointer &ToPtr = S.Stk.peek<Pointer>();
3022
3023 if (!CheckLoad(S, OpPC, FromPtr))
3024 return false;
3025
3026 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3027 return false;
3028
3029 return true;
3030}
3031
3032/// Typeid support.
3033bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3034 const Type *TypeInfoType);
3035bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3036bool DiagTypeid(InterpState &S, CodePtr OpPC);
3037
3038//===----------------------------------------------------------------------===//
3039// Read opcode arguments
3040//===----------------------------------------------------------------------===//
3041
3042template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3043 if constexpr (std::is_pointer<T>::value) {
3044 uint32_t ID = OpPC.read<uint32_t>();
3045 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3046 } else {
3047 return OpPC.read<T>();
3048 }
3049}
3050
3051template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3053 OpPC += align(F.bytesToSerialize());
3054 return F;
3055}
3056
3057template <>
3058inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3059 CodePtr &OpPC) {
3060 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3061 OpPC += align(I.bytesToSerialize());
3062 return I;
3063}
3064
3065template <>
3066inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3067 CodePtr &OpPC) {
3068 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3069 OpPC += align(I.bytesToSerialize());
3070 return I;
3071}
3072
3073template <>
3076 OpPC += align(FP.bytesToSerialize());
3077 return FP;
3078}
3079
3080} // namespace interp
3081} // namespace clang
3082
3083#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3460
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:3209
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:158
static FixedPoint deserialize(const std::byte *Buff)
Definition: FixedPoint.h:108
static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
Definition: FixedPoint.h:151
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
Definition: FixedPoint.h:40
size_t bytesToSerialize() const
Definition: FixedPoint.h:94
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:2517
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.cpp:1201
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1787
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2498
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:2632
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:1619
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2620
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1179
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1608
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:673
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition: Interp.h:2220
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2705
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:2567
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:3051
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:890
bool SideEffect(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2740
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2360
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:1653
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:448
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:846
bool BitCast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:3019
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:2366
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:898
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
Definition: Interp.cpp:1647
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:752
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:763
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1302
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2810
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:2861
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition: Interp.cpp:1590
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:1196
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:496
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2686
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:437
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:1569
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:2588
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1157
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2557
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2693
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:591
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2355
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)
Definition: Interp.h:2975
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2508
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2410
llvm::FixedPointSemantics FixedPointSemantics
Definition: Interp.h:43
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:535
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2258
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:2168
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2573
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:781
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:2604
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2387
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:837
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:3042
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:2190
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2664
bool DiagTypeid(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:1674
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition: Interp.cpp:620
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:1630
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:2795
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
FixedPoint ReadArg< FixedPoint >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3074
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2285
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition: Interp.cpp:1103
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:2968
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2350
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:2731
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
Definition: Interp.h:2758
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:645
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:874
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:790
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:1225
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2048
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2958
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2880
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.cpp:1582
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1859
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2269
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:1479
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
Definition: Interp.h:2700
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1652
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2773
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition: Interp.h:2323
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.cpp:1128
bool IsNonNull(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2375
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:561
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:924
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:903
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2712
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:2301
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:2837
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:2236
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:447
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
Definition: Interp.h:2423
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:1410
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition: Interp.cpp:1010
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.cpp:1532
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:681
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:1436
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1014
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2310
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:74
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1336
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
Definition: Interp.h:2175
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:468
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:2923
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1363
bool Interpret(InterpState &S)
Interpreter entry point.
Definition: Interp.cpp:1686
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:2745
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:2161
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:2782
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:661
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:2953
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition: Interp.h:2897
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition: Interp.h:2825
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