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