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>() =
1475 Value.truncate(F->Decl->getBitWidthValue(S.getASTContext()));
1476 Field.initialize();
1477 return true;
1478}
1479
1480/// 1) Pops the value from the stack
1481/// 2) Peeks a pointer from the stack
1482/// 3) Pushes the value to field I of the pointer on the stack
1483template <PrimType Name, class T = typename PrimConv<Name>::T>
1484bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1485 const T &Value = S.Stk.pop<T>();
1486 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1487 Field.deref<T>() = Value;
1488 Field.activate();
1489 Field.initialize();
1490 return true;
1491}
1492
1493template <PrimType Name, class T = typename PrimConv<Name>::T>
1494bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1495 assert(F->isBitField());
1496 const T &Value = S.Stk.pop<T>();
1497 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1498 Field.deref<T>() =
1499 Value.truncate(F->Decl->getBitWidthValue(S.getASTContext()));
1500 Field.activate();
1501 Field.initialize();
1502 return true;
1503}
1504
1505//===----------------------------------------------------------------------===//
1506// GetPtr Local/Param/Global/Field/This
1507//===----------------------------------------------------------------------===//
1508
1509inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1510 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1511 return true;
1512}
1513
1514inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1515 if (S.checkingPotentialConstantExpression()) {
1516 return false;
1517 }
1518 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1519 return true;
1520}
1521
1522inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1523 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1524 return true;
1525}
1526
1527/// 1) Peeks a Pointer
1528/// 2) Pushes Pointer.atField(Off) on the stack
1529inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1530 const Pointer &Ptr = S.Stk.peek<Pointer>();
1531
1532 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1533 !CheckNull(S, OpPC, Ptr, CSK_Field))
1534 return false;
1535
1536 if (!CheckExtern(S, OpPC, Ptr))
1537 return false;
1538 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1539 return false;
1540 if (!CheckArray(S, OpPC, Ptr))
1541 return false;
1542 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1543 return false;
1544
1545 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1546 return false;
1547
1548 if (Ptr.isIntegralPointer()) {
1549 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
1550 return true;
1551 }
1552
1553 S.Stk.push<Pointer>(Ptr.atField(Off));
1554 return true;
1555}
1556
1557inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1558 const Pointer &Ptr = S.Stk.pop<Pointer>();
1559
1560 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1561 !CheckNull(S, OpPC, Ptr, CSK_Field))
1562 return false;
1563
1564 if (!CheckExtern(S, OpPC, Ptr))
1565 return false;
1566 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1567 return false;
1568 if (!CheckArray(S, OpPC, Ptr))
1569 return false;
1570 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1571 return false;
1572
1573 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1574 return false;
1575
1576 if (Ptr.isIntegralPointer()) {
1577 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
1578 return true;
1579 }
1580
1581 S.Stk.push<Pointer>(Ptr.atField(Off));
1582 return true;
1583}
1584
1585inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1586 if (S.checkingPotentialConstantExpression())
1587 return false;
1588 const Pointer &This = S.Current->getThis();
1589 if (!CheckThis(S, OpPC, This))
1590 return false;
1591 S.Stk.push<Pointer>(This.atField(Off));
1592 return true;
1593}
1594
1595inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1596 const Pointer &Ptr = S.Stk.pop<Pointer>();
1597 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1598 return false;
1599 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1600 return false;
1601 Pointer Field = Ptr.atField(Off);
1602 Ptr.deactivate();
1603 Field.activate();
1604 S.Stk.push<Pointer>(std::move(Field));
1605 return true;
1606}
1607
1608inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1609 if (S.checkingPotentialConstantExpression())
1610 return false;
1611 const Pointer &This = S.Current->getThis();
1612 if (!CheckThis(S, OpPC, This))
1613 return false;
1614 Pointer Field = This.atField(Off);
1615 This.deactivate();
1616 Field.activate();
1617 S.Stk.push<Pointer>(std::move(Field));
1618 return true;
1619}
1620
1621inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1622 const Pointer &Ptr = S.Stk.pop<Pointer>();
1623 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1624 return false;
1625 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1626 return false;
1627 if (!CheckDowncast(S, OpPC, Ptr, Off))
1628 return false;
1629
1630 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1631 return true;
1632}
1633
1634inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1635 const Pointer &Ptr = S.Stk.peek<Pointer>();
1636 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1637 return false;
1638
1639 if (!Ptr.isBlockPointer()) {
1640 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1641 return true;
1642 }
1643
1644 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1645 return false;
1646 const Pointer &Result = Ptr.atField(Off);
1647 if (Result.isPastEnd() || !Result.isBaseClass())
1648 return false;
1649 S.Stk.push<Pointer>(Result);
1650 return true;
1651}
1652
1653inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1654 const Pointer &Ptr = S.Stk.pop<Pointer>();
1655
1656 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1657 return false;
1658
1659 if (!Ptr.isBlockPointer()) {
1660 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1661 return true;
1662 }
1663
1664 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1665 return false;
1666 const Pointer &Result = Ptr.atField(Off);
1667 if (Result.isPastEnd() || !Result.isBaseClass())
1668 return false;
1669 S.Stk.push<Pointer>(Result);
1670 return true;
1671}
1672
1673inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1674 const auto &Ptr = S.Stk.pop<MemberPointer>();
1675 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1676 return true;
1677}
1678
1679inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1680 if (S.checkingPotentialConstantExpression())
1681 return false;
1682 const Pointer &This = S.Current->getThis();
1683 if (!CheckThis(S, OpPC, This))
1684 return false;
1685 S.Stk.push<Pointer>(This.atField(Off));
1686 return true;
1687}
1688
1689inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1690 const Pointer &Ptr = S.Stk.pop<Pointer>();
1691 if (Ptr.canBeInitialized()) {
1692 Ptr.initialize();
1693 Ptr.activate();
1694 }
1695 return true;
1696}
1697
1698inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1699 const Pointer &Ptr = S.Stk.peek<Pointer>();
1700 if (Ptr.canBeInitialized()) {
1701 Ptr.initialize();
1702 Ptr.activate();
1703 }
1704 return true;
1705}
1706
1707inline bool Dump(InterpState &S, CodePtr OpPC) {
1708 S.Stk.dump();
1709 return true;
1710}
1711
1712inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1713 const Pointer &Ptr) {
1714 Pointer Base = Ptr;
1715 while (Base.isBaseClass())
1716 Base = Base.getBase();
1717
1718 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1719 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1720 return true;
1721}
1722
1724 const RecordDecl *D) {
1725 assert(D);
1726 const Pointer &Ptr = S.Stk.pop<Pointer>();
1727 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1728 return false;
1729 return VirtBaseHelper(S, OpPC, D, Ptr);
1730}
1731
1733 const RecordDecl *D) {
1734 assert(D);
1735 if (S.checkingPotentialConstantExpression())
1736 return false;
1737 const Pointer &This = S.Current->getThis();
1738 if (!CheckThis(S, OpPC, This))
1739 return false;
1740 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1741}
1742
1743//===----------------------------------------------------------------------===//
1744// Load, Store, Init
1745//===----------------------------------------------------------------------===//
1746
1747template <PrimType Name, class T = typename PrimConv<Name>::T>
1748bool Load(InterpState &S, CodePtr OpPC) {
1749 const Pointer &Ptr = S.Stk.peek<Pointer>();
1750 if (!CheckLoad(S, OpPC, Ptr))
1751 return false;
1752 if (!Ptr.isBlockPointer())
1753 return false;
1754 S.Stk.push<T>(Ptr.deref<T>());
1755 return true;
1756}
1757
1758template <PrimType Name, class T = typename PrimConv<Name>::T>
1760 const Pointer &Ptr = S.Stk.pop<Pointer>();
1761 if (!CheckLoad(S, OpPC, Ptr))
1762 return false;
1763 if (!Ptr.isBlockPointer())
1764 return false;
1765 S.Stk.push<T>(Ptr.deref<T>());
1766 return true;
1767}
1768
1769template <PrimType Name, class T = typename PrimConv<Name>::T>
1770bool Store(InterpState &S, CodePtr OpPC) {
1771 const T &Value = S.Stk.pop<T>();
1772 const Pointer &Ptr = S.Stk.peek<Pointer>();
1773 if (!CheckStore(S, OpPC, Ptr))
1774 return false;
1775 if (Ptr.canBeInitialized()) {
1776 Ptr.initialize();
1777 Ptr.activate();
1778 }
1779 Ptr.deref<T>() = Value;
1780 return true;
1781}
1782
1783template <PrimType Name, class T = typename PrimConv<Name>::T>
1785 const T &Value = S.Stk.pop<T>();
1786 const Pointer &Ptr = S.Stk.pop<Pointer>();
1787 if (!CheckStore(S, OpPC, Ptr))
1788 return false;
1789 if (Ptr.canBeInitialized()) {
1790 Ptr.initialize();
1791 Ptr.activate();
1792 }
1793 Ptr.deref<T>() = Value;
1794 return true;
1795}
1796
1797template <PrimType Name, class T = typename PrimConv<Name>::T>
1799 const T &Value = S.Stk.pop<T>();
1800 const Pointer &Ptr = S.Stk.peek<Pointer>();
1801 if (!CheckStore(S, OpPC, Ptr))
1802 return false;
1803 if (Ptr.canBeInitialized())
1804 Ptr.initialize();
1805 if (const auto *FD = Ptr.getField())
1806 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getASTContext()));
1807 else
1808 Ptr.deref<T>() = Value;
1809 return true;
1810}
1811
1812template <PrimType Name, class T = typename PrimConv<Name>::T>
1814 const T &Value = S.Stk.pop<T>();
1815 const Pointer &Ptr = S.Stk.pop<Pointer>();
1816 if (!CheckStore(S, OpPC, Ptr))
1817 return false;
1818 if (Ptr.canBeInitialized())
1819 Ptr.initialize();
1820 if (const auto *FD = Ptr.getField())
1821 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getASTContext()));
1822 else
1823 Ptr.deref<T>() = Value;
1824 return true;
1825}
1826
1827template <PrimType Name, class T = typename PrimConv<Name>::T>
1828bool Init(InterpState &S, CodePtr OpPC) {
1829 const T &Value = S.Stk.pop<T>();
1830 const Pointer &Ptr = S.Stk.peek<Pointer>();
1831 if (!CheckInit(S, OpPC, Ptr)) {
1832 assert(false);
1833 return false;
1834 }
1835 Ptr.activate();
1836 Ptr.initialize();
1837 new (&Ptr.deref<T>()) T(Value);
1838 return true;
1839}
1840
1841template <PrimType Name, class T = typename PrimConv<Name>::T>
1843 const T &Value = S.Stk.pop<T>();
1844 const Pointer &Ptr = S.Stk.pop<Pointer>();
1845 if (!CheckInit(S, OpPC, Ptr))
1846 return false;
1847 Ptr.activate();
1848 Ptr.initialize();
1849 new (&Ptr.deref<T>()) T(Value);
1850 return true;
1851}
1852
1853/// 1) Pops the value from the stack
1854/// 2) Peeks a pointer and gets its index \Idx
1855/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1856template <PrimType Name, class T = typename PrimConv<Name>::T>
1857bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1858 const T &Value = S.Stk.pop<T>();
1859 const Pointer &Ptr = S.Stk.peek<Pointer>();
1860
1861 if (Ptr.isUnknownSizeArray())
1862 return false;
1863
1864 // In the unlikely event that we're initializing the first item of
1865 // a non-array, skip the atIndex().
1866 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1867 Ptr.initialize();
1868 new (&Ptr.deref<T>()) T(Value);
1869 return true;
1870 }
1871
1872 const Pointer &ElemPtr = Ptr.atIndex(Idx);
1873 if (!CheckInit(S, OpPC, ElemPtr))
1874 return false;
1875 ElemPtr.initialize();
1876 new (&ElemPtr.deref<T>()) T(Value);
1877 return true;
1878}
1879
1880/// The same as InitElem, but pops the pointer as well.
1881template <PrimType Name, class T = typename PrimConv<Name>::T>
1882bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1883 const T &Value = S.Stk.pop<T>();
1884 const Pointer &Ptr = S.Stk.pop<Pointer>();
1885 if (Ptr.isUnknownSizeArray())
1886 return false;
1887
1888 // In the unlikely event that we're initializing the first item of
1889 // a non-array, skip the atIndex().
1890 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1891 Ptr.initialize();
1892 new (&Ptr.deref<T>()) T(Value);
1893 return true;
1894 }
1895
1896 const Pointer &ElemPtr = Ptr.atIndex(Idx);
1897 if (!CheckInit(S, OpPC, ElemPtr))
1898 return false;
1899 ElemPtr.initialize();
1900 new (&ElemPtr.deref<T>()) T(Value);
1901 return true;
1902}
1903
1904inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1905 const Pointer &Src = S.Stk.pop<Pointer>();
1906 Pointer &Dest = S.Stk.peek<Pointer>();
1907
1908 if (!CheckLoad(S, OpPC, Src))
1909 return false;
1910
1911 return DoMemcpy(S, OpPC, Src, Dest);
1912}
1913
1914inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1915 const auto &Member = S.Stk.pop<MemberPointer>();
1916 const auto &Base = S.Stk.pop<Pointer>();
1917
1918 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1919 return true;
1920}
1921
1922inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1923 const auto &MP = S.Stk.pop<MemberPointer>();
1924
1925 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1926 S.Stk.push<Pointer>(*Ptr);
1927 return true;
1928 }
1929 return false;
1930}
1931
1932//===----------------------------------------------------------------------===//
1933// AddOffset, SubOffset
1934//===----------------------------------------------------------------------===//
1935
1936template <class T, ArithOp Op>
1937bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1938 const Pointer &Ptr, bool IsPointerArith = false) {
1939 // A zero offset does not change the pointer.
1940 if (Offset.isZero()) {
1941 S.Stk.push<Pointer>(Ptr);
1942 return true;
1943 }
1944
1945 if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1946 // The CheckNull will have emitted a note already, but we only
1947 // abort in C++, since this is fine in C.
1948 if (S.getLangOpts().CPlusPlus)
1949 return false;
1950 }
1951
1952 // Arrays of unknown bounds cannot have pointers into them.
1953 if (!CheckArray(S, OpPC, Ptr))
1954 return false;
1955
1956 // This is much simpler for integral pointers, so handle them first.
1957 if (Ptr.isIntegralPointer()) {
1958 uint64_t V = Ptr.getIntegerRepresentation();
1959 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
1960 if constexpr (Op == ArithOp::Add)
1961 S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
1962 else
1963 S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
1964 return true;
1965 } else if (Ptr.isFunctionPointer()) {
1966 uint64_t O = static_cast<uint64_t>(Offset);
1967 uint64_t N;
1968 if constexpr (Op == ArithOp::Add)
1969 N = Ptr.getByteOffset() + O;
1970 else
1971 N = Ptr.getByteOffset() - O;
1972
1973 if (N > 1)
1974 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1975 << N << /*non-array*/ true << 0;
1976 S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N);
1977 return true;
1978 }
1979
1980 assert(Ptr.isBlockPointer());
1981
1982 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1983 uint64_t Index;
1984 if (Ptr.isOnePastEnd())
1985 Index = MaxIndex;
1986 else
1987 Index = Ptr.getIndex();
1988
1989 bool Invalid = false;
1990 // Helper to report an invalid offset, computed as APSInt.
1991 auto DiagInvalidOffset = [&]() -> void {
1992 const unsigned Bits = Offset.bitWidth();
1993 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1994 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1995 /*IsUnsigned=*/false);
1996 APSInt NewIndex =
1997 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1998 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1999 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
2000 Invalid = true;
2001 };
2002
2003 if (Ptr.isBlockPointer()) {
2004 uint64_t IOffset = static_cast<uint64_t>(Offset);
2005 uint64_t MaxOffset = MaxIndex - Index;
2006
2007 if constexpr (Op == ArithOp::Add) {
2008 // If the new offset would be negative, bail out.
2009 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2010 DiagInvalidOffset();
2011
2012 // If the new offset would be out of bounds, bail out.
2013 if (Offset.isPositive() && IOffset > MaxOffset)
2014 DiagInvalidOffset();
2015 } else {
2016 // If the new offset would be negative, bail out.
2017 if (Offset.isPositive() && Index < IOffset)
2018 DiagInvalidOffset();
2019
2020 // If the new offset would be out of bounds, bail out.
2021 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2022 DiagInvalidOffset();
2023 }
2024 }
2025
2026 if (Invalid && S.getLangOpts().CPlusPlus)
2027 return false;
2028
2029 // Offset is valid - compute it on unsigned.
2030 int64_t WideIndex = static_cast<int64_t>(Index);
2031 int64_t WideOffset = static_cast<int64_t>(Offset);
2032 int64_t Result;
2033 if constexpr (Op == ArithOp::Add)
2034 Result = WideIndex + WideOffset;
2035 else
2036 Result = WideIndex - WideOffset;
2037
2038 // When the pointer is one-past-end, going back to index 0 is the only
2039 // useful thing we can do. Any other index has been diagnosed before and
2040 // we don't get here.
2041 if (Result == 0 && Ptr.isOnePastEnd()) {
2042 S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
2043 Ptr.asBlockPointer().Base);
2044 return true;
2045 }
2046
2047 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
2048 return true;
2049}
2050
2051template <PrimType Name, class T = typename PrimConv<Name>::T>
2053 const T &Offset = S.Stk.pop<T>();
2054 Pointer Ptr = S.Stk.pop<Pointer>();
2055 if (Ptr.isBlockPointer())
2056 Ptr = Ptr.expand();
2057 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
2058 /*IsPointerArith=*/true);
2059}
2060
2061template <PrimType Name, class T = typename PrimConv<Name>::T>
2063 const T &Offset = S.Stk.pop<T>();
2064 const Pointer &Ptr = S.Stk.pop<Pointer>();
2065 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
2066 /*IsPointerArith=*/true);
2067}
2068
2069template <ArithOp Op>
2070static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2071 const Pointer &Ptr) {
2072 if (Ptr.isDummy())
2073 return false;
2074
2075 using OneT = Integral<8, false>;
2076
2077 const Pointer &P = Ptr.deref<Pointer>();
2078 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
2079 return false;
2080
2081 // Get the current value on the stack.
2082 S.Stk.push<Pointer>(P);
2083
2084 // Now the current Ptr again and a constant 1.
2085 OneT One = OneT::from(1);
2086 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true))
2087 return false;
2088
2089 // Store the new value.
2090 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
2091 return true;
2092}
2093
2094static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2095 const Pointer &Ptr = S.Stk.pop<Pointer>();
2096
2097 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
2098 return false;
2099
2100 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2101}
2102
2103static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2104 const Pointer &Ptr = S.Stk.pop<Pointer>();
2105
2106 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
2107 return false;
2108
2109 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2110}
2111
2112/// 1) Pops a Pointer from the stack.
2113/// 2) Pops another Pointer from the stack.
2114/// 3) Pushes the different of the indices of the two pointers on the stack.
2115template <PrimType Name, class T = typename PrimConv<Name>::T>
2116inline bool SubPtr(InterpState &S, CodePtr OpPC) {
2117 const Pointer &LHS = S.Stk.pop<Pointer>();
2118 const Pointer &RHS = S.Stk.pop<Pointer>();
2119
2120 for (const Pointer &P : {LHS, RHS}) {
2121 if (P.isZeroSizeArray()) {
2122 QualType PtrT = P.getType();
2123 while (auto *AT = dyn_cast<ArrayType>(PtrT))
2124 PtrT = AT->getElementType();
2125
2127 PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2128 S.FFDiag(S.Current->getSource(OpPC),
2129 diag::note_constexpr_pointer_subtraction_zero_size)
2130 << ArrayTy;
2131
2132 return false;
2133 }
2134 }
2135
2136 if (RHS.isZero()) {
2137 S.Stk.push<T>(T::from(LHS.getIndex()));
2138 return true;
2139 }
2140
2141 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2142 // TODO: Diagnose.
2143 return false;
2144 }
2145
2146 if (LHS.isZero() && RHS.isZero()) {
2147 S.Stk.push<T>();
2148 return true;
2149 }
2150
2151 T A = LHS.isBlockPointer()
2152 ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
2153 : T::from(LHS.getIndex()))
2154 : T::from(LHS.getIntegerRepresentation());
2155 T B = RHS.isBlockPointer()
2156 ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2157 : T::from(RHS.getIndex()))
2158 : T::from(RHS.getIntegerRepresentation());
2159
2160 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2161}
2162
2163//===----------------------------------------------------------------------===//
2164// Destroy
2165//===----------------------------------------------------------------------===//
2166
2167inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2168 S.Current->destroy(I);
2169 return true;
2170}
2171
2172inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2173 S.Current->initScope(I);
2174 return true;
2175}
2176
2177//===----------------------------------------------------------------------===//
2178// Cast, CastFP
2179//===----------------------------------------------------------------------===//
2180
2181template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2182 using T = typename PrimConv<TIn>::T;
2183 using U = typename PrimConv<TOut>::T;
2184 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2185 return true;
2186}
2187
2188/// 1) Pops a Floating from the stack.
2189/// 2) Pushes a new floating on the stack that uses the given semantics.
2190inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2191 llvm::RoundingMode RM) {
2192 Floating F = S.Stk.pop<Floating>();
2193 Floating Result = F.toSemantics(Sem, RM);
2194 S.Stk.push<Floating>(Result);
2195 return true;
2196}
2197
2198inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2199 FixedPointSemantics TargetSemantics(0, 0, false, false, false);
2200 std::memcpy(&TargetSemantics, &FPS, sizeof(TargetSemantics));
2201
2202 const auto &Source = S.Stk.pop<FixedPoint>();
2203
2204 bool Overflow;
2205 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2206
2207 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2208 return false;
2209
2210 S.Stk.push<FixedPoint>(Result);
2211 return true;
2212}
2213
2214/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2215/// to know what bitwidth the result should be.
2216template <PrimType Name, class T = typename PrimConv<Name>::T>
2217bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2218 S.Stk.push<IntegralAP<false>>(
2219 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2220 return true;
2221}
2222
2223template <PrimType Name, class T = typename PrimConv<Name>::T>
2224bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2225 S.Stk.push<IntegralAP<true>>(
2226 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2227 return true;
2228}
2229
2230template <PrimType Name, class T = typename PrimConv<Name>::T>
2232 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2233 const T &From = S.Stk.pop<T>();
2234 APSInt FromAP = From.toAPSInt();
2236
2238 auto Status =
2239 Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
2240 S.Stk.push<Floating>(Result);
2241
2242 return CheckFloatResult(S, OpPC, Result, Status, FPO);
2243}
2244
2245template <PrimType Name, class T = typename PrimConv<Name>::T>
2246bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2247 const Floating &F = S.Stk.pop<Floating>();
2248
2249 if constexpr (std::is_same_v<T, Boolean>) {
2250 S.Stk.push<T>(T(F.isNonZero()));
2251 return true;
2252 } else {
2253 APSInt Result(std::max(8u, T::bitWidth()),
2254 /*IsUnsigned=*/!T::isSigned());
2255 auto Status = F.convertToInteger(Result);
2256
2257 // Float-to-Integral overflow check.
2258 if ((Status & APFloat::opStatus::opInvalidOp)) {
2259 const Expr *E = S.Current->getExpr(OpPC);
2260 QualType Type = E->getType();
2261
2262 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2263 if (S.noteUndefinedBehavior()) {
2264 S.Stk.push<T>(T(Result));
2265 return true;
2266 }
2267 return false;
2268 }
2269
2271 S.Stk.push<T>(T(Result));
2272 return CheckFloatResult(S, OpPC, F, Status, FPO);
2273 }
2274}
2275
2276static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2277 uint32_t BitWidth, uint32_t FPOI) {
2278 const Floating &F = S.Stk.pop<Floating>();
2279
2280 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2281 auto Status = F.convertToInteger(Result);
2282
2283 // Float-to-Integral overflow check.
2284 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2285 return handleOverflow(S, OpPC, F.getAPFloat());
2286
2289 return CheckFloatResult(S, OpPC, F, Status, FPO);
2290}
2291
2292static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2293 uint32_t BitWidth, uint32_t FPOI) {
2294 const Floating &F = S.Stk.pop<Floating>();
2295
2296 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2297 auto Status = F.convertToInteger(Result);
2298
2299 // Float-to-Integral overflow check.
2300 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2301 return handleOverflow(S, OpPC, F.getAPFloat());
2302
2305 return CheckFloatResult(S, OpPC, F, Status, FPO);
2306}
2307
2308bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2309 const Pointer &Ptr, unsigned BitWidth);
2310bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2311bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2312
2313template <PrimType Name, class T = typename PrimConv<Name>::T>
2315 const Pointer &Ptr = S.Stk.pop<Pointer>();
2316
2317 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2318 return false;
2319
2320 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2321 return true;
2322}
2323
2324template <PrimType Name, class T = typename PrimConv<Name>::T>
2325static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2326 uint32_t FPS) {
2327 const T &Int = S.Stk.pop<T>();
2328
2329 FixedPointSemantics Sem(0, 0, false, false, false);
2330 std::memcpy(&Sem, &FPS, sizeof(Sem));
2331
2332 bool Overflow;
2333 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2334
2335 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2336 return false;
2337
2338 S.Stk.push<FixedPoint>(Result);
2339 return true;
2340}
2341
2342static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2343 uint32_t FPS) {
2344 const auto &Float = S.Stk.pop<Floating>();
2345
2346 FixedPointSemantics Sem(0, 0, false, false, false);
2347 std::memcpy(&Sem, &FPS, sizeof(Sem));
2348
2349 bool Overflow;
2350 FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
2351
2352 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2353 return false;
2354
2355 S.Stk.push<FixedPoint>(Result);
2356 return true;
2357}
2358
2359static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2360 const llvm::fltSemantics *Sem) {
2361 const auto &Fixed = S.Stk.pop<FixedPoint>();
2362
2363 S.Stk.push<Floating>(Fixed.toFloat(Sem));
2364 return true;
2365}
2366
2367template <PrimType Name, class T = typename PrimConv<Name>::T>
2368static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2369 const auto &Fixed = S.Stk.pop<FixedPoint>();
2370
2371 bool Overflow;
2372 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2373
2374 if (Overflow && !handleOverflow(S, OpPC, Int))
2375 return false;
2376
2377 S.Stk.push<T>(Int);
2378 return true;
2379}
2380
2381static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2382 const auto &Ptr = S.Stk.peek<Pointer>();
2383
2384 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2385 bool HasValidResult = !Ptr.isZero();
2386
2387 if (HasValidResult) {
2388 // FIXME: note_constexpr_invalid_void_star_cast
2389 } else if (!S.getLangOpts().CPlusPlus26) {
2390 const SourceInfo &E = S.Current->getSource(OpPC);
2391 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2392 << 3 << "'void *'" << S.Current->getRange(OpPC);
2393 }
2394 } else {
2395 const SourceInfo &E = S.Current->getSource(OpPC);
2396 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2397 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2398 }
2399
2400 return true;
2401}
2402
2403//===----------------------------------------------------------------------===//
2404// Zero, Nullptr
2405//===----------------------------------------------------------------------===//
2406
2407template <PrimType Name, class T = typename PrimConv<Name>::T>
2408bool Zero(InterpState &S, CodePtr OpPC) {
2409 S.Stk.push<T>(T::zero());
2410 return true;
2411}
2412
2413static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2414 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2415 return true;
2416}
2417
2418static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2419 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2420 return true;
2421}
2422
2423template <PrimType Name, class T = typename PrimConv<Name>::T>
2424inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2425 const Descriptor *Desc) {
2426 // FIXME(perf): This is a somewhat often-used function and the value of a
2427 // null pointer is almost always 0.
2428 S.Stk.push<T>(Value, Desc);
2429 return true;
2430}
2431
2432template <PrimType Name, class T = typename PrimConv<Name>::T>
2433inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2434 const auto &P = S.Stk.pop<T>();
2435 if (P.isWeak())
2436 return false;
2437 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2438 return true;
2439}
2440
2441//===----------------------------------------------------------------------===//
2442// This, ImplicitThis
2443//===----------------------------------------------------------------------===//
2444
2445inline bool This(InterpState &S, CodePtr OpPC) {
2446 // Cannot read 'this' in this mode.
2447 if (S.checkingPotentialConstantExpression()) {
2448 return false;
2449 }
2450
2451 const Pointer &This = S.Current->getThis();
2452 if (!CheckThis(S, OpPC, This))
2453 return false;
2454
2455 // Ensure the This pointer has been cast to the correct base.
2456 if (!This.isDummy()) {
2457 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2458 assert(This.getRecord());
2459 assert(
2460 This.getRecord()->getDecl() ==
2461 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2462 }
2463
2464 S.Stk.push<Pointer>(This);
2465 return true;
2466}
2467
2468inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2469 assert(S.Current->getFunction()->hasRVO());
2470 if (S.checkingPotentialConstantExpression())
2471 return false;
2472 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2473 return true;
2474}
2475
2476//===----------------------------------------------------------------------===//
2477// Shr, Shl
2478//===----------------------------------------------------------------------===//
2479
2480template <class LT, class RT, ShiftDir Dir>
2481inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2482 const unsigned Bits = LHS.bitWidth();
2483
2484 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2485 if (S.getLangOpts().OpenCL)
2486 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2487 RHS.bitWidth(), &RHS);
2488
2489 if (RHS.isNegative()) {
2490 // During constant-folding, a negative shift is an opposite shift. Such a
2491 // shift is not a constant expression.
2492 const SourceInfo &Loc = S.Current->getSource(OpPC);
2493 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2494 if (!S.noteUndefinedBehavior())
2495 return false;
2496 RHS = -RHS;
2497 return DoShift<LT, RT,
2499 S, OpPC, LHS, RHS);
2500 }
2501
2502 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2503 return false;
2504
2505 // Limit the shift amount to Bits - 1. If this happened,
2506 // it has already been diagnosed by CheckShift() above,
2507 // but we still need to handle it.
2508 // Note that we have to be extra careful here since we're doing the shift in
2509 // any case, but we need to adjust the shift amount or the way we do the shift
2510 // for the potential error cases.
2511 typename LT::AsUnsigned R;
2512 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2513 if constexpr (Dir == ShiftDir::Left) {
2514 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2516 if (LHS.isNegative())
2517 R = LT::AsUnsigned::zero(LHS.bitWidth());
2518 else {
2519 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2520 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2521 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2522 }
2523 } else if (LHS.isNegative()) {
2524 if (LHS.isMin()) {
2525 R = LT::AsUnsigned::zero(LHS.bitWidth());
2526 } else {
2527 // If the LHS is negative, perform the cast and invert the result.
2528 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2529 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2530 &R);
2531 R = -R;
2532 }
2533 } else {
2534 // The good case, a simple left shift.
2535 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2536 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2537 }
2538 } else {
2539 // Right shift.
2540 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2542 R = LT::AsUnsigned::from(-1);
2543 } else {
2544 // Do the shift on potentially signed LT, then convert to unsigned type.
2545 LT A;
2546 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2547 R = LT::AsUnsigned::from(A);
2548 }
2549 }
2550
2551 S.Stk.push<LT>(LT::from(R));
2552 return true;
2553}
2554
2555template <PrimType NameL, PrimType NameR>
2556inline bool Shr(InterpState &S, CodePtr OpPC) {
2557 using LT = typename PrimConv<NameL>::T;
2558 using RT = typename PrimConv<NameR>::T;
2559 auto RHS = S.Stk.pop<RT>();
2560 auto LHS = S.Stk.pop<LT>();
2561
2562 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2563}
2564
2565template <PrimType NameL, PrimType NameR>
2566inline bool Shl(InterpState &S, CodePtr OpPC) {
2567 using LT = typename PrimConv<NameL>::T;
2568 using RT = typename PrimConv<NameR>::T;
2569 auto RHS = S.Stk.pop<RT>();
2570 auto LHS = S.Stk.pop<LT>();
2571
2572 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2573}
2574
2575static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
2576 const auto &RHS = S.Stk.pop<FixedPoint>();
2577 const auto &LHS = S.Stk.pop<FixedPoint>();
2578 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
2579
2580 unsigned ShiftBitWidth =
2581 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
2582
2583 // Embedded-C 4.1.6.2.2:
2584 // The right operand must be nonnegative and less than the total number
2585 // of (nonpadding) bits of the fixed-point operand ...
2586 if (RHS.isNegative()) {
2587 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2588 << RHS.toAPSInt();
2589 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2590 ShiftBitWidth)) != RHS.toAPSInt()) {
2591 const Expr *E = S.Current->getExpr(OpPC);
2592 S.CCEDiag(E, diag::note_constexpr_large_shift)
2593 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
2594 }
2595
2597 if (Left) {
2598 if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
2600 return false;
2601 } else {
2602 if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
2604 return false;
2605 }
2606
2607 S.Stk.push<FixedPoint>(Result);
2608 return true;
2609}
2610
2611//===----------------------------------------------------------------------===//
2612// NoRet
2613//===----------------------------------------------------------------------===//
2614
2615inline bool NoRet(InterpState &S, CodePtr OpPC) {
2616 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2617 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2618 return false;
2619}
2620
2621//===----------------------------------------------------------------------===//
2622// NarrowPtr, ExpandPtr
2623//===----------------------------------------------------------------------===//
2624
2625inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2626 const Pointer &Ptr = S.Stk.pop<Pointer>();
2627 S.Stk.push<Pointer>(Ptr.narrow());
2628 return true;
2629}
2630
2631inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2632 const Pointer &Ptr = S.Stk.pop<Pointer>();
2633 S.Stk.push<Pointer>(Ptr.expand());
2634 return true;
2635}
2636
2637// 1) Pops an integral value from the stack
2638// 2) Peeks a pointer
2639// 3) Pushes a new pointer that's a narrowed array
2640// element of the peeked pointer with the value
2641// from 1) added as offset.
2642//
2643// This leaves the original pointer on the stack and pushes a new one
2644// with the offset applied and narrowed.
2645template <PrimType Name, class T = typename PrimConv<Name>::T>
2646inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2647 const T &Offset = S.Stk.pop<T>();
2648 const Pointer &Ptr = S.Stk.peek<Pointer>();
2649
2650 if (!Ptr.isZero() && !Offset.isZero()) {
2651 if (!CheckArray(S, OpPC, Ptr))
2652 return false;
2653 }
2654
2655 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2656 return false;
2657
2658 return NarrowPtr(S, OpPC);
2659}
2660
2661template <PrimType Name, class T = typename PrimConv<Name>::T>
2662inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2663 const T &Offset = S.Stk.pop<T>();
2664 const Pointer &Ptr = S.Stk.pop<Pointer>();
2665
2666 if (!Ptr.isZero() && !Offset.isZero()) {
2667 if (!CheckArray(S, OpPC, Ptr))
2668 return false;
2669 }
2670
2671 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2672 return false;
2673
2674 return NarrowPtr(S, OpPC);
2675}
2676
2677template <PrimType Name, class T = typename PrimConv<Name>::T>
2678inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2679 const Pointer &Ptr = S.Stk.peek<Pointer>();
2680
2681 if (!CheckLoad(S, OpPC, Ptr))
2682 return false;
2683
2684 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2685 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2686 return true;
2687}
2688
2689template <PrimType Name, class T = typename PrimConv<Name>::T>
2690inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2691 const Pointer &Ptr = S.Stk.pop<Pointer>();
2692
2693 if (!CheckLoad(S, OpPC, Ptr))
2694 return false;
2695
2696 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2697 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2698 return true;
2699}
2700
2701template <PrimType Name, class T = typename PrimConv<Name>::T>
2702inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2703 uint32_t DestIndex, uint32_t Size) {
2704 const auto &SrcPtr = S.Stk.pop<Pointer>();
2705 const auto &DestPtr = S.Stk.peek<Pointer>();
2706
2707 for (uint32_t I = 0; I != Size; ++I) {
2708 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2709
2710 if (!CheckLoad(S, OpPC, SP))
2711 return false;
2712
2713 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2714 DP.deref<T>() = SP.deref<T>();
2715 DP.initialize();
2716 }
2717 return true;
2718}
2719
2720/// Just takes a pointer and checks if it's an incomplete
2721/// array type.
2722inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2723 const Pointer &Ptr = S.Stk.pop<Pointer>();
2724
2725 if (Ptr.isZero()) {
2726 S.Stk.push<Pointer>(Ptr);
2727 return true;
2728 }
2729
2730 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2731 return false;
2732
2733 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
2734 S.Stk.push<Pointer>(Ptr.atIndex(0));
2735 return true;
2736 }
2737
2738 const SourceInfo &E = S.Current->getSource(OpPC);
2739 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2740
2741 return false;
2742}
2743
2744inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2745 assert(Func);
2746 S.Stk.push<FunctionPointer>(Func);
2747 return true;
2748}
2749
2750template <PrimType Name, class T = typename PrimConv<Name>::T>
2751inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2752 const T &IntVal = S.Stk.pop<T>();
2753
2754 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2755 return true;
2756}
2757
2758inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
2759 S.Stk.push<MemberPointer>(D);
2760 return true;
2761}
2762
2763inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2764 const auto &MP = S.Stk.pop<MemberPointer>();
2765
2766 S.Stk.push<Pointer>(MP.getBase());
2767 return true;
2768}
2769
2770inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2771 const auto &MP = S.Stk.pop<MemberPointer>();
2772
2773 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2774 const auto *Func = S.getContext().getOrCreateFunction(FD);
2775
2776 S.Stk.push<FunctionPointer>(Func);
2777 return true;
2778}
2779
2780/// Just emit a diagnostic. The expression that caused emission of this
2781/// op is not valid in a constant context.
2782inline bool Invalid(InterpState &S, CodePtr OpPC) {
2783 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2784 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2785 << S.Current->getRange(OpPC);
2786 return false;
2787}
2788
2789inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2790 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2791 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2792 << S.Current->getRange(OpPC);
2793 return false;
2794}
2795
2796/// Do nothing and just abort execution.
2797inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2798inline bool SideEffect(InterpState &S, CodePtr OpPC) {
2799 return S.noteSideEffect();
2800}
2801
2802/// Same here, but only for casts.
2803inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2804 bool Fatal) {
2805 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2806
2807 // FIXME: Support diagnosing other invalid cast kinds.
2808 if (Kind == CastKind::Reinterpret) {
2809 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2810 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2811 return !Fatal;
2812 }
2813 return false;
2814}
2815
2816inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
2817 bool InitializerFailed) {
2818 assert(DR);
2819
2820 if (InitializerFailed) {
2821 const SourceInfo &Loc = S.Current->getSource(OpPC);
2822 const auto *VD = cast<VarDecl>(DR->getDecl());
2823 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2824 S.Note(VD->getLocation(), diag::note_declared_at);
2825 return false;
2826 }
2827
2828 return CheckDeclRef(S, OpPC, DR);
2829}
2830
2832 if (S.inConstantContext()) {
2833 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2834 const Expr *E = S.Current->getExpr(OpPC);
2835 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2836 }
2837 return false;
2838}
2839
2840inline bool Assume(InterpState &S, CodePtr OpPC) {
2841 const auto Val = S.Stk.pop<Boolean>();
2842
2843 if (Val)
2844 return true;
2845
2846 // Else, diagnose.
2847 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2848 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2849 return false;
2850}
2851
2852template <PrimType Name, class T = typename PrimConv<Name>::T>
2853inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2854 llvm::SmallVector<int64_t> ArrayIndices;
2855 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2856 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2857
2858 int64_t Result;
2859 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2860 return false;
2861
2862 S.Stk.push<T>(T::from(Result));
2863
2864 return true;
2865}
2866
2867template <PrimType Name, class T = typename PrimConv<Name>::T>
2868inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2869 const T &Arg = S.Stk.peek<T>();
2870 if (!Arg.isZero())
2871 return true;
2872
2873 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2874 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2875
2876 return false;
2877}
2878
2879void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2880 const APSInt &Value);
2881
2882template <PrimType Name, class T = typename PrimConv<Name>::T>
2883inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2884 assert(ED);
2885 assert(!ED->isFixed());
2886 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2887
2888 if (S.inConstantContext())
2889 diagnoseEnumValue(S, OpPC, ED, Val);
2890 return true;
2891}
2892
2893/// OldPtr -> Integer -> NewPtr.
2894template <PrimType TIn, PrimType TOut>
2895inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2896 static_assert(isPtrType(TIn) && isPtrType(TOut));
2897 using FromT = typename PrimConv<TIn>::T;
2898 using ToT = typename PrimConv<TOut>::T;
2899
2900 const FromT &OldPtr = S.Stk.pop<FromT>();
2901
2902 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2903 std::is_same_v<ToT, Pointer>) {
2904 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2905 return true;
2906 } else if constexpr (std::is_same_v<FromT, Pointer> &&
2907 std::is_same_v<ToT, FunctionPointer>) {
2908 if (OldPtr.isFunctionPointer()) {
2909 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2910 OldPtr.getByteOffset());
2911 return true;
2912 }
2913 }
2914
2915 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2916 return true;
2917}
2918
2919inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2920 // An expression E is a core constant expression unless the evaluation of E
2921 // would evaluate one of the following: [C++23] - a control flow that passes
2922 // through a declaration of a variable with static or thread storage duration
2923 // unless that variable is usable in constant expressions.
2924 assert(VD->isLocalVarDecl() &&
2925 VD->isStaticLocal()); // Checked before emitting this.
2926
2927 if (VD == S.EvaluatingDecl)
2928 return true;
2929
2931 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2932 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2933 return false;
2934 }
2935 return true;
2936}
2937
2938inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2939 assert(Desc);
2940
2941 if (!CheckDynamicMemoryAllocation(S, OpPC))
2942 return false;
2943
2944 DynamicAllocator &Allocator = S.getAllocator();
2945 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2947 assert(B);
2948
2949 S.Stk.push<Pointer>(B);
2950
2951 return true;
2952}
2953
2954template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2955inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2956 bool IsNoThrow) {
2957 if (!CheckDynamicMemoryAllocation(S, OpPC))
2958 return false;
2959
2960 SizeT NumElements = S.Stk.pop<SizeT>();
2961 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2962 if (!IsNoThrow)
2963 return false;
2964
2965 // If this failed and is nothrow, just return a null ptr.
2966 S.Stk.push<Pointer>(0, nullptr);
2967 return true;
2968 }
2969
2970 DynamicAllocator &Allocator = S.getAllocator();
2971 Block *B =
2972 Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2973 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
2974 assert(B);
2975 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2976
2977 return true;
2978}
2979
2980template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2981inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2982 bool IsNoThrow) {
2983 if (!CheckDynamicMemoryAllocation(S, OpPC))
2984 return false;
2985
2986 SizeT NumElements = S.Stk.pop<SizeT>();
2987 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2988 IsNoThrow)) {
2989 if (!IsNoThrow)
2990 return false;
2991
2992 // If this failed and is nothrow, just return a null ptr.
2993 S.Stk.push<Pointer>(0, ElementDesc);
2994 return true;
2995 }
2996
2997 DynamicAllocator &Allocator = S.getAllocator();
2998 Block *B =
2999 Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
3000 S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
3001 assert(B);
3002
3003 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
3004
3005 return true;
3006}
3007
3008bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
3009 bool IsGlobalDelete);
3010
3011static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
3012 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
3013 return true;
3014}
3015
3016static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
3017 return S.maybeDiagnoseDanglingAllocations();
3018}
3019
3020/// Check if the initializer and storage types of a placement-new expression
3021/// match.
3022bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
3023 std::optional<uint64_t> ArraySize = std::nullopt);
3024
3025template <PrimType Name, class T = typename PrimConv<Name>::T>
3027 const auto &Size = S.Stk.pop<T>();
3028 return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
3029}
3030bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
3031
3032template <PrimType Name, class T = typename PrimConv<Name>::T>
3033inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3034 uint32_t ResultBitWidth,
3035 const llvm::fltSemantics *Sem) {
3036 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3037
3038 if (!CheckLoad(S, OpPC, FromPtr))
3039 return false;
3040
3041 if constexpr (std::is_same_v<T, Pointer>) {
3042 // The only pointer type we can validly bitcast to is nullptr_t.
3043 S.Stk.push<Pointer>();
3044 return true;
3045 } else {
3046
3047 size_t BuffSize = ResultBitWidth / 8;
3048 llvm::SmallVector<std::byte> Buff(BuffSize);
3049 bool HasIndeterminateBits = false;
3050
3051 Bits FullBitWidth(ResultBitWidth);
3052 Bits BitWidth = FullBitWidth;
3053
3054 if constexpr (std::is_same_v<T, Floating>) {
3055 assert(Sem);
3056 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3057 }
3058
3059 if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3060 HasIndeterminateBits))
3061 return false;
3062
3063 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3064 return false;
3065
3066 if constexpr (std::is_same_v<T, Floating>) {
3067 assert(Sem);
3068 S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3069 } else {
3070 assert(!Sem);
3071 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3072 }
3073 return true;
3074 }
3075}
3076
3077inline bool BitCast(InterpState &S, CodePtr OpPC) {
3078 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3079 Pointer &ToPtr = S.Stk.peek<Pointer>();
3080
3081 if (!CheckLoad(S, OpPC, FromPtr))
3082 return false;
3083
3084 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3085 return false;
3086
3087 return true;
3088}
3089
3090//===----------------------------------------------------------------------===//
3091// Read opcode arguments
3092//===----------------------------------------------------------------------===//
3093
3094template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3095 if constexpr (std::is_pointer<T>::value) {
3096 uint32_t ID = OpPC.read<uint32_t>();
3097 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3098 } else {
3099 return OpPC.read<T>();
3100 }
3101}
3102
3103template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3105 OpPC += align(F.bytesToSerialize());
3106 return F;
3107}
3108
3109template <>
3110inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3111 CodePtr &OpPC) {
3112 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3113 OpPC += align(I.bytesToSerialize());
3114 return I;
3115}
3116
3117template <>
3118inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3119 CodePtr &OpPC) {
3120 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3121 OpPC += align(I.bytesToSerialize());
3122 return I;
3123}
3124
3125} // namespace interp
3126} // namespace clang
3127
3128#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3443
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:3847
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
Definition: Decl.h:4061
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:277
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:3247
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3148
Expr * getTemporaryExpr()
Retrieve the expression to which the temporary materialization conversion was applied.
Definition: DeclCXX.h:3293
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:4148
ASTContext & getASTContext() const
Definition: Sema.h:531
const LangOptions & getLangOpts() const
Definition: Sema.h:524
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
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:80
Wrapper around boolean types.
Definition: Boolean.h:25
static Boolean from(T Value)
Definition: Boolean.h:103
Pointer into the code segment.
Definition: Source.h:30
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:60
Manages dynamic memory allocations done during bytecode interpretation.
Wrapper around fixed point types.
Definition: FixedPoint.h:23
llvm::FixedPointSemantics getSemantics() const
Definition: FixedPoint.h:71
static bool shiftRight(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
Definition: FixedPoint.h:132
static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
Definition: FixedPoint.h:125
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
Definition: FixedPoint.h:40
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:205
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:158
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:186
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:179
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:119
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
size_t bytesToSerialize() const
Definition: Floating.h:144
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:173
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:199
bool isNonZero() const
Definition: Floating.h:92
bool isFinite() const
Definition: Floating.h:98
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:192
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition: Floating.h:50
const Function * getFunction() const
ComparisonCategoryResult compare(const FunctionPointer &RHS) const
std::string toDiagnosticString(const ASTContext &Ctx) const
Bytecode function.
Definition: Function.h:81
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:300
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:118
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
Wrapper around numeric types.
Definition: Integral.h:66
Frame storing local variables.
Definition: InterpFrame.h:26
Interpreter context.
Definition: InterpState.h:36
ComparisonCategoryResult compare(const MemberPointer &RHS) const
A pointer to a memory block, live or dead.
Definition: Pointer.h:83
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:444
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:185
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:440
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:320
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:151
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:544
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:178
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:485
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:589
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:170
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:642
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:580
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:417
void activate() const
Activats a field.
Definition: Pointer.cpp:404
bool isIntegralPointer() const
Definition: Pointer.h:468
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:394
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:399
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:571
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:310
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:261
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:676
const IntPointer & asIntPointer() const
Definition: Pointer.h:458
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:439
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:284
unsigned getOffset() const
Returns the offset into an array.
Definition: Pointer.h:376
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:607
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:138
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:227
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:630
bool isBlockPointer() const
Definition: Pointer.h:467
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:462
const Block * block() const
Definition: Pointer.h:586
bool isFunctionPointer() const
Definition: Pointer.h:469
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:329
size_t elemSize() const
Returns the element size of the innermost field.
Definition: Pointer.h:358
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:447
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:454
void initialize() const
Initializes a field.
Definition: Pointer.cpp:356
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:2575
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1557
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1842
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2556
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:2690
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1653
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1570
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2678
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1179
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1559
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:671
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition: Interp.h:2276
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2763
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:2625
llvm::APInt APInt
Definition: FixedPoint.h:19
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
Definition: Interp.h:1673
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1448
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3103
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:890
bool SideEffect(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2798
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2418
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1271
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:1882
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1798
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Offset)
Checks if the dowcast using the given offset is possible with the given pointer.
Definition: Interp.cpp:446
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
Definition: Interp.cpp:844
bool BitCast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:3077
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1759
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
Definition: Interp.h:2424
static llvm::RoundingMode getRoundingMode(FPOptions FPO)
Definition: Interp.h:409
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2094
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
Definition: Interp.cpp:896
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1212
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:750
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:761
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1302
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2868
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:2070
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1509
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:2919
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition: Interp.cpp:1541
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.h:1529
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:674
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:494
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2744
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:1608
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:2116
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:435
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1522
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
Definition: Interp.cpp:1520
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:2646
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1157
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2615
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2751
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:589
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2413
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)
Definition: Interp.h:3033
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2566
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2468
llvm::FixedPointSemantics FixedPointSemantics
Definition: Interp.h:43
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:533
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2314
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:1937
bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:914
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2062
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:2224
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2631
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:779
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1770
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:2662
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2445
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2172
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition: Interp.cpp:835
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...
Definition: Interp.h:1484
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:3094
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:2246
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2722
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition: Interp.cpp:618
bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...
Definition: Interp.h:1429
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:767
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
Definition: Interp.cpp:1581
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:2853
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:603
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:176
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
Definition: Interp.h:164
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2342
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition: Interp.cpp:1101
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1171
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:34
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.h:3026
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2408
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:2789
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
Definition: Interp.h:2816
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:643
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:404
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr)
Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.
Definition: Interp.cpp:872
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status, FPOptions FPO)
Checks if the result of a floating-point operation is valid in the current context.
Definition: Interp.cpp:788
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:2190
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:1813
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1176
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2103
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
Definition: Interp.h:3016
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2938
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.cpp:1533
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1914
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2325
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:1712
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:1430
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
Definition: Interp.h:2758
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1707
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2831
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition: Interp.h:2381
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.cpp:1126
bool IsNonNull(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2433
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1585
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1595
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:298
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:559
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1621
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
Definition: Interp.cpp:922
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1634
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1280
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:901
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2770
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:2359
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:2895
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1723
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1784
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:1698
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition: Interp.h:2292
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:447
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
Definition: Interp.h:2481
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:1857
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2167
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:1494
bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID)
Definition: Interp.cpp:1361
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition: Interp.cpp:1008
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.cpp:1483
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:1689
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:1748
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1390
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2181
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1126
bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition: Interp.h:898
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops a pointer from the stack 2) Pushes the value of the pointer's field on the stack
Definition: Interp.h:1320
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1084
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:679
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2052
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:1904
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:1387
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1014
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2368
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:74
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1287
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
Definition: Interp.h:2231
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:943
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:466
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition: Interp.h:2198
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1514
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
Definition: Interp.h:2981
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1363
bool Interpret(InterpState &S)
Interpreter entry point.
Definition: Interp.cpp:1602
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:1732
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:2803
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1922
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:2217
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:2840
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:659
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1679
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:3011
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition: Interp.h:2955
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition: Interp.h:2883
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:680
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:653
const Descriptor * Desc
Definition: Pointer.h:45
Mapping from primitive types to their representation.
Definition: PrimType.h:77