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