clang 23.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"
24#include "InterpFrame.h"
25#include "InterpHelpers.h"
26#include "InterpStack.h"
27#include "InterpState.h"
28#include "MemberPointer.h"
29#include "PrimType.h"
30#include "Program.h"
31#include "State.h"
33#include "clang/AST/Expr.h"
34#include "llvm/ADT/APFloat.h"
35#include "llvm/ADT/APSInt.h"
36#include "llvm/ADT/ScopeExit.h"
37#include <type_traits>
38
39// preserve_none is supported on aarch64, but causes problems when asan is
40// enabled. See https://github.com/llvm/llvm-project/issues/177519.
41#if !defined(__aarch64__) && !defined(__i386__) && \
42 __has_cpp_attribute(clang::preserve_none)
43#define PRESERVE_NONE [[clang::preserve_none]]
44#else
45#define PRESERVE_NONE
46#endif
47
48namespace clang {
49namespace interp {
50
51using APSInt = llvm::APSInt;
52using FixedPointSemantics = llvm::FixedPointSemantics;
53
54/// Checks if the variable has externally defined storage.
55bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
56
57/// Checks if a pointer is null.
58bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60
61/// Checks if Ptr is a one-past-the-end pointer.
62bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64
65/// Checks if the dowcast using the given offset is possible with the given
66/// pointer.
67bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 uint32_t Offset);
69
70/// Checks if a pointer points to const storage.
71bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
72
73/// Checks if the Descriptor is of a constexpr or const global variable.
74bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
75
76bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
77
78bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
79 AccessKinds AK);
80bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
81 const Descriptor *Desc, AccessKinds AK);
82
83/// Checks a direct load of a primitive value from a global or local variable.
84bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
85bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);
86
87/// Checks if a value can be stored in a block.
88bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
89 bool WillBeActivated = false);
90
91/// Checks if a value can be initialized.
92bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93
94/// Checks the 'this' pointer.
95bool CheckThis(InterpState &S, CodePtr OpPC);
96
97/// Checks if dynamic memory allocation is available in the current
98/// language mode.
100
101/// Check the source of the pointer passed to delete/delete[] has actually
102/// been heap allocated by us.
103bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
104 const Pointer &Ptr);
105
106bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
107 AccessKinds AK, bool WillActivate = false);
108
109/// Sets the given integral value to the pointer, which is of
110/// a std::{weak,partial,strong}_ordering type.
112 const Pointer &Ptr, const APSInt &IntValue);
113
114bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
115 uint32_t VarArgSize);
116bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
117 uint32_t VarArgSize);
118bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
119 uint32_t VarArgSize);
120bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
121 uint32_t BuiltinID);
122bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
123 const CallExpr *CE);
124bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
125bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
126bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
127 bool TargetIsUCharOrByte);
128bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
129bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
130bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD);
131bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
132 bool SrcIsVoidPtr);
133bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal);
134
136 const FixedPoint &FP);
137
138bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I);
139bool isConstexprUnknown(const Pointer &P);
140
141enum class ShiftDir { Left, Right };
142
143/// Checks if the shift operation is legal.
144template <ShiftDir Dir, typename LT, typename RT>
145bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
146 unsigned Bits) {
147 if (RHS.isNegative()) {
148 const SourceInfo &Loc = S.Current->getSource(OpPC);
149 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
150 if (!S.noteUndefinedBehavior())
151 return false;
152 }
153
154 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
155 // the shifted type.
156 if (Bits > 1 && RHS >= Bits) {
157 const Expr *E = S.Current->getExpr(OpPC);
158 const APSInt Val = RHS.toAPSInt();
159 QualType Ty = E->getType();
160 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
161 if (!S.noteUndefinedBehavior())
162 return false;
163 }
164
165 if constexpr (Dir == ShiftDir::Left) {
166 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
167 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
168 // operand, and must not overflow the corresponding unsigned type.
169 if (LHS.isNegative()) {
170 const Expr *E = S.Current->getExpr(OpPC);
171 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
172 if (!S.noteUndefinedBehavior())
173 return false;
174 } else if (LHS.toUnsigned().countLeadingZeros() <
175 static_cast<unsigned>(RHS)) {
176 const Expr *E = S.Current->getExpr(OpPC);
177 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
178 if (!S.noteUndefinedBehavior())
179 return false;
180 }
181 }
182 }
183
184 // C++2a [expr.shift]p2: [P0907R4]:
185 // E1 << E2 is the unique value congruent to
186 // E1 x 2^E2 module 2^N.
187 return true;
188}
189
190/// Checks if Div/Rem operation on LHS and RHS is valid.
191template <typename T>
192bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
193 if (RHS.isZero()) {
194 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
195 if constexpr (std::is_same_v<T, Floating>) {
196 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
197 << Op->getRHS()->getSourceRange();
198 return true;
199 }
200
201 S.FFDiag(Op, diag::note_expr_divide_by_zero)
202 << Op->getRHS()->getSourceRange();
203 return false;
204 }
205
206 if constexpr (!std::is_same_v<T, FixedPoint>) {
207 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
208 APSInt LHSInt = LHS.toAPSInt();
209 SmallString<32> Trunc;
210 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
211 const SourceInfo &Loc = S.Current->getSource(OpPC);
212 const Expr *E = S.Current->getExpr(OpPC);
213 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
214 return false;
215 }
216 }
217 return true;
218}
219
220/// Checks if the result of a floating-point operation is valid
221/// in the current context.
222bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
223 APFloat::opStatus Status, FPOptions FPO);
224
225/// Checks why the given DeclRefExpr is invalid.
226bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
227bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
228 bool InitializerFailed);
229
230/// DerivedToBaseMemberPointer
231bool CastMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off,
232 const RecordDecl *BaseDecl);
233/// BaseToDerivedMemberPointer
234bool CastMemberPtrDerivedPop(InterpState &S, CodePtr OpPC, int32_t Off,
235 const RecordDecl *BaseDecl);
236enum class ArithOp { Add, Sub };
237
238//===----------------------------------------------------------------------===//
239// Returning values
240//===----------------------------------------------------------------------===//
241
242void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
243 const Function *Func);
244
245template <PrimType Name, class T = typename PrimConv<Name>::T>
247 const T &Ret = S.Stk.pop<T>();
248
249 assert(S.Current);
250 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
253
254 if (InterpFrame *Caller = S.Current->Caller) {
255 PC = S.Current->getRetPC();
257 S.Current = Caller;
258 S.Stk.push<T>(Ret);
259 } else {
261 S.Current = nullptr;
262 // The topmost frame should come from an EvalEmitter,
263 // which has its own implementation of the Ret<> instruction.
264 }
265
266 return true;
267}
268
270 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
271
274
275 if (InterpFrame *Caller = S.Current->Caller) {
276 PC = S.Current->getRetPC();
278 S.Current = Caller;
279 } else {
281 S.Current = nullptr;
282 }
283
284 return true;
285}
286
287//===----------------------------------------------------------------------===//
288// Add, Sub, Mul
289//===----------------------------------------------------------------------===//
290
291template <typename T, bool (*OpFW)(T, T, unsigned, T *),
292 template <typename U> class OpAP>
293bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
294 const T &RHS) {
295 // Fast path - add the numbers with fixed width.
296 T Result;
297 if constexpr (needsAlloc<T>())
298 Result = S.allocAP<T>(LHS.bitWidth());
299
300 if (!OpFW(LHS, RHS, Bits, &Result)) {
301 S.Stk.push<T>(Result);
302 return true;
303 }
304 // If for some reason evaluation continues, use the truncated results.
305 S.Stk.push<T>(Result);
306
307 // Short-circuit fixed-points here since the error handling is easier.
308 if constexpr (std::is_same_v<T, FixedPoint>)
309 return handleFixedPointOverflow(S, OpPC, Result);
310
311 // If wrapping is enabled, the new value is fine.
312 if (S.Current->getExpr(OpPC)->getType().isWrapType())
313 return true;
314
315 // Slow path - compute the result using another bit of precision.
316 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
317
318 // Report undefined behaviour, stopping if required.
320 const Expr *E = S.Current->getExpr(OpPC);
321 QualType Type = E->getType();
322 SmallString<32> Trunc;
323 Value.trunc(Result.bitWidth())
324 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
325 /*UpperCase=*/true, /*InsertSeparators=*/true);
326 S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
327 << Trunc << Type << E->getSourceRange();
328 }
329
330 if (!handleOverflow(S, OpPC, Value)) {
331 S.Stk.pop<T>();
332 return false;
333 }
334 return true;
335}
336
337template <PrimType Name, class T = typename PrimConv<Name>::T>
338bool Add(InterpState &S, CodePtr OpPC) {
339 const T &RHS = S.Stk.pop<T>();
340 const T &LHS = S.Stk.pop<T>();
341 const unsigned Bits = RHS.bitWidth() + 1;
342
343 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
344}
345
346inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
347 const Floating &RHS = S.Stk.pop<Floating>();
348 const Floating &LHS = S.Stk.pop<Floating>();
349
351 Floating Result = S.allocFloat(LHS.getSemantics());
352 auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
354 return CheckFloatResult(S, OpPC, Result, Status, FPO);
355}
356
357template <PrimType Name, class T = typename PrimConv<Name>::T>
358bool Sub(InterpState &S, CodePtr OpPC) {
359 const T &RHS = S.Stk.pop<T>();
360 const T &LHS = S.Stk.pop<T>();
361 const unsigned Bits = RHS.bitWidth() + 1;
362
363 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
364}
365
366inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
367 const Floating &RHS = S.Stk.pop<Floating>();
368 const Floating &LHS = S.Stk.pop<Floating>();
369
371 Floating Result = S.allocFloat(LHS.getSemantics());
372 auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
374 return CheckFloatResult(S, OpPC, Result, Status, FPO);
375}
376
377template <PrimType Name, class T = typename PrimConv<Name>::T>
378bool Mul(InterpState &S, CodePtr OpPC) {
379 const T &RHS = S.Stk.pop<T>();
380 const T &LHS = S.Stk.pop<T>();
381 const unsigned Bits = RHS.bitWidth() * 2;
382
383 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
384}
385
386inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
387 const Floating &RHS = S.Stk.pop<Floating>();
388 const Floating &LHS = S.Stk.pop<Floating>();
389
391 Floating Result = S.allocFloat(LHS.getSemantics());
392
393 auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
394
396 return CheckFloatResult(S, OpPC, Result, Status, FPO);
397}
398
399template <PrimType Name, class T = typename PrimConv<Name>::T>
400inline bool Mulc(InterpState &S, CodePtr OpPC) {
401 const Pointer &RHS = S.Stk.pop<Pointer>();
402 const Pointer &LHS = S.Stk.pop<Pointer>();
403 const Pointer &Result = S.Stk.peek<Pointer>();
404
405 if constexpr (std::is_same_v<T, Floating>) {
406 APFloat A = LHS.elem<Floating>(0).getAPFloat();
407 APFloat B = LHS.elem<Floating>(1).getAPFloat();
408 APFloat C = RHS.elem<Floating>(0).getAPFloat();
409 APFloat D = RHS.elem<Floating>(1).getAPFloat();
410
411 APFloat ResR(A.getSemantics());
412 APFloat ResI(A.getSemantics());
413 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
414
415 // Copy into the result.
416 Floating RA = S.allocFloat(A.getSemantics());
417 RA.copy(ResR);
418 Result.elem<Floating>(0) = RA; // Floating(ResR);
419
420 Floating RI = S.allocFloat(A.getSemantics());
421 RI.copy(ResI);
422 Result.elem<Floating>(1) = RI; // Floating(ResI);
423 Result.initializeAllElements();
424 } else {
425 // Integer element type.
426 const T &LHSR = LHS.elem<T>(0);
427 const T &LHSI = LHS.elem<T>(1);
428 const T &RHSR = RHS.elem<T>(0);
429 const T &RHSI = RHS.elem<T>(1);
430 unsigned Bits = LHSR.bitWidth();
431
432 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
433 T A;
434 if constexpr (needsAlloc<T>())
435 A = S.allocAP<T>(Bits);
436 if (T::mul(LHSR, RHSR, Bits, &A))
437 return false;
438
439 T B;
440 if constexpr (needsAlloc<T>())
441 B = S.allocAP<T>(Bits);
442 if (T::mul(LHSI, RHSI, Bits, &B))
443 return false;
444
445 if constexpr (needsAlloc<T>())
446 Result.elem<T>(0) = S.allocAP<T>(Bits);
447 if (T::sub(A, B, Bits, &Result.elem<T>(0)))
448 return false;
449
450 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
451 if (T::mul(LHSR, RHSI, Bits, &A))
452 return false;
453 if (T::mul(LHSI, RHSR, Bits, &B))
454 return false;
455
456 if constexpr (needsAlloc<T>())
457 Result.elem<T>(1) = S.allocAP<T>(Bits);
458 if (T::add(A, B, Bits, &Result.elem<T>(1)))
459 return false;
460 Result.initialize();
461 Result.initializeAllElements();
462 }
463
464 return true;
465}
466
467template <PrimType Name, class T = typename PrimConv<Name>::T>
468inline bool Divc(InterpState &S, CodePtr OpPC) {
469 const Pointer &RHS = S.Stk.pop<Pointer>();
470 const Pointer &LHS = S.Stk.pop<Pointer>();
471 const Pointer &Result = S.Stk.peek<Pointer>();
472
473 if constexpr (std::is_same_v<T, Floating>) {
474 APFloat A = LHS.elem<Floating>(0).getAPFloat();
475 APFloat B = LHS.elem<Floating>(1).getAPFloat();
476 APFloat C = RHS.elem<Floating>(0).getAPFloat();
477 APFloat D = RHS.elem<Floating>(1).getAPFloat();
478
479 APFloat ResR(A.getSemantics());
480 APFloat ResI(A.getSemantics());
481 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
482
483 // Copy into the result.
484 Floating RA = S.allocFloat(A.getSemantics());
485 RA.copy(ResR);
486 Result.elem<Floating>(0) = RA; // Floating(ResR);
487
488 Floating RI = S.allocFloat(A.getSemantics());
489 RI.copy(ResI);
490 Result.elem<Floating>(1) = RI; // Floating(ResI);
491
492 Result.initializeAllElements();
493 } else {
494 // Integer element type.
495 const T &LHSR = LHS.elem<T>(0);
496 const T &LHSI = LHS.elem<T>(1);
497 const T &RHSR = RHS.elem<T>(0);
498 const T &RHSI = RHS.elem<T>(1);
499 unsigned Bits = LHSR.bitWidth();
500
501 if (RHSR.isZero() && RHSI.isZero()) {
502 const SourceInfo &E = S.Current->getSource(OpPC);
503 S.FFDiag(E, diag::note_expr_divide_by_zero);
504 return false;
505 }
506
507 // Den = real(RHS)² + imag(RHS)²
508 T A, B;
509 if constexpr (needsAlloc<T>()) {
510 A = S.allocAP<T>(Bits);
511 B = S.allocAP<T>(Bits);
512 }
513
514 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
515 // Ignore overflow here, because that's what the current interpeter does.
516 }
517 T Den;
518 if constexpr (needsAlloc<T>())
519 Den = S.allocAP<T>(Bits);
520
521 if (T::add(A, B, Bits, &Den))
522 return false;
523
524 if (Den.isZero()) {
525 const SourceInfo &E = S.Current->getSource(OpPC);
526 S.FFDiag(E, diag::note_expr_divide_by_zero);
527 return false;
528 }
529
530 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
531 T &ResultR = Result.elem<T>(0);
532 T &ResultI = Result.elem<T>(1);
533 if constexpr (needsAlloc<T>()) {
534 ResultR = S.allocAP<T>(Bits);
535 ResultI = S.allocAP<T>(Bits);
536 }
537 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
538 return false;
539 if (T::add(A, B, Bits, &ResultR))
540 return false;
541 if (T::div(ResultR, Den, Bits, &ResultR))
542 return false;
543
544 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
545 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
546 return false;
547 if (T::sub(A, B, Bits, &ResultI))
548 return false;
549 if (T::div(ResultI, Den, Bits, &ResultI))
550 return false;
551 Result.initializeAllElements();
552 }
553
554 return true;
555}
556
557/// 1) Pops the RHS from the stack.
558/// 2) Pops the LHS from the stack.
559/// 3) Pushes 'LHS & RHS' on the stack
560template <PrimType Name, class T = typename PrimConv<Name>::T>
561bool BitAnd(InterpState &S, CodePtr OpPC) {
562 const T &RHS = S.Stk.pop<T>();
563 const T &LHS = S.Stk.pop<T>();
564 unsigned Bits = RHS.bitWidth();
565
566 T Result;
567 if constexpr (needsAlloc<T>())
568 Result = S.allocAP<T>(Bits);
569
570 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
571 S.Stk.push<T>(Result);
572 return true;
573 }
574 return false;
575}
576
577/// 1) Pops the RHS from the stack.
578/// 2) Pops the LHS from the stack.
579/// 3) Pushes 'LHS | RHS' on the stack
580template <PrimType Name, class T = typename PrimConv<Name>::T>
581bool BitOr(InterpState &S, CodePtr OpPC) {
582 const T &RHS = S.Stk.pop<T>();
583 const T &LHS = S.Stk.pop<T>();
584 unsigned Bits = RHS.bitWidth();
585
586 T Result;
587 if constexpr (needsAlloc<T>())
588 Result = S.allocAP<T>(Bits);
589
590 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
591 S.Stk.push<T>(Result);
592 return true;
593 }
594 return false;
595}
596
597/// 1) Pops the RHS from the stack.
598/// 2) Pops the LHS from the stack.
599/// 3) Pushes 'LHS ^ RHS' on the stack
600template <PrimType Name, class T = typename PrimConv<Name>::T>
601bool BitXor(InterpState &S, CodePtr OpPC) {
602 const T &RHS = S.Stk.pop<T>();
603 const T &LHS = S.Stk.pop<T>();
604
605 unsigned Bits = RHS.bitWidth();
606
607 T Result;
608 if constexpr (needsAlloc<T>())
609 Result = S.allocAP<T>(Bits);
610
611 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
612 S.Stk.push<T>(Result);
613 return true;
614 }
615 return false;
616}
617
618/// 1) Pops the RHS from the stack.
619/// 2) Pops the LHS from the stack.
620/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
621template <PrimType Name, class T = typename PrimConv<Name>::T>
622bool Rem(InterpState &S, CodePtr OpPC) {
623 const T &RHS = S.Stk.pop<T>();
624 const T &LHS = S.Stk.pop<T>();
625 const unsigned Bits = RHS.bitWidth() * 2;
626
627 if (!CheckDivRem(S, OpPC, LHS, RHS))
628 return false;
629
630 T Result;
631 if constexpr (needsAlloc<T>())
632 Result = S.allocAP<T>(LHS.bitWidth());
633
634 if (!T::rem(LHS, RHS, Bits, &Result)) {
635 S.Stk.push<T>(Result);
636 return true;
637 }
638 return false;
639}
640
641/// 1) Pops the RHS from the stack.
642/// 2) Pops the LHS from the stack.
643/// 3) Pushes 'LHS / RHS' on the stack
644template <PrimType Name, class T = typename PrimConv<Name>::T>
645bool Div(InterpState &S, CodePtr OpPC) {
646 const T &RHS = S.Stk.pop<T>();
647 const T &LHS = S.Stk.pop<T>();
648 const unsigned Bits = RHS.bitWidth() * 2;
649
650 if (!CheckDivRem(S, OpPC, LHS, RHS))
651 return false;
652
653 T Result;
654 if constexpr (needsAlloc<T>())
655 Result = S.allocAP<T>(LHS.bitWidth());
656
657 if (!T::div(LHS, RHS, Bits, &Result)) {
658 S.Stk.push<T>(Result);
659 return true;
660 }
661
662 if constexpr (std::is_same_v<T, FixedPoint>) {
663 if (handleFixedPointOverflow(S, OpPC, Result)) {
664 S.Stk.push<T>(Result);
665 return true;
666 }
667 }
668 return false;
669}
670
671inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
672 const Floating &RHS = S.Stk.pop<Floating>();
673 const Floating &LHS = S.Stk.pop<Floating>();
674
675 if (!CheckDivRem(S, OpPC, LHS, RHS))
676 return false;
677
679
680 Floating Result = S.allocFloat(LHS.getSemantics());
681 auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
682
684 return CheckFloatResult(S, OpPC, Result, Status, FPO);
685}
686
687//===----------------------------------------------------------------------===//
688// Inv
689//===----------------------------------------------------------------------===//
690
691inline bool Inv(InterpState &S, CodePtr OpPC) {
692 const auto &Val = S.Stk.pop<Boolean>();
693 S.Stk.push<Boolean>(!Val);
694 return true;
695}
696
697//===----------------------------------------------------------------------===//
698// Neg
699//===----------------------------------------------------------------------===//
700
701template <PrimType Name, class T = typename PrimConv<Name>::T>
702bool Neg(InterpState &S, CodePtr OpPC) {
703 const T &Value = S.Stk.pop<T>();
704
705 if constexpr (std::is_same_v<T, Floating>) {
706 T Result = S.allocFloat(Value.getSemantics());
707
708 if (!T::neg(Value, &Result)) {
709 S.Stk.push<T>(Result);
710 return true;
711 }
712 return false;
713 } else {
714 T Result;
715 if constexpr (needsAlloc<T>())
716 Result = S.allocAP<T>(Value.bitWidth());
717
718 if (!T::neg(Value, &Result)) {
719 S.Stk.push<T>(Result);
720 return true;
721 }
722
723 assert((isIntegerType(Name) || Name == PT_FixedPoint) &&
724 "don't expect other types to fail at constexpr negation");
725 S.Stk.push<T>(Result);
726
727 if (S.Current->getExpr(OpPC)->getType().isWrapType())
728 return true;
729
730 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
732 const Expr *E = S.Current->getExpr(OpPC);
733 QualType Type = E->getType();
734 SmallString<32> Trunc;
735 NegatedValue.trunc(Result.bitWidth())
736 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
737 /*UpperCase=*/true, /*InsertSeparators=*/true);
738 S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
739 << Trunc << Type << E->getSourceRange();
740 return true;
741 }
742
743 return handleOverflow(S, OpPC, NegatedValue);
744 }
745}
746
747enum class PushVal : bool {
750};
751enum class IncDecOp {
754};
755
756template <typename T, IncDecOp Op, PushVal DoPush>
757bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
758 bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {
759 assert(!Ptr.isDummy());
760
761 if (!S.inConstantContext()) {
762 if (isConstexprUnknown(Ptr))
763 return false;
764 }
765
766 if constexpr (std::is_same_v<T, Boolean>) {
767 if (!S.getLangOpts().CPlusPlus14)
768 return Invalid(S, OpPC);
769 }
770
771 const T &Value = Ptr.deref<T>();
772 T Result;
773 if constexpr (needsAlloc<T>())
774 Result = S.allocAP<T>(Value.bitWidth());
775
776 if constexpr (DoPush == PushVal::Yes)
777 S.Stk.push<T>(Value);
778
779 if constexpr (Op == IncDecOp::Inc) {
780 if (!T::increment(Value, &Result) || !CanOverflow) {
781 if (BitWidth)
782 Ptr.deref<T>() = Result.truncate(*BitWidth);
783 else
784 Ptr.deref<T>() = Result;
785 return true;
786 }
787 } else {
788 if (!T::decrement(Value, &Result) || !CanOverflow) {
789 if (BitWidth)
790 Ptr.deref<T>() = Result.truncate(*BitWidth);
791 else
792 Ptr.deref<T>() = Result;
793 return true;
794 }
795 }
796 assert(CanOverflow);
797
798 if (S.Current->getExpr(OpPC)->getType().isWrapType()) {
799 Ptr.deref<T>() = Result;
800 return true;
801 }
802
803 // Something went wrong with the previous operation. Compute the
804 // result with another bit of precision.
805 unsigned Bits = Value.bitWidth() + 1;
806 APSInt APResult;
807 if constexpr (Op == IncDecOp::Inc)
808 APResult = ++Value.toAPSInt(Bits);
809 else
810 APResult = --Value.toAPSInt(Bits);
811
812 // Report undefined behaviour, stopping if required.
814 const Expr *E = S.Current->getExpr(OpPC);
815 QualType Type = E->getType();
816 SmallString<32> Trunc;
817 APResult.trunc(Result.bitWidth())
818 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
819 /*UpperCase=*/true, /*InsertSeparators=*/true);
820 S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
821 << Trunc << Type << E->getSourceRange();
822 return true;
823 }
824 return handleOverflow(S, OpPC, APResult);
825}
826
827/// 1) Pops a pointer from the stack
828/// 2) Load the value from the pointer
829/// 3) Writes the value increased by one back to the pointer
830/// 4) Pushes the original (pre-inc) value on the stack.
831template <PrimType Name, class T = typename PrimConv<Name>::T>
832bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
833 const Pointer &Ptr = S.Stk.pop<Pointer>();
834 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
835 return false;
836 if (!CheckConst(S, OpPC, Ptr))
837 return false;
838
840 CanOverflow);
841}
842
843template <PrimType Name, class T = typename PrimConv<Name>::T>
844bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
845 unsigned BitWidth) {
846 const Pointer &Ptr = S.Stk.pop<Pointer>();
847 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
848 return false;
849 if (!CheckConst(S, OpPC, Ptr))
850 return false;
851
852 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
853 BitWidth);
854}
855
856/// 1) Pops a pointer from the stack
857/// 2) Load the value from the pointer
858/// 3) Writes the value increased by one back to the pointer
859template <PrimType Name, class T = typename PrimConv<Name>::T>
860bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
861 const Pointer &Ptr = S.Stk.pop<Pointer>();
862 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
863 return false;
864 if (!CheckConst(S, OpPC, Ptr))
865 return false;
866
867 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
868}
869
870template <PrimType Name, class T = typename PrimConv<Name>::T>
871bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
872 uint32_t BitWidth) {
873 const Pointer &Ptr = S.Stk.pop<Pointer>();
874 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
875 return false;
876 if (!CheckConst(S, OpPC, Ptr))
877 return false;
878
879 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
880 BitWidth);
881}
882
883template <PrimType Name, class T = typename PrimConv<Name>::T>
884bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
885 const Pointer &Ptr = S.Stk.peek<Pointer>();
886 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
887 return false;
888 if (!CheckConst(S, OpPC, Ptr))
889 return false;
890
891 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
892}
893
894template <PrimType Name, class T = typename PrimConv<Name>::T>
895bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
896 uint32_t BitWidth) {
897 const Pointer &Ptr = S.Stk.peek<Pointer>();
898 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
899 return false;
900 if (!CheckConst(S, OpPC, Ptr))
901 return false;
902
903 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
904 BitWidth);
905}
906
907/// 1) Pops a pointer from the stack
908/// 2) Load the value from the pointer
909/// 3) Writes the value decreased by one back to the pointer
910/// 4) Pushes the original (pre-dec) value on the stack.
911template <PrimType Name, class T = typename PrimConv<Name>::T>
912bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
913 const Pointer &Ptr = S.Stk.pop<Pointer>();
914 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
915 return false;
916 if (!CheckConst(S, OpPC, Ptr))
917 return false;
918
920 CanOverflow);
921}
922template <PrimType Name, class T = typename PrimConv<Name>::T>
923bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
924 uint32_t BitWidth) {
925 const Pointer &Ptr = S.Stk.pop<Pointer>();
926 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
927 return false;
928 if (!CheckConst(S, OpPC, Ptr))
929 return false;
930
931 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
932 BitWidth);
933}
934
935/// 1) Pops a pointer from the stack
936/// 2) Load the value from the pointer
937/// 3) Writes the value decreased by one back to the pointer
938template <PrimType Name, class T = typename PrimConv<Name>::T>
939bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
940 const Pointer &Ptr = S.Stk.pop<Pointer>();
941 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
942 return false;
943 if (!CheckConst(S, OpPC, Ptr))
944 return false;
945
946 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
947}
948
949template <PrimType Name, class T = typename PrimConv<Name>::T>
950bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
951 uint32_t BitWidth) {
952 const Pointer &Ptr = S.Stk.pop<Pointer>();
953 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
954 return false;
955 if (!CheckConst(S, OpPC, Ptr))
956 return false;
957
958 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
959 BitWidth);
960}
961
962template <PrimType Name, class T = typename PrimConv<Name>::T>
963bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
964 const Pointer &Ptr = S.Stk.peek<Pointer>();
965 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
966 return false;
967 if (!CheckConst(S, OpPC, Ptr))
968 return false;
969 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
970}
971
972template <PrimType Name, class T = typename PrimConv<Name>::T>
973bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
974 uint32_t BitWidth) {
975 const Pointer &Ptr = S.Stk.peek<Pointer>();
976 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
977 return false;
978 if (!CheckConst(S, OpPC, Ptr))
979 return false;
980 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
981 BitWidth);
982}
983
984template <IncDecOp Op, PushVal DoPush>
986 uint32_t FPOI) {
987 Floating Value = Ptr.deref<Floating>();
988 Floating Result = S.allocFloat(Value.getSemantics());
989
990 if constexpr (DoPush == PushVal::Yes)
992
994 llvm::APFloat::opStatus Status;
995 if constexpr (Op == IncDecOp::Inc)
997 else
999
1000 Ptr.deref<Floating>() = Result;
1001
1002 return CheckFloatResult(S, OpPC, Result, Status, FPO);
1003}
1004
1005inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1006 const Pointer &Ptr = S.Stk.pop<Pointer>();
1007 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
1008 return false;
1009 if (!CheckConst(S, OpPC, Ptr))
1010 return false;
1011
1012 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
1013}
1014
1015inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1016 const Pointer &Ptr = S.Stk.pop<Pointer>();
1017 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
1018 return false;
1019 if (!CheckConst(S, OpPC, Ptr))
1020 return false;
1021
1022 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
1023}
1024
1025inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1026 const Pointer &Ptr = S.Stk.pop<Pointer>();
1027 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
1028 return false;
1029 if (!CheckConst(S, OpPC, Ptr))
1030 return false;
1031
1032 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
1033}
1034
1035inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1036 const Pointer &Ptr = S.Stk.pop<Pointer>();
1037 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
1038 return false;
1039 if (!CheckConst(S, OpPC, Ptr))
1040 return false;
1041
1042 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
1043}
1044
1045/// 1) Pops the value from the stack.
1046/// 2) Pushes the bitwise complemented value on the stack (~V).
1047template <PrimType Name, class T = typename PrimConv<Name>::T>
1048bool Comp(InterpState &S, CodePtr OpPC) {
1049 const T &Val = S.Stk.pop<T>();
1050
1051 T Result;
1052 if constexpr (needsAlloc<T>())
1053 Result = S.allocAP<T>(Val.bitWidth());
1054
1055 if (!T::comp(Val, &Result)) {
1056 S.Stk.push<T>(Result);
1057 return true;
1058 }
1059 return false;
1060}
1061
1062//===----------------------------------------------------------------------===//
1063// EQ, NE, GT, GE, LT, LE
1064//===----------------------------------------------------------------------===//
1065
1066using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
1067
1068template <typename T>
1070 assert((!std::is_same_v<T, MemberPointer>) &&
1071 "Non-equality comparisons on member pointer types should already be "
1072 "rejected in Sema.");
1073 using BoolT = PrimConv<PT_Bool>::T;
1074 const T &RHS = S.Stk.pop<T>();
1075 const T &LHS = S.Stk.pop<T>();
1076 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
1077 return true;
1078}
1079
1080template <typename T>
1082 return CmpHelper<T>(S, OpPC, Fn);
1083}
1084
1085template <>
1087 using BoolT = PrimConv<PT_Bool>::T;
1088 const Pointer &RHS = S.Stk.pop<Pointer>();
1089 const Pointer &LHS = S.Stk.pop<Pointer>();
1090
1091 // Function pointers cannot be compared in an ordered way.
1092 if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||
1093 LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
1094 const SourceInfo &Loc = S.Current->getSource(OpPC);
1095 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1096 << LHS.toDiagnosticString(S.getASTContext())
1098 return false;
1099 }
1100
1101 if (!Pointer::hasSameBase(LHS, RHS)) {
1102 const SourceInfo &Loc = S.Current->getSource(OpPC);
1103 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1104 << LHS.toDiagnosticString(S.getASTContext())
1106 return false;
1107 }
1108
1109 // Diagnose comparisons between fields with different access specifiers.
1110 if (std::optional<std::pair<Pointer, Pointer>> Split =
1111 Pointer::computeSplitPoint(LHS, RHS)) {
1112 const FieldDecl *LF = Split->first.getField();
1113 const FieldDecl *RF = Split->second.getField();
1114 if (LF && RF && !LF->getParent()->isUnion() &&
1115 LF->getAccess() != RF->getAccess()) {
1116 S.CCEDiag(S.Current->getSource(OpPC),
1117 diag::note_constexpr_pointer_comparison_differing_access)
1118 << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();
1119 }
1120 }
1121
1122 unsigned VL = LHS.getByteOffset();
1123 unsigned VR = RHS.getByteOffset();
1124 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1125 return true;
1126}
1127
1128static inline bool IsOpaqueConstantCall(const CallExpr *E) {
1129 unsigned Builtin = E->getBuiltinCallee();
1130 return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1131 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1132 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1133 Builtin == Builtin::BI__builtin_function_start);
1134}
1135
1137 const Pointer &RHS);
1138
1139template <>
1141 using BoolT = PrimConv<PT_Bool>::T;
1142 const Pointer &RHS = S.Stk.pop<Pointer>();
1143 const Pointer &LHS = S.Stk.pop<Pointer>();
1144
1145 if (LHS.isZero() && RHS.isZero()) {
1146 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
1147 return true;
1148 }
1149
1150 // Reject comparisons to weak pointers.
1151 for (const auto &P : {LHS, RHS}) {
1152 if (P.isZero())
1153 continue;
1154 if (P.isWeak()) {
1155 const SourceInfo &Loc = S.Current->getSource(OpPC);
1156 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1157 << P.toDiagnosticString(S.getASTContext());
1158 return false;
1159 }
1160 }
1161
1162 if (!S.inConstantContext()) {
1163 if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))
1164 return false;
1165 }
1166
1167 if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {
1168 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(LHS.getIntegerRepresentation(),
1169 RHS.getIntegerRepresentation()))));
1170 return true;
1171 }
1172
1173 // FIXME: The source check here isn't entirely correct.
1174 if (LHS.pointsToStringLiteral() && RHS.pointsToStringLiteral() &&
1175 LHS.getFieldDesc()->asExpr() != RHS.getFieldDesc()->asExpr()) {
1177 const SourceInfo &Loc = S.Current->getSource(OpPC);
1178 S.FFDiag(Loc, diag::note_constexpr_literal_comparison)
1179 << LHS.toDiagnosticString(S.getASTContext())
1181 return false;
1182 }
1183 }
1184
1185 if (Pointer::hasSameBase(LHS, RHS)) {
1186 size_t A = LHS.computeOffsetForComparison(S.getASTContext());
1187 size_t B = RHS.computeOffsetForComparison(S.getASTContext());
1188
1189 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));
1190 return true;
1191 }
1192
1193 // Otherwise we need to do a bunch of extra checks before returning Unordered.
1194 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
1195 RHS.isBlockPointer() && RHS.getOffset() == 0) {
1196 const SourceInfo &Loc = S.Current->getSource(OpPC);
1197 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1198 << LHS.toDiagnosticString(S.getASTContext());
1199 return false;
1200 }
1201 if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1202 LHS.isBlockPointer() && LHS.getOffset() == 0) {
1203 const SourceInfo &Loc = S.Current->getSource(OpPC);
1204 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1206 return false;
1207 }
1208
1209 bool BothNonNull = !LHS.isZero() && !RHS.isZero();
1210 // Reject comparisons to literals.
1211 for (const auto &P : {LHS, RHS}) {
1212 if (P.isZero())
1213 continue;
1214 if (BothNonNull && P.pointsToLiteral()) {
1215 const Expr *E = P.getDeclDesc()->asExpr();
1216 if (isa<StringLiteral>(E)) {
1217 const SourceInfo &Loc = S.Current->getSource(OpPC);
1218 S.FFDiag(Loc, diag::note_constexpr_literal_comparison);
1219 return false;
1220 }
1221 if (const auto *CE = dyn_cast<CallExpr>(E);
1222 CE && IsOpaqueConstantCall(CE)) {
1223 const SourceInfo &Loc = S.Current->getSource(OpPC);
1224 S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
1225 << P.toDiagnosticString(S.getASTContext());
1226 return false;
1227 }
1228 } else if (BothNonNull && P.isIntegralPointer()) {
1229 const SourceInfo &Loc = S.Current->getSource(OpPC);
1230 S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
1231 << LHS.toDiagnosticString(S.getASTContext())
1233 return false;
1234 }
1235 }
1236
1237 if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
1238 const SourceInfo &Loc = S.Current->getSource(OpPC);
1239 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1240 << LHS.toDiagnosticString(S.getASTContext())
1242 return false;
1243 }
1244
1245 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1246 return true;
1247}
1248
1249template <>
1251 CompareFn Fn) {
1252 const auto &RHS = S.Stk.pop<MemberPointer>();
1253 const auto &LHS = S.Stk.pop<MemberPointer>();
1254
1255 // If either operand is a pointer to a weak function, the comparison is not
1256 // constant.
1257 for (const auto &MP : {LHS, RHS}) {
1258 if (MP.isWeak()) {
1259 const SourceInfo &Loc = S.Current->getSource(OpPC);
1260 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1261 << MP.getMemberFunction();
1262 return false;
1263 }
1264 }
1265
1266 // C++11 [expr.eq]p2:
1267 // If both operands are null, they compare equal. Otherwise if only one is
1268 // null, they compare unequal.
1269 if (LHS.isZero() && RHS.isZero()) {
1271 return true;
1272 }
1273 if (LHS.isZero() || RHS.isZero()) {
1275 return true;
1276 }
1277
1278 // We cannot compare against virtual declarations at compile time.
1279 for (const auto &MP : {LHS, RHS}) {
1280 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1281 MD && MD->isVirtual()) {
1282 const SourceInfo &Loc = S.Current->getSource(OpPC);
1283 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1284 }
1285 }
1286
1287 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1288 return true;
1289}
1290
1291template <PrimType Name, class T = typename PrimConv<Name>::T>
1292bool EQ(InterpState &S, CodePtr OpPC) {
1293 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1295 });
1296}
1297
1298template <PrimType Name, class T = typename PrimConv<Name>::T>
1299bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1300 const T &RHS = S.Stk.pop<T>();
1301 const T &LHS = S.Stk.pop<T>();
1302 const Pointer &P = S.Stk.peek<Pointer>();
1303
1304 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1305 if constexpr (std::is_same_v<T, Pointer>) {
1306 if (CmpResult == ComparisonCategoryResult::Unordered) {
1307 const SourceInfo &Loc = S.Current->getSource(OpPC);
1308 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1309 << LHS.toDiagnosticString(S.getASTContext())
1310 << RHS.toDiagnosticString(S.getASTContext());
1311 return false;
1312 }
1313 }
1314
1315 assert(CmpInfo);
1316 const auto *CmpValueInfo =
1317 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1318 assert(CmpValueInfo);
1319 assert(CmpValueInfo->hasValidIntValue());
1320 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1321}
1322
1323template <PrimType Name, class T = typename PrimConv<Name>::T>
1324bool NE(InterpState &S, CodePtr OpPC) {
1325 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1327 });
1328}
1329
1330template <PrimType Name, class T = typename PrimConv<Name>::T>
1331bool LT(InterpState &S, CodePtr OpPC) {
1332 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1334 });
1335}
1336
1337template <PrimType Name, class T = typename PrimConv<Name>::T>
1338bool LE(InterpState &S, CodePtr OpPC) {
1339 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1340 return R == ComparisonCategoryResult::Less ||
1342 });
1343}
1344
1345template <PrimType Name, class T = typename PrimConv<Name>::T>
1346bool GT(InterpState &S, CodePtr OpPC) {
1347 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1349 });
1350}
1351
1352template <PrimType Name, class T = typename PrimConv<Name>::T>
1353bool GE(InterpState &S, CodePtr OpPC) {
1354 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1357 });
1358}
1359
1360//===----------------------------------------------------------------------===//
1361// Dup, Pop, Test
1362//===----------------------------------------------------------------------===//
1363
1364template <PrimType Name, class T = typename PrimConv<Name>::T>
1365bool Dup(InterpState &S, CodePtr OpPC) {
1366 S.Stk.push<T>(S.Stk.peek<T>());
1367 return true;
1368}
1369
1370template <PrimType Name, class T = typename PrimConv<Name>::T>
1371bool Pop(InterpState &S, CodePtr OpPC) {
1372 S.Stk.discard<T>();
1373 return true;
1374}
1375
1376/// [Value1, Value2] -> [Value2, Value1]
1377template <PrimType TopName, PrimType BottomName>
1378bool Flip(InterpState &S, CodePtr OpPC) {
1379 using TopT = typename PrimConv<TopName>::T;
1380 using BottomT = typename PrimConv<BottomName>::T;
1381
1382 const auto &Top = S.Stk.pop<TopT>();
1383 const auto &Bottom = S.Stk.pop<BottomT>();
1384
1385 S.Stk.push<TopT>(Top);
1386 S.Stk.push<BottomT>(Bottom);
1387
1388 return true;
1389}
1390
1391//===----------------------------------------------------------------------===//
1392// Const
1393//===----------------------------------------------------------------------===//
1394
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1396bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1397 if constexpr (needsAlloc<T>()) {
1398 T Result = S.allocAP<T>(Arg.bitWidth());
1399 Result.copy(Arg.toAPSInt());
1400 S.Stk.push<T>(Result);
1401 return true;
1402 }
1403 S.Stk.push<T>(Arg);
1404 return true;
1405}
1406
1407inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
1409 Result.copy(F.getAPFloat());
1410 S.Stk.push<Floating>(Result);
1411 return true;
1412}
1413
1414//===----------------------------------------------------------------------===//
1415// Get/Set Local/Param/Global/This
1416//===----------------------------------------------------------------------===//
1417
1418template <PrimType Name, class T = typename PrimConv<Name>::T>
1419bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1420 const Block *B = S.Current->getLocalBlock(I);
1421 if (!CheckLocalLoad(S, OpPC, B))
1422 return false;
1423 S.Stk.push<T>(B->deref<T>());
1424 return true;
1425}
1426
1427bool EndLifetime(InterpState &S, CodePtr OpPC);
1428bool EndLifetimePop(InterpState &S, CodePtr OpPC);
1429bool StartLifetime(InterpState &S, CodePtr OpPC);
1430
1431/// 1) Pops the value from the stack.
1432/// 2) Writes the value to the local variable with the
1433/// given offset.
1434template <PrimType Name, class T = typename PrimConv<Name>::T>
1435bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1436 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1437 return true;
1438}
1439
1440template <PrimType Name, class T = typename PrimConv<Name>::T>
1441bool GetParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
1443 return false;
1444 }
1445 S.Stk.push<T>(S.Current->getParam<T>(Index));
1446 return true;
1447}
1448
1449template <PrimType Name, class T = typename PrimConv<Name>::T>
1450bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1451 S.Current->setParam<T>(I, S.Stk.pop<T>());
1452 return true;
1453}
1454
1455/// 1) Peeks a pointer on the stack
1456/// 2) Pushes the value of the pointer's field on the stack
1457template <PrimType Name, class T = typename PrimConv<Name>::T>
1458bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1459 const Pointer &Obj = S.Stk.peek<Pointer>();
1460 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1461 return false;
1462 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1463 return false;
1464 const Pointer &Field = Obj.atField(I);
1465 if (!CheckLoad(S, OpPC, Field))
1466 return false;
1467 S.Stk.push<T>(Field.deref<T>());
1468 return true;
1469}
1470
1471template <PrimType Name, class T = typename PrimConv<Name>::T>
1472bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1473 const T &Value = S.Stk.pop<T>();
1474 const Pointer &Obj = S.Stk.peek<Pointer>();
1475 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1476 return false;
1477 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1478 return false;
1479 const Pointer &Field = Obj.atField(I);
1480 if (!CheckStore(S, OpPC, Field))
1481 return false;
1482 Field.initialize();
1483 Field.deref<T>() = Value;
1484 return true;
1485}
1486
1487/// 1) Pops a pointer from the stack
1488/// 2) Pushes the value of the pointer's field on the stack
1489template <PrimType Name, class T = typename PrimConv<Name>::T>
1490bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1491 const Pointer &Obj = S.Stk.pop<Pointer>();
1492 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1493 return false;
1494 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1495 return false;
1496 const Pointer &Field = Obj.atField(I);
1497 if (!CheckLoad(S, OpPC, Field))
1498 return false;
1499 S.Stk.push<T>(Field.deref<T>());
1500 return true;
1501}
1502
1503template <PrimType Name, class T = typename PrimConv<Name>::T>
1504bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1506 return false;
1507 if (!CheckThis(S, OpPC))
1508 return false;
1509 const Pointer &This = S.Current->getThis();
1510 const Pointer &Field = This.atField(I);
1511 if (!CheckLoad(S, OpPC, Field))
1512 return false;
1513 S.Stk.push<T>(Field.deref<T>());
1514 return true;
1515}
1516
1517template <PrimType Name, class T = typename PrimConv<Name>::T>
1518bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1520 return false;
1521 if (!CheckThis(S, OpPC))
1522 return false;
1523 const T &Value = S.Stk.pop<T>();
1524 const Pointer &This = S.Current->getThis();
1525 const Pointer &Field = This.atField(I);
1526 if (!CheckStore(S, OpPC, Field))
1527 return false;
1528 Field.deref<T>() = Value;
1529 return true;
1530}
1531
1532template <PrimType Name, class T = typename PrimConv<Name>::T>
1533bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1534 const Block *B = S.P.getGlobal(I);
1535
1536 if (!CheckGlobalLoad(S, OpPC, B))
1537 return false;
1538
1539 S.Stk.push<T>(B->deref<T>());
1540 return true;
1541}
1542
1543/// Same as GetGlobal, but without the checks.
1544template <PrimType Name, class T = typename PrimConv<Name>::T>
1545bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1546 const Block *B = S.P.getGlobal(I);
1547 const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
1548 if (Desc.InitState != GlobalInitState::Initialized)
1549 return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
1550 AK_Read);
1551
1552 S.Stk.push<T>(B->deref<T>());
1553 return true;
1554}
1555
1556template <PrimType Name, class T = typename PrimConv<Name>::T>
1557bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1558 // TODO: emit warning.
1559 return false;
1560}
1561
1562template <PrimType Name, class T = typename PrimConv<Name>::T>
1563bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1564 const Pointer &P = S.P.getGlobal(I);
1565
1566 P.deref<T>() = S.Stk.pop<T>();
1567
1568 if constexpr (std::is_same_v<T, Floating>) {
1569 auto &Val = P.deref<Floating>();
1570 if (!Val.singleWord()) {
1571 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1572 Val.take(NewMemory);
1573 }
1574
1575 } else if constexpr (std::is_same_v<T, MemberPointer>) {
1576 auto &Val = P.deref<MemberPointer>();
1577 unsigned PathLength = Val.getPathLength();
1578 auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
1579 for (unsigned I = 0; I != PathLength; ++I) {
1580 NewPath[I] = Val.getPathEntry(I);
1581 }
1582 Val.takePath(NewPath);
1583 } else if constexpr (needsAlloc<T>()) {
1584 auto &Val = P.deref<T>();
1585 if (!Val.singleWord()) {
1586 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1587 Val.take(NewMemory);
1588 }
1589 }
1590
1591 P.initialize();
1592 return true;
1593}
1594
1595/// 1) Converts the value on top of the stack to an APValue
1596/// 2) Sets that APValue on \Temp
1597/// 3) Initializes global with index \I with that
1598template <PrimType Name, class T = typename PrimConv<Name>::T>
1599bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1600 const LifetimeExtendedTemporaryDecl *Temp) {
1602 return false;
1603 assert(Temp);
1604
1605 const Pointer &Ptr = S.P.getGlobal(I);
1606 assert(Ptr.getDeclDesc()->asExpr());
1607 S.SeenGlobalTemporaries.push_back(
1608 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1609
1610 Ptr.deref<T>() = S.Stk.pop<T>();
1611 Ptr.initialize();
1612 return true;
1613}
1614
1615/// 1) Converts the value on top of the stack to an APValue
1616/// 2) Sets that APValue on \Temp
1617/// 3) Initialized global with index \I with that
1619 const LifetimeExtendedTemporaryDecl *Temp) {
1621 return false;
1622 assert(Temp);
1623
1624 const Pointer &Ptr = S.Stk.peek<Pointer>();
1625 S.SeenGlobalTemporaries.push_back(
1626 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1627 return true;
1628}
1629
1630template <PrimType Name, class T = typename PrimConv<Name>::T>
1631bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1633 return false;
1634 if (!CheckThis(S, OpPC))
1635 return false;
1636 const Pointer &This = S.Current->getThis();
1637 const Pointer &Field = This.atField(I);
1638 assert(Field.canBeInitialized());
1639 Field.deref<T>() = S.Stk.pop<T>();
1640 Field.initialize();
1641 return true;
1642}
1643
1644template <PrimType Name, class T = typename PrimConv<Name>::T>
1645bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1647 return false;
1648 if (!CheckThis(S, OpPC))
1649 return false;
1650 const Pointer &This = S.Current->getThis();
1651 const Pointer &Field = This.atField(I);
1652 assert(Field.canBeInitialized());
1653 Field.deref<T>() = S.Stk.pop<T>();
1654 Field.activate();
1655 Field.initialize();
1656 return true;
1657}
1658
1659// FIXME: The Field pointer here is too much IMO and we could instead just
1660// pass an Offset + BitWidth pair.
1661template <PrimType Name, class T = typename PrimConv<Name>::T>
1663 uint32_t FieldOffset, // const Record::Field *F,
1664 uint32_t FieldBitWidth) {
1666 return false;
1667 if (!CheckThis(S, OpPC))
1668 return false;
1669 const Pointer &This = S.Current->getThis();
1670 const Pointer &Field = This.atField(FieldOffset);
1671 assert(Field.canBeInitialized());
1672 const auto &Value = S.Stk.pop<T>();
1673 Field.deref<T>() = Value.truncate(FieldBitWidth);
1674 Field.initialize();
1675 return true;
1676}
1677
1678template <PrimType Name, class T = typename PrimConv<Name>::T>
1680 uint32_t FieldOffset, uint32_t FieldBitWidth) {
1682 return false;
1683 if (!CheckThis(S, OpPC))
1684 return false;
1685 const Pointer &This = S.Current->getThis();
1686 const Pointer &Field = This.atField(FieldOffset);
1687 assert(Field.canBeInitialized());
1688 const auto &Value = S.Stk.pop<T>();
1689 Field.deref<T>() = Value.truncate(FieldBitWidth);
1690 Field.initialize();
1691 Field.activate();
1692 return true;
1693}
1694
1695/// 1) Pops the value from the stack
1696/// 2) Peeks a pointer from the stack
1697/// 3) Pushes the value to field I of the pointer on the stack
1698template <PrimType Name, class T = typename PrimConv<Name>::T>
1699bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1700 const T &Value = S.Stk.pop<T>();
1701 const Pointer &Ptr = S.Stk.peek<Pointer>();
1702 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1703 return false;
1704 if (!CheckArray(S, OpPC, Ptr))
1705 return false;
1706
1707 const Pointer &Field = Ptr.atField(I);
1708 Field.deref<T>() = Value;
1709 Field.initialize();
1710 return true;
1711}
1712
1713template <PrimType Name, class T = typename PrimConv<Name>::T>
1714bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1715 const T &Value = S.Stk.pop<T>();
1716 const Pointer &Ptr = S.Stk.peek<Pointer>();
1717 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1718 return false;
1719 if (!CheckArray(S, OpPC, Ptr))
1720 return false;
1721
1722 const Pointer &Field = Ptr.atField(I);
1723 Field.deref<T>() = Value;
1724 Field.activate();
1725 Field.initialize();
1726 return true;
1727}
1728
1729template <PrimType Name, class T = typename PrimConv<Name>::T>
1730bool InitBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
1731 uint32_t FieldBitWidth) {
1732 const T &Value = S.Stk.pop<T>();
1733 const Pointer &Ptr = S.Stk.peek<Pointer>();
1734 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1735 return false;
1736 if (!CheckArray(S, OpPC, Ptr))
1737 return false;
1738
1739 const Pointer &Field = Ptr.atField(FieldOffset);
1740
1741 unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
1742 if constexpr (needsAlloc<T>()) {
1743 T Result = S.allocAP<T>(Value.bitWidth());
1744 if constexpr (T::isSigned())
1745 Result.copy(
1746 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
1747 else
1748 Result.copy(
1749 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
1750
1751 Field.deref<T>() = Result;
1752 } else {
1753 Field.deref<T>() = Value.truncate(FieldBitWidth);
1754 }
1755 Field.initialize();
1756 return true;
1757}
1758
1759template <PrimType Name, class T = typename PrimConv<Name>::T>
1760bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
1761 uint32_t FieldBitWidth) {
1762 const T &Value = S.Stk.pop<T>();
1763 const Pointer &Ptr = S.Stk.peek<Pointer>();
1764 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1765 return false;
1766 if (!CheckArray(S, OpPC, Ptr))
1767 return false;
1768
1769 const Pointer &Field = Ptr.atField(FieldOffset);
1770
1771 unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
1772 if constexpr (needsAlloc<T>()) {
1773 T Result = S.allocAP<T>(Value.bitWidth());
1774 if constexpr (T::isSigned())
1775 Result.copy(
1776 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
1777 else
1778 Result.copy(
1779 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
1780
1781 Field.deref<T>() = Result;
1782 } else {
1783 Field.deref<T>() = Value.truncate(FieldBitWidth);
1784 }
1785 Field.activate();
1786 Field.initialize();
1787 return true;
1788}
1789
1790//===----------------------------------------------------------------------===//
1791// GetPtr Local/Param/Global/Field/This
1792//===----------------------------------------------------------------------===//
1793
1794inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1796 return true;
1797}
1798
1799inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
1800 if (S.Current->isBottomFrame())
1801 return false;
1802 S.Stk.push<Pointer>(S.Current->getParamPointer(Index));
1803 return true;
1804}
1805
1806inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1807 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1808 return true;
1809}
1810
1811/// 1) Peeks a Pointer
1812/// 2) Pushes Pointer.atField(Off) on the stack
1813bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1814bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
1815
1816inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1818 return false;
1819 if (!CheckThis(S, OpPC))
1820 return false;
1821 const Pointer &This = S.Current->getThis();
1822 S.Stk.push<Pointer>(This.atField(Off));
1823 return true;
1824}
1825
1826inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
1827 bool NullOK, const Type *TargetType) {
1828 const Pointer &Ptr = S.Stk.pop<Pointer>();
1829 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
1830 return false;
1831
1832 if (!Ptr.isBlockPointer()) {
1833 // FIXME: We don't have the necessary information in integral pointers.
1834 // The Descriptor only has a record, but that does of course not include
1835 // the potential derived classes of said record.
1836 S.Stk.push<Pointer>(Ptr);
1837 return true;
1838 }
1839
1840 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1841 return false;
1842 if (!CheckDowncast(S, OpPC, Ptr, Off))
1843 return false;
1844
1845 const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
1846 assert(TargetRecord);
1847
1848 if (TargetRecord->getDecl()->getCanonicalDecl() !=
1849 TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
1850 QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1851 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
1852 << MostDerivedType << QualType(TargetType, 0);
1853 return false;
1854 }
1855
1856 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1857 return true;
1858}
1859
1860inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1861 const Pointer &Ptr = S.Stk.peek<Pointer>();
1862 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1863 return false;
1864
1865 if (!Ptr.isBlockPointer()) {
1866 if (!Ptr.isIntegralPointer())
1867 return false;
1868 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1869 return true;
1870 }
1871
1872 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1873 return false;
1874 const Pointer &Result = Ptr.atField(Off);
1875 if (Result.isPastEnd() || !Result.isBaseClass())
1876 return false;
1877 S.Stk.push<Pointer>(Result);
1878 return true;
1879}
1880
1881inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
1882 bool NullOK) {
1883 const Pointer &Ptr = S.Stk.pop<Pointer>();
1884
1885 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
1886 return false;
1887
1888 if (!Ptr.isBlockPointer()) {
1889 if (!Ptr.isIntegralPointer())
1890 return false;
1891 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1892 return true;
1893 }
1894
1895 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1896 return false;
1897 const Pointer &Result = Ptr.atField(Off);
1898 if (Result.isPastEnd() || !Result.isBaseClass())
1899 return false;
1900 S.Stk.push<Pointer>(Result);
1901 return true;
1902}
1903
1904inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1906 return false;
1907 if (!CheckThis(S, OpPC))
1908 return false;
1909 const Pointer &This = S.Current->getThis();
1910 S.Stk.push<Pointer>(This.atField(Off));
1911 return true;
1912}
1913
1914inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1915 const Pointer &Ptr = S.Stk.pop<Pointer>();
1916 if (Ptr.canBeInitialized())
1917 Ptr.initialize();
1918 return true;
1919}
1920
1921inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1922 const Pointer &Ptr = S.Stk.peek<Pointer>();
1923 if (Ptr.canBeInitialized())
1924 Ptr.initialize();
1925 return true;
1926}
1927
1929 const Pointer &Ptr = S.Stk.peek<Pointer>();
1930 if (Ptr.canBeInitialized()) {
1931 Ptr.initialize();
1932 Ptr.activate();
1933 }
1934 return true;
1935}
1936
1938 const Pointer &Ptr = S.Stk.pop<Pointer>();
1939 if (Ptr.canBeInitialized()) {
1940 Ptr.initialize();
1941 Ptr.activate();
1942 }
1943 return true;
1944}
1945
1946bool FinishInitGlobal(InterpState &S, CodePtr OpPC);
1947
1948inline bool Dump(InterpState &S, CodePtr OpPC) {
1949 S.Stk.dump();
1950 return true;
1951}
1952
1953inline bool CheckNull(InterpState &S, CodePtr OpPC) {
1954 const auto &Ptr = S.Stk.peek<Pointer>();
1955 if (Ptr.isZero()) {
1956 S.FFDiag(S.Current->getSource(OpPC),
1957 diag::note_constexpr_dereferencing_null);
1958 return S.noteUndefinedBehavior();
1959 }
1960 return true;
1961}
1962
1963inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1964 const Pointer &Ptr) {
1965 Pointer Base = Ptr.stripBaseCasts();
1966 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1967 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1968 return true;
1969}
1970
1972 const RecordDecl *D) {
1973 assert(D);
1974 const Pointer &Ptr = S.Stk.pop<Pointer>();
1975 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1976 return false;
1977 return VirtBaseHelper(S, OpPC, D, Ptr);
1978}
1979
1981 const RecordDecl *D) {
1982 assert(D);
1984 return false;
1985 if (!CheckThis(S, OpPC))
1986 return false;
1987 const Pointer &This = S.Current->getThis();
1988 return VirtBaseHelper(S, OpPC, D, This);
1989}
1990
1991//===----------------------------------------------------------------------===//
1992// Load, Store, Init
1993//===----------------------------------------------------------------------===//
1994
1995template <PrimType Name, class T = typename PrimConv<Name>::T>
1996bool Load(InterpState &S, CodePtr OpPC) {
1997 const Pointer &Ptr = S.Stk.peek<Pointer>();
1998 if (!CheckLoad(S, OpPC, Ptr))
1999 return false;
2000 if (!Ptr.isBlockPointer())
2001 return false;
2002 if (!Ptr.canDeref(Name))
2003 return false;
2004 S.Stk.push<T>(Ptr.deref<T>());
2005 return true;
2006}
2007
2008template <PrimType Name, class T = typename PrimConv<Name>::T>
2010 const Pointer &Ptr = S.Stk.pop<Pointer>();
2011 if (!CheckLoad(S, OpPC, Ptr))
2012 return false;
2013 if (!Ptr.isBlockPointer())
2014 return false;
2015 if (!Ptr.canDeref(Name))
2016 return false;
2017 S.Stk.push<T>(Ptr.deref<T>());
2018 return true;
2019}
2020
2021template <PrimType Name, class T = typename PrimConv<Name>::T>
2022bool Store(InterpState &S, CodePtr OpPC) {
2023 const T &Value = S.Stk.pop<T>();
2024 const Pointer &Ptr = S.Stk.peek<Pointer>();
2025 if (!CheckStore(S, OpPC, Ptr))
2026 return false;
2027 if (Ptr.canBeInitialized())
2028 Ptr.initialize();
2029 Ptr.deref<T>() = Value;
2030 return true;
2031}
2032
2033template <PrimType Name, class T = typename PrimConv<Name>::T>
2035 const T &Value = S.Stk.pop<T>();
2036 const Pointer &Ptr = S.Stk.pop<Pointer>();
2037 if (!CheckStore(S, OpPC, Ptr))
2038 return false;
2039 if (Ptr.canBeInitialized())
2040 Ptr.initialize();
2041 Ptr.deref<T>() = Value;
2042 return true;
2043}
2044
2045static inline bool Activate(InterpState &S, CodePtr OpPC) {
2046 const Pointer &Ptr = S.Stk.peek<Pointer>();
2047 if (Ptr.canBeInitialized())
2048 Ptr.activate();
2049 return true;
2050}
2051
2052static inline bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
2054 return false;
2055 if (!S.Current->hasThisPointer())
2056 return false;
2057
2058 const Pointer &Ptr = S.Current->getThis();
2059 assert(Ptr.atField(I).canBeInitialized());
2060 Ptr.atField(I).activate();
2061 return true;
2062}
2063
2064template <PrimType Name, class T = typename PrimConv<Name>::T>
2066 const T &Value = S.Stk.pop<T>();
2067 const Pointer &Ptr = S.Stk.peek<Pointer>();
2068
2069 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
2070 return false;
2071 if (Ptr.canBeInitialized()) {
2072 Ptr.initialize();
2073 Ptr.activate();
2074 }
2075 Ptr.deref<T>() = Value;
2076 return true;
2077}
2078
2079template <PrimType Name, class T = typename PrimConv<Name>::T>
2081 const T &Value = S.Stk.pop<T>();
2082 const Pointer &Ptr = S.Stk.pop<Pointer>();
2083
2084 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
2085 return false;
2086 if (Ptr.canBeInitialized()) {
2087 Ptr.initialize();
2088 Ptr.activate();
2089 }
2090 Ptr.deref<T>() = Value;
2091 return true;
2092}
2093
2094template <PrimType Name, class T = typename PrimConv<Name>::T>
2096 const T &Value = S.Stk.pop<T>();
2097 const Pointer &Ptr = S.Stk.peek<Pointer>();
2098
2099 if (!CheckStore(S, OpPC, Ptr))
2100 return false;
2101 if (Ptr.canBeInitialized())
2102 Ptr.initialize();
2103 if (const auto *FD = Ptr.getField())
2104 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2105 else
2106 Ptr.deref<T>() = Value;
2107 return true;
2108}
2109
2110template <PrimType Name, class T = typename PrimConv<Name>::T>
2112 const T &Value = S.Stk.pop<T>();
2113 const Pointer &Ptr = S.Stk.pop<Pointer>();
2114 if (!CheckStore(S, OpPC, Ptr))
2115 return false;
2116 if (Ptr.canBeInitialized())
2117 Ptr.initialize();
2118 if (const auto *FD = Ptr.getField())
2119 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2120 else
2121 Ptr.deref<T>() = Value;
2122 return true;
2123}
2124
2125template <PrimType Name, class T = typename PrimConv<Name>::T>
2127 const T &Value = S.Stk.pop<T>();
2128 const Pointer &Ptr = S.Stk.peek<Pointer>();
2129
2130 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
2131 return false;
2132 if (Ptr.canBeInitialized()) {
2133 Ptr.initialize();
2134 Ptr.activate();
2135 }
2136 if (const auto *FD = Ptr.getField())
2137 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2138 else
2139 Ptr.deref<T>() = Value;
2140 return true;
2141}
2142
2143template <PrimType Name, class T = typename PrimConv<Name>::T>
2145 const T &Value = S.Stk.pop<T>();
2146 const Pointer &Ptr = S.Stk.pop<Pointer>();
2147
2148 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
2149 return false;
2150 if (Ptr.canBeInitialized()) {
2151 Ptr.initialize();
2152 Ptr.activate();
2153 }
2154 if (const auto *FD = Ptr.getField())
2155 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2156 else
2157 Ptr.deref<T>() = Value;
2158 return true;
2159}
2160
2161template <PrimType Name, class T = typename PrimConv<Name>::T>
2162bool Init(InterpState &S, CodePtr OpPC) {
2163 const T &Value = S.Stk.pop<T>();
2164 const Pointer &Ptr = S.Stk.peek<Pointer>();
2165 if (!CheckInit(S, OpPC, Ptr))
2166 return false;
2167 Ptr.initialize();
2168 new (&Ptr.deref<T>()) T(Value);
2169 return true;
2170}
2171
2172template <PrimType Name, class T = typename PrimConv<Name>::T>
2174 const T &Value = S.Stk.pop<T>();
2175 const Pointer &Ptr = S.Stk.pop<Pointer>();
2176 if (!CheckInit(S, OpPC, Ptr))
2177 return false;
2178 Ptr.initialize();
2179 new (&Ptr.deref<T>()) T(Value);
2180 return true;
2181}
2182
2183/// 1) Pops the value from the stack
2184/// 2) Peeks a pointer and gets its index \Idx
2185/// 3) Sets the value on the pointer, leaving the pointer on the stack.
2186template <PrimType Name, class T = typename PrimConv<Name>::T>
2187bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2188 const T &Value = S.Stk.pop<T>();
2189 const Pointer &Ptr = S.Stk.peek<Pointer>();
2190
2191 const Descriptor *Desc = Ptr.getFieldDesc();
2192 if (Desc->isUnknownSizeArray())
2193 return false;
2194
2195 // In the unlikely event that we're initializing the first item of
2196 // a non-array, skip the atIndex().
2197 if (Idx == 0 && !Desc->isArray()) {
2198 Ptr.initialize();
2199 new (&Ptr.deref<T>()) T(Value);
2200 return true;
2201 }
2202
2203 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
2204 return false;
2205 if (Idx >= Desc->getNumElems()) {
2206 // CheckRange.
2207 if (S.getLangOpts().CPlusPlus) {
2208 const SourceInfo &Loc = S.Current->getSource(OpPC);
2209 S.FFDiag(Loc, diag::note_constexpr_access_past_end)
2210 << AK_Assign << S.Current->getRange(OpPC);
2211 }
2212 return false;
2213 }
2214 Ptr.initializeElement(Idx);
2215 new (&Ptr.elem<T>(Idx)) T(Value);
2216 return true;
2217}
2218
2219/// The same as InitElem, but pops the pointer as well.
2220template <PrimType Name, class T = typename PrimConv<Name>::T>
2221bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2222 const T &Value = S.Stk.pop<T>();
2223 const Pointer &Ptr = S.Stk.pop<Pointer>();
2224
2225 const Descriptor *Desc = Ptr.getFieldDesc();
2226 if (Desc->isUnknownSizeArray())
2227 return false;
2228
2229 // In the unlikely event that we're initializing the first item of
2230 // a non-array, skip the atIndex().
2231 if (Idx == 0 && !Desc->isArray()) {
2232 Ptr.initialize();
2233 new (&Ptr.deref<T>()) T(Value);
2234 return true;
2235 }
2236
2237 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
2238 return false;
2239 if (Idx >= Desc->getNumElems()) {
2240 // CheckRange.
2241 if (S.getLangOpts().CPlusPlus) {
2242 const SourceInfo &Loc = S.Current->getSource(OpPC);
2243 S.FFDiag(Loc, diag::note_constexpr_access_past_end)
2244 << AK_Assign << S.Current->getRange(OpPC);
2245 }
2246 return false;
2247 }
2248 Ptr.initializeElement(Idx);
2249 new (&Ptr.elem<T>(Idx)) T(Value);
2250 return true;
2251}
2252
2253inline bool Memcpy(InterpState &S, CodePtr OpPC) {
2254 const Pointer &Src = S.Stk.pop<Pointer>();
2255 Pointer &Dest = S.Stk.peek<Pointer>();
2256
2257 if (!CheckLoad(S, OpPC, Src))
2258 return false;
2259
2260 return DoMemcpy(S, OpPC, Src, Dest);
2261}
2262
2263inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
2264 const auto &Member = S.Stk.pop<MemberPointer>();
2265 const auto &Base = S.Stk.pop<Pointer>();
2266
2267 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
2268 return true;
2269}
2270
2271inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
2272 const auto &MP = S.Stk.pop<MemberPointer>();
2273
2274 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
2275 S.Stk.push<Pointer>(*Ptr);
2276 return true;
2277 }
2278 return Invalid(S, OpPC);
2279}
2280
2281//===----------------------------------------------------------------------===//
2282// AddOffset, SubOffset
2283//===----------------------------------------------------------------------===//
2284
2285template <class T, ArithOp Op>
2286std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
2287 const T &Offset, const Pointer &Ptr,
2288 bool IsPointerArith = false) {
2289 // A zero offset does not change the pointer.
2290 if (Offset.isZero())
2291 return Ptr;
2292
2293 if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
2294 // The CheckNull will have emitted a note already, but we only
2295 // abort in C++, since this is fine in C.
2296 if (S.getLangOpts().CPlusPlus)
2297 return std::nullopt;
2298 }
2299
2300 // Arrays of unknown bounds cannot have pointers into them.
2301 if (!CheckArray(S, OpPC, Ptr))
2302 return std::nullopt;
2303
2304 // This is much simpler for integral pointers, so handle them first.
2305 if (Ptr.isIntegralPointer()) {
2306 uint64_t V = Ptr.getIntegerRepresentation();
2307 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
2308 if constexpr (Op == ArithOp::Add)
2309 return Pointer(V + O, Ptr.asIntPointer().Desc);
2310 else
2311 return Pointer(V - O, Ptr.asIntPointer().Desc);
2312 } else if (Ptr.isFunctionPointer()) {
2313 uint64_t O = static_cast<uint64_t>(Offset);
2314 uint64_t N;
2315 if constexpr (Op == ArithOp::Add)
2316 N = Ptr.getByteOffset() + O;
2317 else
2318 N = Ptr.getByteOffset() - O;
2319
2320 if (N > 1)
2321 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2322 << N << /*non-array*/ true << 0;
2323 return Pointer(Ptr.asFunctionPointer().Func, N);
2324 } else if (!Ptr.isBlockPointer()) {
2325 return std::nullopt;
2326 }
2327
2328 assert(Ptr.isBlockPointer());
2329
2330 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
2331 uint64_t Index;
2332 if (Ptr.isOnePastEnd())
2333 Index = MaxIndex;
2334 else
2335 Index = Ptr.getIndex();
2336
2337 bool Invalid = false;
2338 // Helper to report an invalid offset, computed as APSInt.
2339 auto DiagInvalidOffset = [&]() -> void {
2340 const unsigned Bits = Offset.bitWidth();
2341 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
2342 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
2343 /*IsUnsigned=*/false);
2344 APSInt NewIndex =
2345 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2346 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2347 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
2348 Invalid = true;
2349 };
2350
2351 if (Ptr.isBlockPointer()) {
2352 uint64_t IOffset = static_cast<uint64_t>(Offset);
2353 uint64_t MaxOffset = MaxIndex - Index;
2354
2355 if constexpr (Op == ArithOp::Add) {
2356 // If the new offset would be negative, bail out.
2357 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2358 DiagInvalidOffset();
2359
2360 // If the new offset would be out of bounds, bail out.
2361 if (Offset.isPositive() && IOffset > MaxOffset)
2362 DiagInvalidOffset();
2363 } else {
2364 // If the new offset would be negative, bail out.
2365 if (Offset.isPositive() && Index < IOffset)
2366 DiagInvalidOffset();
2367
2368 // If the new offset would be out of bounds, bail out.
2369 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2370 DiagInvalidOffset();
2371 }
2372 }
2373
2374 if (Invalid && (S.getLangOpts().CPlusPlus || Ptr.inArray()))
2375 return std::nullopt;
2376
2377 // Offset is valid - compute it on unsigned.
2378 int64_t WideIndex = static_cast<int64_t>(Index);
2379 int64_t WideOffset = static_cast<int64_t>(Offset);
2380 int64_t Result;
2381 if constexpr (Op == ArithOp::Add)
2382 Result = WideIndex + WideOffset;
2383 else
2384 Result = WideIndex - WideOffset;
2385
2386 // When the pointer is one-past-end, going back to index 0 is the only
2387 // useful thing we can do. Any other index has been diagnosed before and
2388 // we don't get here.
2389 if (Result == 0 && Ptr.isOnePastEnd()) {
2390 if (Ptr.getFieldDesc()->isArray())
2391 return Ptr.atIndex(0);
2392 return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2393 }
2394
2395 return Ptr.atIndex(static_cast<uint64_t>(Result));
2396}
2397
2398template <PrimType Name, class T = typename PrimConv<Name>::T>
2400 const T &Offset = S.Stk.pop<T>();
2401 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2402
2403 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
2404 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2405 S.Stk.push<Pointer>(Result->narrow());
2406 return true;
2407 }
2408 return false;
2409}
2410
2411template <PrimType Name, class T = typename PrimConv<Name>::T>
2413 const T &Offset = S.Stk.pop<T>();
2414 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2415
2416 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
2417 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2418 S.Stk.push<Pointer>(Result->narrow());
2419 return true;
2420 }
2421 return false;
2422}
2423
2424template <ArithOp Op>
2425static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2426 const Pointer &Ptr) {
2427 if (Ptr.isDummy())
2428 return false;
2429
2430 using OneT = Integral<8, false>;
2431
2432 const Pointer &P = Ptr.deref<Pointer>();
2433 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
2434 return false;
2435
2436 // Get the current value on the stack.
2437 S.Stk.push<Pointer>(P);
2438
2439 // Now the current Ptr again and a constant 1.
2440 OneT One = OneT::from(1);
2441 if (std::optional<Pointer> Result =
2442 OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {
2443 // Store the new value.
2444 Ptr.deref<Pointer>() = Result->narrow();
2445 return true;
2446 }
2447 return false;
2448}
2449
2450static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2451 const Pointer &Ptr = S.Stk.pop<Pointer>();
2452
2453 if (!Ptr.isInitialized())
2454 return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment);
2455
2456 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2457}
2458
2459static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2460 const Pointer &Ptr = S.Stk.pop<Pointer>();
2461
2462 if (!Ptr.isInitialized())
2463 return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement);
2464
2465 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2466}
2467
2468/// 1) Pops a Pointer from the stack.
2469/// 2) Pops another Pointer from the stack.
2470/// 3) Pushes the difference of the indices of the two pointers on the stack.
2471template <PrimType Name, class T = typename PrimConv<Name>::T>
2472inline bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero) {
2473 const Pointer &LHS = S.Stk.pop<Pointer>().expand();
2474 const Pointer &RHS = S.Stk.pop<Pointer>().expand();
2475
2476 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2477 S.FFDiag(S.Current->getSource(OpPC),
2478 diag::note_constexpr_pointer_arith_unspecified)
2481 return false;
2482 }
2483
2484 if (ElemSizeIsZero) {
2485 QualType PtrT = LHS.getType();
2486 while (auto *AT = dyn_cast<ArrayType>(PtrT))
2487 PtrT = AT->getElementType();
2488
2490 PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2491 S.FFDiag(S.Current->getSource(OpPC),
2492 diag::note_constexpr_pointer_subtraction_zero_size)
2493 << ArrayTy;
2494
2495 return false;
2496 }
2497
2498 if (LHS == RHS) {
2499 S.Stk.push<T>();
2500 return true;
2501 }
2502
2503 int64_t A64 =
2504 LHS.isBlockPointer()
2505 ? (LHS.isElementPastEnd() ? LHS.getNumElems() : LHS.getIndex())
2507
2508 int64_t B64 =
2509 RHS.isBlockPointer()
2510 ? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())
2512
2513 int64_t R64 = A64 - B64;
2514 if (static_cast<int64_t>(T::from(R64)) != R64)
2515 return handleOverflow(S, OpPC, R64);
2516
2517 S.Stk.push<T>(T::from(R64));
2518 return true;
2519}
2520
2521inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2522 S.Current->initScope(I);
2523 return true;
2524}
2525
2526inline bool EnableLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
2527 assert(!S.Current->isLocalEnabled(I));
2528 S.Current->enableLocal(I);
2529 return true;
2530}
2531
2532inline bool GetLocalEnabled(InterpState &S, CodePtr OpPC, uint32_t I) {
2533 assert(S.Current);
2534 S.Stk.push<bool>(S.Current->isLocalEnabled(I));
2535 return true;
2536}
2537
2538//===----------------------------------------------------------------------===//
2539// Cast, CastFP
2540//===----------------------------------------------------------------------===//
2541
2542template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2543 using T = typename PrimConv<TIn>::T;
2544 using U = typename PrimConv<TOut>::T;
2545 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2546 return true;
2547}
2548
2549/// 1) Pops a Floating from the stack.
2550/// 2) Pushes a new floating on the stack that uses the given semantics.
2551inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2552 llvm::RoundingMode RM) {
2553 Floating F = S.Stk.pop<Floating>();
2554 Floating Result = S.allocFloat(*Sem);
2555 F.toSemantics(Sem, RM, &Result);
2556 S.Stk.push<Floating>(Result);
2557 return true;
2558}
2559
2560inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2561 FixedPointSemantics TargetSemantics =
2562 FixedPointSemantics::getFromOpaqueInt(FPS);
2563 const auto &Source = S.Stk.pop<FixedPoint>();
2564
2565 bool Overflow;
2566 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2567
2568 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2569 return false;
2570
2572 return true;
2573}
2574
2575/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2576/// to know what bitwidth the result should be.
2577template <PrimType Name, class T = typename PrimConv<Name>::T>
2578bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2579 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2580 // Copy data.
2581 {
2582 APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2583 Result.copy(Source);
2584 }
2586 return true;
2587}
2588
2589template <PrimType Name, class T = typename PrimConv<Name>::T>
2590bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2591 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2592 // Copy data.
2593 {
2594 APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2595 Result.copy(Source);
2596 }
2598 return true;
2599}
2600
2601template <PrimType Name, class T = typename PrimConv<Name>::T>
2603 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2604 const T &From = S.Stk.pop<T>();
2605 APSInt FromAP = From.toAPSInt();
2606
2608 Floating Result = S.allocFloat(*Sem);
2609 auto Status =
2610 Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result);
2611 S.Stk.push<Floating>(Result);
2612
2613 return CheckFloatResult(S, OpPC, Result, Status, FPO);
2614}
2615
2616template <PrimType Name, class T = typename PrimConv<Name>::T>
2617bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2618 const Floating &F = S.Stk.pop<Floating>();
2619
2620 if constexpr (std::is_same_v<T, Boolean>) {
2621 S.Stk.push<T>(T(F.isNonZero()));
2622 return true;
2623 } else {
2624 APSInt Result(std::max(8u, T::bitWidth()),
2625 /*IsUnsigned=*/!T::isSigned());
2626 auto Status = F.convertToInteger(Result);
2627
2628 // Float-to-Integral overflow check.
2629 if ((Status & APFloat::opStatus::opInvalidOp)) {
2630 const Expr *E = S.Current->getExpr(OpPC);
2631 QualType Type = E->getType();
2632
2633 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2634 if (S.noteUndefinedBehavior()) {
2635 S.Stk.push<T>(T(Result));
2636 return true;
2637 }
2638 return false;
2639 }
2640
2642 S.Stk.push<T>(T(Result));
2643 return CheckFloatResult(S, OpPC, F, Status, FPO);
2644 }
2645}
2646
2647static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2648 uint32_t BitWidth, uint32_t FPOI) {
2649 const Floating &F = S.Stk.pop<Floating>();
2650
2651 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2652 auto Status = F.convertToInteger(Result);
2653
2654 // Float-to-Integral overflow check.
2655 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite() &&
2656 !handleOverflow(S, OpPC, F.getAPFloat()))
2657 return false;
2658
2660
2661 auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);
2662 ResultAP.copy(Result);
2663
2664 S.Stk.push<IntegralAP<false>>(ResultAP);
2665
2666 return CheckFloatResult(S, OpPC, F, Status, FPO);
2667}
2668
2669static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2670 uint32_t BitWidth, uint32_t FPOI) {
2671 const Floating &F = S.Stk.pop<Floating>();
2672
2673 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2674 auto Status = F.convertToInteger(Result);
2675
2676 // Float-to-Integral overflow check.
2677 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite() &&
2678 !handleOverflow(S, OpPC, F.getAPFloat()))
2679 return false;
2680
2682
2683 auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);
2684 ResultAP.copy(Result);
2685
2686 S.Stk.push<IntegralAP<true>>(ResultAP);
2687
2688 return CheckFloatResult(S, OpPC, F, Status, FPO);
2689}
2690
2691bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2692 const Pointer &Ptr, unsigned BitWidth);
2693bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2694bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2695
2696template <PrimType Name, class T = typename PrimConv<Name>::T>
2698 const Pointer &Ptr = S.Stk.pop<Pointer>();
2699
2700 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2701 return Invalid(S, OpPC);
2702
2703 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2704 return true;
2705}
2706
2707template <PrimType Name, class T = typename PrimConv<Name>::T>
2708static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2709 uint32_t FPS) {
2710 const T &Int = S.Stk.pop<T>();
2711
2712 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2713
2714 bool Overflow;
2715 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2716
2717 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2718 return false;
2719
2721 return true;
2722}
2723
2724static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2725 uint32_t FPS) {
2726 const auto &Float = S.Stk.pop<Floating>();
2727
2728 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2729
2730 bool Overflow;
2731 FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
2732
2733 if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2734 return false;
2735
2737 return true;
2738}
2739
2740static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2741 const llvm::fltSemantics *Sem) {
2742 const auto &Fixed = S.Stk.pop<FixedPoint>();
2743 Floating Result = S.allocFloat(*Sem);
2744 Result.copy(Fixed.toFloat(Sem));
2745 S.Stk.push<Floating>(Result);
2746 return true;
2747}
2748
2749template <PrimType Name, class T = typename PrimConv<Name>::T>
2750static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2751 const auto &Fixed = S.Stk.pop<FixedPoint>();
2752
2753 bool Overflow;
2754 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2755
2756 if (Overflow && !handleOverflow(S, OpPC, Int))
2757 return false;
2758
2759 S.Stk.push<T>(Int);
2760 return true;
2761}
2762
2763static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) {
2764 const SourceInfo &E = S.Current->getSource(OpPC);
2765 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2766 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2767 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2768 return true;
2769}
2770
2771static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2772 const auto &Ptr = S.Stk.peek<Pointer>();
2773
2774 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2775 bool HasValidResult = !Ptr.isZero();
2776
2777 if (HasValidResult) {
2778 if (S.getStdAllocatorCaller("allocate"))
2779 return true;
2780
2781 const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
2782 if (S.getLangOpts().CPlusPlus26 &&
2783 S.getASTContext().hasSimilarType(Ptr.getType(),
2784 E->getType()->getPointeeType()))
2785 return true;
2786
2787 S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
2788 << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
2789 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
2790 } else if (!S.getLangOpts().CPlusPlus26) {
2791 const SourceInfo &E = S.Current->getSource(OpPC);
2792 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2793 << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
2794 << S.Current->getRange(OpPC);
2795 }
2796 } else {
2797 const SourceInfo &E = S.Current->getSource(OpPC);
2798 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2799 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2800 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2801 }
2802
2803 return true;
2804}
2805
2806//===----------------------------------------------------------------------===//
2807// Zero, Nullptr
2808//===----------------------------------------------------------------------===//
2809
2810template <PrimType Name, class T = typename PrimConv<Name>::T>
2811bool Zero(InterpState &S, CodePtr OpPC) {
2812 S.Stk.push<T>(T::zero());
2813 return true;
2814}
2815
2816static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2817 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2818 if (!Result.singleWord())
2819 std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
2821 return true;
2822}
2823
2824static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2825 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2826 if (!Result.singleWord())
2827 std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
2829 return true;
2830}
2831
2832template <PrimType Name, class T = typename PrimConv<Name>::T>
2833inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2834 const Descriptor *Desc) {
2835 // FIXME(perf): This is a somewhat often-used function and the value of a
2836 // null pointer is almost always 0.
2837 S.Stk.push<T>(Value, Desc);
2838 return true;
2839}
2840
2841template <PrimType Name, class T = typename PrimConv<Name>::T>
2842inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2843 const auto &P = S.Stk.pop<T>();
2844 if (P.isWeak())
2845 return false;
2846 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2847 return true;
2848}
2849
2850//===----------------------------------------------------------------------===//
2851// This, ImplicitThis
2852//===----------------------------------------------------------------------===//
2853
2854inline bool This(InterpState &S, CodePtr OpPC) {
2855 // Cannot read 'this' in this mode.
2857 return false;
2858 if (!CheckThis(S, OpPC))
2859 return false;
2860 const Pointer &This = S.Current->getThis();
2861
2862 // Ensure the This pointer has been cast to the correct base.
2863 if (!This.isDummy()) {
2865 if (!This.isTypeidPointer()) {
2866 [[maybe_unused]] const Record *R = This.getRecord();
2867 if (!R)
2868 R = This.narrow().getRecord();
2869 assert(R);
2870 assert(R->getDecl() ==
2872 ->getParent());
2873 }
2874 }
2875
2876 S.Stk.push<Pointer>(This);
2877 return true;
2878}
2879
2880inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2881 assert(S.Current->getFunction()->hasRVO());
2883 return false;
2884 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2885 return true;
2886}
2887
2888//===----------------------------------------------------------------------===//
2889// Shr, Shl
2890//===----------------------------------------------------------------------===//
2891
2892template <class LT, class RT, ShiftDir Dir>
2893inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
2894 LT *Result) {
2895 static_assert(!needsAlloc<LT>());
2896 const unsigned Bits = LHS.bitWidth();
2897
2898 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2899 if (S.getLangOpts().OpenCL)
2900 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2901 RHS.bitWidth(), &RHS);
2902
2903 if (RHS.isNegative()) {
2904 // During constant-folding, a negative shift is an opposite shift. Such a
2905 // shift is not a constant expression.
2906 const SourceInfo &Loc = S.Current->getSource(OpPC);
2907 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2908 if (!S.noteUndefinedBehavior())
2909 return false;
2910
2911 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(RHS.bitWidth(), false)) : -RHS;
2912
2913 return DoShift<LT, RT,
2915 S, OpPC, LHS, RHS, Result);
2916 }
2917
2918 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2919 return false;
2920
2921 // Limit the shift amount to Bits - 1. If this happened,
2922 // it has already been diagnosed by CheckShift() above,
2923 // but we still need to handle it.
2924 // Note that we have to be extra careful here since we're doing the shift in
2925 // any case, but we need to adjust the shift amount or the way we do the shift
2926 // for the potential error cases.
2927 typename LT::AsUnsigned R;
2928 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2929 if constexpr (Dir == ShiftDir::Left) {
2930 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2932 if (LHS.isNegative())
2933 R = LT::AsUnsigned::zero(LHS.bitWidth());
2934 else {
2935 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2936 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2937 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2938 }
2939 } else if (LHS.isNegative()) {
2940 if (LHS.isMin()) {
2941 R = LT::AsUnsigned::zero(LHS.bitWidth());
2942 } else {
2943 // If the LHS is negative, perform the cast and invert the result.
2944 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2945 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2946 &R);
2947 R = -R;
2948 }
2949 } else {
2950 // The good case, a simple left shift.
2951 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2952 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2953 }
2954 S.Stk.push<LT>(LT::from(R));
2955 return true;
2956 }
2957
2958 // Right shift.
2959 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2961 R = LT::AsUnsigned::from(-1);
2962 } else {
2963 // Do the shift on potentially signed LT, then convert to unsigned type.
2964 LT A;
2965 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2966 R = LT::AsUnsigned::from(A);
2967 }
2968
2969 S.Stk.push<LT>(LT::from(R));
2970 return true;
2971}
2972
2973/// A version of DoShift that works on IntegralAP.
2974template <class LT, class RT, ShiftDir Dir>
2975inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,
2976 APSInt RHS, LT *Result) {
2977 const unsigned Bits = LHS.getBitWidth();
2978
2979 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2980 if (S.getLangOpts().OpenCL)
2981 RHS &=
2982 APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),
2983 RHS.isUnsigned());
2984
2985 if (RHS.isNegative()) {
2986 // During constant-folding, a negative shift is an opposite shift. Such a
2987 // shift is not a constant expression.
2988 const SourceInfo &Loc = S.Current->getSource(OpPC);
2989 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();
2990 if (!S.noteUndefinedBehavior())
2991 return false;
2992 return DoShiftAP<LT, RT,
2994 S, OpPC, LHS, -RHS, Result);
2995 }
2996
2997 if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),
2998 Bits))
2999 return false;
3000
3001 unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1);
3002 if constexpr (Dir == ShiftDir::Left) {
3003 if constexpr (needsAlloc<LT>())
3004 Result->copy(LHS << SA);
3005 else
3006 *Result = LT(LHS << SA);
3007 } else {
3008 if constexpr (needsAlloc<LT>())
3009 Result->copy(LHS >> SA);
3010 else
3011 *Result = LT(LHS >> SA);
3012 }
3013
3014 S.Stk.push<LT>(*Result);
3015 return true;
3016}
3017
3018template <PrimType NameL, PrimType NameR>
3019inline bool Shr(InterpState &S, CodePtr OpPC) {
3020 using LT = typename PrimConv<NameL>::T;
3021 using RT = typename PrimConv<NameR>::T;
3022 auto RHS = S.Stk.pop<RT>();
3023 auto LHS = S.Stk.pop<LT>();
3024
3025 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3026 LT Result;
3027 if constexpr (needsAlloc<LT>())
3028 Result = S.allocAP<LT>(LHS.bitWidth());
3029 return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
3030 RHS.toAPSInt(), &Result);
3031 } else {
3032 LT Result;
3033 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
3034 }
3035}
3036
3037template <PrimType NameL, PrimType NameR>
3038inline bool Shl(InterpState &S, CodePtr OpPC) {
3039 using LT = typename PrimConv<NameL>::T;
3040 using RT = typename PrimConv<NameR>::T;
3041 auto RHS = S.Stk.pop<RT>();
3042 auto LHS = S.Stk.pop<LT>();
3043
3044 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3045 LT Result;
3046 if constexpr (needsAlloc<LT>())
3047 Result = S.allocAP<LT>(LHS.bitWidth());
3048 return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
3049 RHS.toAPSInt(), &Result);
3050 } else {
3051 LT Result;
3052 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
3053 }
3054}
3055
3056static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
3057 const auto &RHS = S.Stk.pop<FixedPoint>();
3058 const auto &LHS = S.Stk.pop<FixedPoint>();
3059 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
3060
3061 unsigned ShiftBitWidth =
3062 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
3063
3064 // Embedded-C 4.1.6.2.2:
3065 // The right operand must be nonnegative and less than the total number
3066 // of (nonpadding) bits of the fixed-point operand ...
3067 if (RHS.isNegative()) {
3068 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
3069 << RHS.toAPSInt();
3070 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3071 ShiftBitWidth)) != RHS.toAPSInt()) {
3072 const Expr *E = S.Current->getExpr(OpPC);
3073 S.CCEDiag(E, diag::note_constexpr_large_shift)
3074 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
3075 }
3076
3078 if (Left) {
3079 if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
3081 return false;
3082 } else {
3083 if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
3085 return false;
3086 }
3087
3089 return true;
3090}
3091
3092//===----------------------------------------------------------------------===//
3093// NoRet
3094//===----------------------------------------------------------------------===//
3096 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
3097 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
3098 return false;
3099}
3100
3101//===----------------------------------------------------------------------===//
3102// NarrowPtr, ExpandPtr
3103//===----------------------------------------------------------------------===//
3104
3105inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
3106 const Pointer &Ptr = S.Stk.pop<Pointer>();
3107 S.Stk.push<Pointer>(Ptr.narrow());
3108 return true;
3109}
3110
3111inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
3112 const Pointer &Ptr = S.Stk.pop<Pointer>();
3113 if (Ptr.isBlockPointer())
3114 S.Stk.push<Pointer>(Ptr.expand());
3115 else
3116 S.Stk.push<Pointer>(Ptr);
3117 return true;
3118}
3119
3120// 1) Pops an integral value from the stack
3121// 2) Peeks a pointer
3122// 3) Pushes a new pointer that's a narrowed array
3123// element of the peeked pointer with the value
3124// from 1) added as offset.
3125//
3126// This leaves the original pointer on the stack and pushes a new one
3127// with the offset applied and narrowed.
3128template <PrimType Name, class T = typename PrimConv<Name>::T>
3129inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
3130 const T &Offset = S.Stk.pop<T>();
3131 const Pointer &Ptr = S.Stk.peek<Pointer>();
3132
3133 if (!Ptr.isZero() && !Offset.isZero()) {
3134 if (!CheckArray(S, OpPC, Ptr))
3135 return false;
3136 }
3137
3138 if (Offset.isZero()) {
3139 if (const Descriptor *Desc = Ptr.getFieldDesc();
3140 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3141 S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
3142 return true;
3143 }
3144 S.Stk.push<Pointer>(Ptr.narrow());
3145 return true;
3146 }
3147
3148 assert(!Offset.isZero());
3149
3150 if (std::optional<Pointer> Result =
3151 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3152 S.Stk.push<Pointer>(Result->narrow());
3153 return true;
3154 }
3155
3156 return false;
3157}
3158
3159template <PrimType Name, class T = typename PrimConv<Name>::T>
3160inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
3161 const T &Offset = S.Stk.pop<T>();
3162 const Pointer &Ptr = S.Stk.pop<Pointer>();
3163
3164 if (!Ptr.isZero() && !Offset.isZero()) {
3165 if (!CheckArray(S, OpPC, Ptr))
3166 return false;
3167 }
3168
3169 if (Offset.isZero()) {
3170 if (const Descriptor *Desc = Ptr.getFieldDesc();
3171 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3172 S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
3173 return true;
3174 }
3175 S.Stk.push<Pointer>(Ptr.narrow());
3176 return true;
3177 }
3178
3179 assert(!Offset.isZero());
3180
3181 if (std::optional<Pointer> Result =
3182 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3183 S.Stk.push<Pointer>(Result->narrow());
3184 return true;
3185 }
3186 return false;
3187}
3188
3189template <PrimType Name, class T = typename PrimConv<Name>::T>
3190inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
3191 const Pointer &Ptr = S.Stk.peek<Pointer>();
3192
3193 if (!CheckLoad(S, OpPC, Ptr))
3194 return false;
3195
3196 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3197 S.Stk.push<T>(Ptr.elem<T>(Index));
3198 return true;
3199}
3200
3201template <PrimType Name, class T = typename PrimConv<Name>::T>
3202inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
3203 const Pointer &Ptr = S.Stk.pop<Pointer>();
3204
3205 if (!CheckLoad(S, OpPC, Ptr))
3206 return false;
3207
3208 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3209 S.Stk.push<T>(Ptr.elem<T>(Index));
3210 return true;
3211}
3212
3213template <PrimType Name, class T = typename PrimConv<Name>::T>
3214inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
3215 uint32_t DestIndex, uint32_t Size) {
3216 const auto &SrcPtr = S.Stk.pop<Pointer>();
3217 const auto &DestPtr = S.Stk.peek<Pointer>();
3218
3219 if (SrcPtr.isDummy() || DestPtr.isDummy())
3220 return false;
3221
3222 if (!SrcPtr.isBlockPointer() || !DestPtr.isBlockPointer())
3223 return false;
3224
3225 for (uint32_t I = 0; I != Size; ++I) {
3226 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
3227
3228 if (!CheckLoad(S, OpPC, SP))
3229 return false;
3230
3231 DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);
3232 DestPtr.initializeElement(DestIndex + I);
3233 }
3234 return true;
3235}
3236
3237/// Just takes a pointer and checks if it's an incomplete
3238/// array type.
3239inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
3240 const Pointer &Ptr = S.Stk.pop<Pointer>();
3241
3242 if (Ptr.isZero()) {
3243 S.Stk.push<Pointer>(Ptr);
3244 return true;
3245 }
3246
3247 if (!Ptr.isZeroSizeArray()) {
3248 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
3249 return false;
3250 }
3251
3252 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
3253 S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
3254 return true;
3255 }
3256
3257 const SourceInfo &E = S.Current->getSource(OpPC);
3258 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
3259
3260 return false;
3261}
3262
3263inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
3264 assert(Func);
3265 S.Stk.push<Pointer>(Func);
3266 return true;
3267}
3268
3269template <PrimType Name, class T = typename PrimConv<Name>::T>
3270inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3271 const T &IntVal = S.Stk.pop<T>();
3272
3273 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3274 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3275 << S.getLangOpts().CPlusPlus;
3276
3277 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
3278 return true;
3279}
3280
3281inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
3282 S.Stk.push<MemberPointer>(D);
3283 return true;
3284}
3285
3286inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
3287 const auto &MP = S.Stk.pop<MemberPointer>();
3288
3289 if (!MP.isBaseCastPossible())
3290 return false;
3291
3292 S.Stk.push<Pointer>(MP.getBase());
3293 return true;
3294}
3295
3296inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
3297 const auto &MP = S.Stk.pop<MemberPointer>();
3298
3299 const auto *FD = cast<FunctionDecl>(MP.getDecl());
3300 const auto *Func = S.getContext().getOrCreateFunction(FD);
3301
3302 S.Stk.push<Pointer>(Func);
3303 return true;
3304}
3305
3306/// Just emit a diagnostic. The expression that caused emission of this
3307/// op is not valid in a constant context.
3308
3309inline bool Unsupported(InterpState &S, CodePtr OpPC) {
3310 const SourceLocation &Loc = S.Current->getLocation(OpPC);
3311 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
3312 << S.Current->getRange(OpPC);
3313 return false;
3314}
3315
3316inline bool PushIgnoreDiags(InterpState &S, CodePtr OpPC) {
3317 ++S.DiagIgnoreDepth;
3318 if (S.DiagIgnoreDepth != 1)
3319 return true;
3320 assert(S.PrevDiags == nullptr);
3322 S.getEvalStatus().Diag = nullptr;
3323 assert(!S.diagnosing());
3324 return true;
3325}
3326
3327inline bool PopIgnoreDiags(InterpState &S, CodePtr OpPC) {
3328 assert(S.DiagIgnoreDepth != 0);
3329 --S.DiagIgnoreDepth;
3330 if (S.DiagIgnoreDepth == 0) {
3332 S.PrevDiags = nullptr;
3333 }
3334 return true;
3335}
3336
3337inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {
3338#ifndef NDEBUG
3339 ++S.SpeculationDepth;
3340#endif
3341 return true;
3342}
3343
3344// This is special-cased in the tablegen opcode emitter.
3345// Its dispatch function will NOT call InterpNext
3346// and instead simply return true.
3348#ifndef NDEBUG
3349 assert(S.SpeculationDepth != 0);
3350 --S.SpeculationDepth;
3351#endif
3352 return true;
3353}
3354
3355inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {
3357 return true;
3358}
3359inline bool PopCC(InterpState &S, CodePtr OpPC) {
3360 S.ConstantContextOverride = std::nullopt;
3361 return true;
3362}
3363
3364inline bool PushMSVCCE(InterpState &S, CodePtr OpPC) {
3365 // This is a per-frame property.
3367 return true;
3368}
3369
3370inline bool PopMSVCCE(InterpState &S, CodePtr OpPC) {
3371 assert(S.Current->MSVCConstexprAllowed >= 1);
3372 // This is a per-frame property.
3374 return true;
3375}
3376
3377/// Do nothing and just abort execution.
3378inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
3379
3380inline bool SideEffect(InterpState &S, CodePtr OpPC) {
3381 return S.noteSideEffect();
3382}
3383
3384/// Abort without a diagnostic if we're checking for a potential constant
3385/// expression and this is not the bottom frame. This is used in constructors to
3386/// allow evaluating their initializers but abort if we encounter anything in
3387/// their body.
3388inline bool CtorCheck(InterpState &S, CodePtr OpPC) {
3390 return false;
3391 return true;
3392}
3393
3394inline bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T) {
3395 if (S.getLangOpts().CPlusPlus) {
3396 QualType VolatileType = QualType(T, 0).withVolatile();
3397 S.FFDiag(S.Current->getSource(OpPC),
3398 diag::note_constexpr_access_volatile_type)
3399 << AK_Assign << VolatileType;
3400 } else {
3401 S.FFDiag(S.Current->getSource(OpPC));
3402 }
3403 return false;
3404}
3405
3407 if (S.inConstantContext()) {
3408 const SourceRange &ArgRange = S.Current->getRange(OpPC);
3409 const Expr *E = S.Current->getExpr(OpPC);
3410 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3411 }
3412 return false;
3413}
3414
3415inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {
3416 if (!S.getLangOpts().CPlusPlus20)
3417 S.CCEDiag(S.Current->getSource(OpPC),
3418 diag::note_constexpr_pseudo_destructor);
3419 return true;
3420}
3421
3422inline bool Assume(InterpState &S, CodePtr OpPC) {
3423 const auto Val = S.Stk.pop<Boolean>();
3424
3425 if (Val)
3426 return true;
3427
3428 // Else, diagnose.
3429 const SourceLocation &Loc = S.Current->getLocation(OpPC);
3430 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
3431 return false;
3432}
3433
3434template <PrimType Name, class T = typename PrimConv<Name>::T>
3435inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
3436 llvm::SmallVector<int64_t> ArrayIndices;
3437 for (size_t I = 0; I != E->getNumExpressions(); ++I)
3438 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
3439
3440 int64_t Result;
3441 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
3442 return false;
3443
3444 S.Stk.push<T>(T::from(Result));
3445
3446 return true;
3447}
3448
3449template <PrimType Name, class T = typename PrimConv<Name>::T>
3450inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
3451 const T &Arg = S.Stk.peek<T>();
3452 if (!Arg.isZero())
3453 return true;
3454
3455 const SourceLocation &Loc = S.Current->getLocation(OpPC);
3456 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
3457
3458 return false;
3459}
3460
3461void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
3462 const APSInt &Value);
3463
3464template <PrimType Name, class T = typename PrimConv<Name>::T>
3465inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
3466 assert(ED);
3467 assert(!ED->isFixed());
3468
3469 if (S.inConstantContext()) {
3470 const APSInt Val = S.Stk.peek<T>().toAPSInt();
3471 diagnoseEnumValue(S, OpPC, ED, Val);
3472 }
3473 return true;
3474}
3475
3476/// OldPtr -> Integer -> NewPtr.
3477template <PrimType TIn, PrimType TOut>
3478inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
3479 static_assert(isPtrType(TIn) && isPtrType(TOut));
3480 using FromT = typename PrimConv<TIn>::T;
3481 using ToT = typename PrimConv<TOut>::T;
3482
3483 const FromT &OldPtr = S.Stk.pop<FromT>();
3484
3485 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3486 std::is_same_v<ToT, Pointer>) {
3487 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
3488 return true;
3489 } else if constexpr (std::is_same_v<FromT, Pointer> &&
3490 std::is_same_v<ToT, FunctionPointer>) {
3491 if (OldPtr.isFunctionPointer()) {
3492 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
3493 OldPtr.getByteOffset());
3494 return true;
3495 }
3496 }
3497
3498 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
3499 return true;
3500}
3501
3502inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
3503 // An expression E is a core constant expression unless the evaluation of E
3504 // would evaluate one of the following: [C++23] - a control flow that passes
3505 // through a declaration of a variable with static or thread storage duration
3506 // unless that variable is usable in constant expressions.
3507 assert(VD->isLocalVarDecl() &&
3508 VD->isStaticLocal()); // Checked before emitting this.
3509
3510 if (VD == S.EvaluatingDecl)
3511 return true;
3512
3514 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
3515 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
3516 return false;
3517 }
3518 return true;
3519}
3520
3521inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3522 assert(Desc);
3523
3524 if (!CheckDynamicMemoryAllocation(S, OpPC))
3525 return false;
3526
3527 DynamicAllocator &Allocator = S.getAllocator();
3528 Block *B =
3530 assert(B);
3531 S.Stk.push<Pointer>(B);
3532 return true;
3533}
3534
3535template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3536inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
3537 bool IsNoThrow) {
3538 if (!CheckDynamicMemoryAllocation(S, OpPC))
3539 return false;
3540
3541 SizeT NumElements = S.Stk.pop<SizeT>();
3542 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
3543 if (!IsNoThrow)
3544 return false;
3545
3546 // If this failed and is nothrow, just return a null ptr.
3547 S.Stk.push<Pointer>(0, nullptr);
3548 return true;
3549 }
3550 if (NumElements.isNegative()) {
3551 if (!IsNoThrow) {
3552 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
3553 << NumElements.toDiagnosticString(S.getASTContext());
3554 return false;
3555 }
3556 S.Stk.push<Pointer>(0, nullptr);
3557 return true;
3558 }
3559
3560 if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
3561 return false;
3562
3563 DynamicAllocator &Allocator = S.getAllocator();
3564 Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
3566 assert(B);
3567 if (NumElements.isZero())
3568 S.Stk.push<Pointer>(B);
3569 else
3570 S.Stk.push<Pointer>(Pointer(B).atIndex(0));
3571 return true;
3572}
3573
3574template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3575inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
3576 bool IsNoThrow) {
3577 if (!CheckDynamicMemoryAllocation(S, OpPC))
3578 return false;
3579
3580 if (!ElementDesc)
3581 return false;
3582
3583 SizeT NumElements = S.Stk.pop<SizeT>();
3584 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
3585 IsNoThrow)) {
3586 if (!IsNoThrow)
3587 return false;
3588
3589 // If this failed and is nothrow, just return a null ptr.
3590 S.Stk.push<Pointer>(0, ElementDesc);
3591 return true;
3592 }
3593 assert(NumElements.isPositive());
3594
3595 if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
3596 return false;
3597
3598 DynamicAllocator &Allocator = S.getAllocator();
3599 Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
3601 assert(B);
3602 if (NumElements.isZero())
3603 S.Stk.push<Pointer>(B);
3604 else
3605 S.Stk.push<Pointer>(Pointer(B).atIndex(0));
3606
3607 return true;
3608}
3609
3610bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
3611 bool IsGlobalDelete);
3612
3613static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
3615 return true;
3616}
3617
3618static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
3620}
3621
3622/// Check if the initializer and storage types of a placement-new expression
3623/// match.
3624bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
3625 std::optional<uint64_t> ArraySize = std::nullopt);
3626
3627template <PrimType Name, class T = typename PrimConv<Name>::T>
3629 const auto &Size = S.Stk.pop<T>();
3630 return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
3631}
3632bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
3633
3634template <PrimType Name, class T = typename PrimConv<Name>::T>
3635inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3636 uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,
3637 const Type *TargetType) {
3638 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3639
3640 if (!CheckLoad(S, OpPC, FromPtr))
3641 return false;
3642
3643 if constexpr (std::is_same_v<T, Pointer>) {
3644 if (!TargetType->isNullPtrType()) {
3645 S.FFDiag(S.Current->getSource(OpPC),
3646 diag::note_constexpr_bit_cast_invalid_type)
3647 << /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;
3648 return false;
3649 }
3650 // The only pointer type we can validly bitcast to is nullptr_t.
3651 S.Stk.push<Pointer>();
3652 return true;
3653 } else if constexpr (std::is_same_v<T, MemberPointer>) {
3654 S.FFDiag(S.Current->getSource(OpPC),
3655 diag::note_constexpr_bit_cast_invalid_type)
3656 << /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;
3657 return false;
3658 } else {
3659
3660 size_t BuffSize = ResultBitWidth / 8;
3661 llvm::SmallVector<std::byte> Buff(BuffSize);
3662 bool HasIndeterminateBits = false;
3663
3664 Bits FullBitWidth(ResultBitWidth);
3665 Bits BitWidth = FullBitWidth;
3666
3667 if constexpr (std::is_same_v<T, Floating>) {
3668 assert(Sem);
3669 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3670 }
3671
3672 if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3673 HasIndeterminateBits))
3674 return false;
3675
3676 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3677 return false;
3678
3679 if constexpr (std::is_same_v<T, Floating>) {
3680 assert(Sem);
3681 Floating Result = S.allocFloat(*Sem);
3682 Floating::bitcastFromMemory(Buff.data(), *Sem, &Result);
3683 S.Stk.push<Floating>(Result);
3684 } else if constexpr (needsAlloc<T>()) {
3685 T Result = S.allocAP<T>(ResultBitWidth);
3686 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);
3687 S.Stk.push<T>(Result);
3688 } else if constexpr (std::is_same_v<T, Boolean>) {
3689 // Only allow to cast single-byte integers to bool if they are either 0
3690 // or 1.
3691 assert(FullBitWidth.getQuantity() == 8);
3692 auto Val = static_cast<unsigned int>(Buff[0]);
3693 if (Val > 1) {
3694 S.FFDiag(S.Current->getSource(OpPC),
3695 diag::note_constexpr_bit_cast_unrepresentable_value)
3696 << S.getASTContext().BoolTy << Val;
3697 return false;
3698 }
3699 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3700 } else {
3701 assert(!Sem);
3702 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3703 }
3704 return true;
3705 }
3706}
3707
3708inline bool BitCast(InterpState &S, CodePtr OpPC) {
3709 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3710 Pointer &ToPtr = S.Stk.peek<Pointer>();
3711
3712 if (!CheckLoad(S, OpPC, FromPtr))
3713 return false;
3714
3715 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3716 return false;
3717
3718 return true;
3719}
3720
3721/// Typeid support.
3722bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3723 const Type *TypeInfoType);
3724bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3725bool DiagTypeid(InterpState &S, CodePtr OpPC);
3726
3727inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
3728 const auto &Ptr = S.Stk.peek<Pointer>();
3729 return CheckDestructor(S, OpPC, Ptr);
3730}
3731
3732//===----------------------------------------------------------------------===//
3733// Read opcode arguments
3734//===----------------------------------------------------------------------===//
3735
3736template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3737 if constexpr (std::is_pointer<T>::value) {
3738 uint32_t ID = OpPC.read<uint32_t>();
3739 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3740 } else {
3741 return OpPC.read<T>();
3742 }
3743}
3744
3745template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3746 auto &Semantics =
3747 llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC));
3748
3749 auto F = S.allocFloat(Semantics);
3750 Floating::deserialize(*OpPC, &F);
3751 OpPC += align(F.bytesToSerialize());
3752 return F;
3753}
3754
3755template <>
3756inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3757 CodePtr &OpPC) {
3758 uint32_t BitWidth = IntegralAP<false>::deserializeSize(*OpPC);
3759 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
3760 assert(Result.bitWidth() == BitWidth);
3761
3763 OpPC += align(Result.bytesToSerialize());
3764 return Result;
3765}
3766
3767template <>
3768inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3769 CodePtr &OpPC) {
3770 uint32_t BitWidth = IntegralAP<true>::deserializeSize(*OpPC);
3771 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
3772 assert(Result.bitWidth() == BitWidth);
3773
3774 IntegralAP<true>::deserialize(*OpPC, &Result);
3775 OpPC += align(Result.bytesToSerialize());
3776 return Result;
3777}
3778
3779template <>
3782 OpPC += align(FP.bytesToSerialize());
3783 return FP;
3784}
3785
3786} // namespace interp
3787} // namespace clang
3788
3789#endif
Defines the clang::ASTContext interface.
#define V(N, I)
llvm::APSInt APSInt
Definition Compiler.cpp:24
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)
#define PRESERVE_NONE
Definition Interp.h:45
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.
CanQualType BoolTy
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2136
bool isVirtual() const
Definition DeclCXX.h:2191
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:522
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2946
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
Definition Expr.cpp:1592
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1273
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
SourceLocation getEndLoc() const LLVM_READONLY
Definition DeclBase.h:435
SourceLocation getLocation() const
Definition DeclBase.h:439
AccessSpecifier getAccess() const
Definition DeclBase.h:507
Represents an enum.
Definition Decl.h:4028
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
Definition Decl.h:4255
This represents one expression.
Definition Expr.h:112
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:277
QualType getType() const
Definition Expr.h:144
static FPOptions getFromOpaqueInt(storage_type Value)
Represents a member of a struct/union/class.
Definition Decl.h:3175
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3411
Represents a function declaration or definition.
Definition Decl.h:2015
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition DeclCXX.h:3311
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition Expr.h:2530
unsigned getNumExpressions() const
Definition Expr.h:2601
A (possibly-)qualified type.
Definition TypeBase.h:937
QualType withVolatile() const
Definition TypeBase.h:1173
bool isWrapType() const
Returns true if it is a OverflowBehaviorType of Wrap kind.
Definition Type.cpp:3002
Represents a struct/union/class.
Definition Decl.h:4342
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:343
TagDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:4900
bool isUnion() const
Definition Decl.h:3943
The base class of the type hierarchy.
Definition TypeBase.h:1866
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isNullPtrType() const
Definition TypeBase.h:9071
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
Represents a variable declaration or definition.
Definition Decl.h:926
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition Decl.h:1208
ThreadStorageClassSpecifier getTSCSpec() const
Definition Decl.h:1177
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1268
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:2540
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:44
const T & deref() const
bool isExtern() const
Checks if the block is extern.
Definition InterpBlock.h:77
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:73
Wrapper around boolean types.
Definition Boolean.h:25
static Boolean from(T Value)
Definition Boolean.h:97
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:57
const Function * getOrCreateFunction(const FunctionDecl *FuncDecl)
Definition Context.cpp:555
Manages dynamic memory allocations done during bytecode interpretation.
Block * allocate(const Descriptor *D, unsigned EvalID, Form AllocForm)
Allocate ONE element of the given descriptor.
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
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:287
static llvm::APFloatBase::Semantics deserializeSemantics(const std::byte *Buff)
Definition Floating.h:212
void copy(const APFloat &F)
Definition Floating.h:123
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating *Result)
Definition Floating.h:172
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:256
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:246
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:236
static void deserialize(const std::byte *Buff, Floating *Result)
Definition Floating.h:216
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:276
bool isNonZero() const
Definition Floating.h:145
void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, Floating *Result) const
Definition Floating.h:77
const llvm::fltSemantics & getSemantics() const
Definition Floating.h:119
bool isFinite() const
Definition Floating.h:151
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:266
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition Floating.h:71
static void bitcastFromMemory(const std::byte *Buff, const llvm::fltSemantics &Sem, Floating *Result)
Definition Floating.h:182
APFloat getAPFloat() const
Definition Floating.h:64
Bytecode function.
Definition Function.h:99
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:133
bool hasRVO() const
Checks if the first argument is a RVO pointer.
Definition Function.h:155
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
static uint32_t deserializeSize(const std::byte *Buff)
Definition IntegralAP.h:332
static void deserialize(const std::byte *Buff, IntegralAP< Signed > *Result)
Definition IntegralAP.h:336
void copy(const APInt &V)
Definition IntegralAP.h:78
Wrapper around numeric types.
Definition Integral.h:66
Frame storing local variables.
Definition InterpFrame.h:27
static void free(InterpFrame *F)
Definition InterpFrame.h:62
const Expr * getExpr(CodePtr PC) const
bool isLocalEnabled(unsigned Idx) const
Definition InterpFrame.h:76
void setParam(unsigned Index, const T &Value)
Mutates a local copy of a parameter.
InterpFrame * Caller
The frame of the previous function.
Definition InterpFrame.h:30
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
CodePtr getRetPC() const
Returns the return address of the frame.
void enableLocal(unsigned Idx)
Block * getLocalBlock(unsigned Offset) const
SourceLocation getLocation(CodePtr PC) const
const Pointer & getThis() const
Returns the 'this' pointer.
const Function * getFunction() const
Returns the current function.
Definition InterpFrame.h:93
size_t getFrameOffset() const
Returns the offset on the stack at which the frame starts.
Definition InterpFrame.h:96
SourceRange getRange(CodePtr PC) const
void setLocal(unsigned Offset, const T &Value)
Mutates a local variable.
Pointer getLocalPointer(unsigned Offset) const
Returns a pointer to a local variables.
unsigned getDepth() const
const T & getParam(unsigned Index) const
Returns the value of an argument.
const Pointer & getRVOPtr() const
Returns the RVO pointer, if the Function has one.
Pointer getParamPointer(unsigned Offset)
Returns a pointer to an argument - lazily creates a block.
const FunctionDecl * getCallee() const override
Returns the caller.
void initScope(unsigned Idx)
T pop()
Returns the value from the top of the stack and removes it.
Definition InterpStack.h:39
void push(Tys &&...Args)
Constructs a value in place on the top of the stack.
Definition InterpStack.h:33
void dump() const
dump the stack contents to stderr.
size_t size() const
Returns the size of the stack in bytes.
Definition InterpStack.h:77
void discard()
Discards the top value from the stack.
Definition InterpStack.h:50
T & peek() const
Returns a reference to the value on the top of the stack.
Definition InterpStack.h:62
Interpreter context.
Definition InterpState.h:36
SmallVectorImpl< PartialDiagnosticAt > * PrevDiags
Things needed to do speculative execution.
Context & getContext() const
Definition InterpState.h:74
DynamicAllocator & getAllocator()
Definition InterpState.h:78
Context & Ctx
Interpreter Context.
Floating allocFloat(const llvm::fltSemantics &Sem)
const unsigned EvalID
ID identifying this evaluation.
llvm::SmallVector< std::pair< const Expr *, const LifetimeExtendedTemporaryDecl * > > SeenGlobalTemporaries
InterpStack & Stk
Temporary stack.
bool maybeDiagnoseDanglingAllocations()
Diagnose any dynamic allocations that haven't been freed yet.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
InterpFrame * Current
The current frame.
std::optional< bool > ConstantContextOverride
T allocAP(unsigned BitWidth)
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
Program & P
Reference to the module containing all bytecode.
unsigned getPathLength() const
Return the length of the cast path.
ComparisonCategoryResult compare(const MemberPointer &RHS) const
A pointer to a memory block, live or dead.
Definition Pointer.h:97
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition Pointer.cpp:692
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:194
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
Definition Pointer.h:786
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:442
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:669
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:162
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:562
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition Pointer.h:187
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:627
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:678
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:179
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:687
unsigned getNumElems() const
Returns the number of elements.
Definition Pointer.h:611
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition Pointer.h:426
void activate() const
Activats a field.
Definition Pointer.cpp:634
static std::optional< std::pair< Pointer, Pointer > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition Pointer.cpp:744
bool isIntegralPointer() const
Definition Pointer.h:480
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:346
bool pointsToStringLiteral() const
Definition Pointer.cpp:732
size_t computeOffsetForComparison(const ASTContext &ASTCtx) const
Compute an integer that can be used to compare this pointer to another one.
Definition Pointer.cpp:369
bool inArray() const
Checks if the innermost field is an array.
Definition Pointer.h:408
T & elem(unsigned I) const
Dereferences the element at index I.
Definition Pointer.h:703
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition Pointer.h:600
bool isTypeidPointer() const
Definition Pointer.h:482
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition Pointer.cpp:432
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:264
const IntPointer & asIntPointer() const
Definition Pointer.h:466
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:448
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:292
unsigned getOffset() const
Returns the offset into an array.
Definition Pointer.h:387
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:644
uint64_t getIntegerRepresentation() const
Definition Pointer.h:149
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition Pointer.h:229
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:666
bool isBlockPointer() const
Definition Pointer.h:479
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:470
bool isFunctionPointer() const
Definition Pointer.h:481
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:336
size_t elemSize() const
Returns the element size of the innermost field.
Definition Pointer.h:369
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition Pointer.h:455
const BlockPointer & asBlockPointer() const
Definition Pointer.h:462
void initialize() const
Initializes a field.
Definition Pointer.cpp:546
void initializeElement(unsigned Index) const
Initialized the given element of a primitive array.
Definition Pointer.cpp:572
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:485
Block * getGlobal(unsigned Idx)
Returns the value of a global.
Definition Program.h:71
Pointer getPtrGlobal(unsigned Idx) const
Returns a pointer to a global.
Definition Program.cpp:81
const void * getNativePointer(unsigned Idx) const
Returns the value of a marshalled native pointer.
Definition Program.cpp:30
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:65
Describes the statement/declaration an opcode was generated from.
Definition Source.h:74
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
Definition State.h:124
EvaluationMode EvalMode
Definition State.h:190
Expr::EvalStatus & getEvalStatus() const
Definition State.h:92
DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId)
Directly reports a diagnostic message.
Definition State.cpp:74
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:21
bool noteSideEffect() const
Note that we have had a side-effect, and determine whether we should keep evaluating.
Definition State.h:98
ASTContext & getASTContext() const
Definition State.h:93
bool noteUndefinedBehavior() const
Note that we hit something that was technically undefined behavior, but that we can evaluate past it ...
Definition State.h:113
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
Definition State.cpp:42
const LangOptions & getLangOpts() const
Definition State.h:94
bool checkingPotentialConstantExpression() const
Are we checking whether the expression is a potential constant expression?
Definition State.h:120
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS)
Definition Interp.cpp:2246
static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)
Definition Interp.h:3056
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.cpp:1470
bool InitPop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2173
bool Shr(InterpState &S, CodePtr OpPC)
Definition Interp.h:3019
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:1599
bool CheckDestruction(InterpState &S, CodePtr OpPC)
Definition Interp.h:3727
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.h:3202
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.cpp:2176
bool PopCC(InterpState &S, CodePtr OpPC)
Definition Interp.h:3359
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.h:3190
bool GT(InterpState &S, CodePtr OpPC)
Definition Interp.h:1346
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.cpp:2163
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition Interp.cpp:895
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition Interp.h:2647
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
Definition Interp.h:3286
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1504
bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow)
Definition Interp.h:884
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:3105
bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD)
Opcode. Check if the function decl can be called at compile time.
Definition Interp.cpp:1516
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1631
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem, const Type *TargetType)
Definition Interp.h:3635
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition Interp.h:3745
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:1005
bool SideEffect(InterpState &S, CodePtr OpPC)
Definition Interp.h:3380
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.h:2824
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS, LT *Result)
Definition Interp.h:2893
bool EndLifetimePop(InterpState &S, CodePtr OpPC)
Ends the lifetime of the pop'd pointer.
Definition Interp.cpp:1975
bool Sub(InterpState &S, CodePtr OpPC)
Definition Interp.h:358
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
Definition Interp.cpp:2212
bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:386
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition Interp.h:2221
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition Interp.h:2095
bool LT(InterpState &S, CodePtr OpPC)
Definition Interp.h:1331
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:538
bool BitCast(InterpState &S, CodePtr OpPC)
Definition Interp.h:3708
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2009
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
Definition Interp.h:2833
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Checks a direct load of a primitive value from a global or local variable.
Definition Interp.cpp:720
PRESERVE_NONE bool NoRet(InterpState &S, CodePtr OpPC)
Definition Interp.h:3095
static llvm::RoundingMode getRoundingMode(FPOptions FPO)
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:2450
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:1146
bool EndLifetime(InterpState &S, CodePtr OpPC)
Ends the lifetime of the peek'd pointer.
Definition Interp.cpp:1965
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
Definition Interp.cpp:2206
bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
Definition Interp.h:1760
bool Dup(InterpState &S, CodePtr OpPC)
Definition Interp.h:1365
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1472
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition Interp.h:3450
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}...
bool InitBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
Definition Interp.h:1730
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition Interp.h:2425
bool FinishInitActivate(InterpState &S, CodePtr OpPC)
Definition Interp.h:1928
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1794
bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:346
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:192
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition Interp.cpp:434
static bool IsOpaqueConstantCall(const CallExpr *E)
Definition Interp.h:1128
bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)
Definition Interp.h:3502
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition Interp.cpp:2143
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition Interp.h:293
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
Definition Interp.cpp:1465
bool StoreActivate(InterpState &S, CodePtr OpPC)
Definition Interp.h:2065
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK, bool WillActivate)
Definition Interp.cpp:291
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:645
PRESERVE_NONE bool EndSpeculation(InterpState &S, CodePtr &OpPC)
Definition Interp.h:3347
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition Interp.h:3263
bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
Definition Interp.h:1679
bool FinishInitActivatePop(InterpState &S, CodePtr OpPC)
Definition Interp.h:1937
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition Interp.h:1545
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition Interp.cpp:527
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1806
static bool Activate(InterpState &S, CodePtr OpPC)
Definition Interp.h:2045
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
Definition Interp.cpp:2122
PRESERVE_NONE bool RetVoid(InterpState &S, CodePtr &PC)
Definition Interp.h:269
bool Mulc(InterpState &S, CodePtr OpPC)
Definition Interp.h:400
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:3129
bool NE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1324
bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, bool SrcIsVoidPtr)
Definition Interp.cpp:1531
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition Interp.h:3270
llvm::FixedPointSemantics FixedPointSemantics
Definition Interp.h:52
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition Interp.cpp:774
static bool FnPtrCast(InterpState &S, CodePtr OpPC)
Definition Interp.h:2763
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.h:2816
bool Shl(InterpState &S, CodePtr OpPC)
Definition Interp.h:3038
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:2880
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition Interp.h:2697
constexpr bool isPtrType(PrimType T)
Definition PrimType.h:54
bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:1035
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, ArrayRef< int64_t > ArrayIndices, int64_t &IntResult)
Interpret an offsetof operation.
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition Interp.h:2412
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:191
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:601
bool CheckBCPResult(InterpState &S, const Pointer &Ptr)
Definition Interp.cpp:271
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition Interp.cpp:505
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.h:2590
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:3111
bool Store(InterpState &S, CodePtr OpPC)
Definition Interp.h:2022
bool Divc(InterpState &S, CodePtr OpPC)
Definition Interp.h:468
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:1458
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition Interp.h:3160
bool This(InterpState &S, CodePtr OpPC)
Definition Interp.h:2854
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:2521
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition Interp.cpp:1091
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:1699
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.h:1799
llvm::APFloat APFloat
Definition Floating.h:27
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition Interp.h:1081
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition Interp.h:3736
bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
Definition Interp.h:973
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition Interp.cpp:399
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:2617
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition Interp.h:3239
bool PushCC(InterpState &S, CodePtr OpPC, bool Value)
Definition Interp.h:3355
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK, const Type *TargetType)
Definition Interp.h:1826
bool DiagTypeid(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:2238
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition Interp.cpp:823
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:1618
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1419
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition Interp.h:3435
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:561
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition Interp.h:145
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
llvm::APInt APInt
Definition FixedPoint.h:19
bool PushIgnoreDiags(InterpState &S, CodePtr OpPC)
Definition Interp.h:3316
FixedPoint ReadArg< FixedPoint >(InterpState &S, CodePtr &OpPC)
Definition Interp.h:3780
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition Interp.h:2724
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition Interp.cpp:1369
bool CastMemberPtrDerivedPop(InterpState &S, CodePtr OpPC, int32_t Off, const RecordDecl *BaseDecl)
BaseToDerivedMemberPointer.
Definition Interp.cpp:2525
bool StartLifetime(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:1934
bool PopIgnoreDiags(InterpState &S, CodePtr OpPC)
Definition Interp.h:3327
bool LE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1338
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
Definition Interp.h:3628
bool Unsupported(InterpState &S, CodePtr OpPC)
Just emit a diagnostic.
Definition Interp.h:3309
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
Definition Interp.cpp:1151
bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition Interp.h:939
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition Interp.cpp:494
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:1118
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:1044
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition Interp.h:2551
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition Primitives.h:25
bool PushMSVCCE(InterpState &S, CodePtr OpPC)
Definition Interp.h:3364
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:33
bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
Definition Interp.h:950
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1518
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2111
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CanOverflow, UnsignedOrNone BitWidth=std::nullopt)
Definition Interp.h:757
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.h:1441
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition Interp.cpp:1586
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:2459
constexpr bool needsAlloc()
Definition PrimType.h:130
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
Definition Interp.h:3618
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition Interp.h:3521
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.cpp:2135
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:2263
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition Interp.h:2708
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:622
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition Interp.h:1963
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:1984
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
Definition Interp.h:3281
bool InitThisBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
Definition Interp.h:1662
bool Dump(InterpState &S, CodePtr OpPC)
Definition Interp.h:1948
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition Interp.h:3406
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition Interp.h:2771
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition Interp.cpp:1390
bool IsNonNull(InterpState &S, CodePtr OpPC)
Definition Interp.h:2842
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.h:1816
bool CtorCheck(InterpState &S, CodePtr OpPC)
Abort without a diagnostic if we're checking for a potential constant expression and this is not the ...
Definition Interp.h:3388
bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F)
Definition Interp.h:1407
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition Interp.cpp:391
bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1645
bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, unsigned BitWidth)
Definition Interp.h:844
bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero)
1) Pops a Pointer from the stack.
Definition Interp.h:2472
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.h:1860
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1450
bool StoreActivatePop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2080
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
Definition Interp.h:3296
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition Interp.h:1048
static bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem)
Definition Interp.h:2740
bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:671
bool CheckThis(InterpState &S, CodePtr OpPC)
Checks the 'this' pointer.
Definition Interp.cpp:1027
bool FinishInitGlobal(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:2386
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition Interp.h:3478
static bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:2052
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition Interp.h:1971
bool StorePop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2034
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
Definition Interp.cpp:219
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition Interp.h:1435
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition Interp.h:1921
bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T)
Definition Interp.h:3394
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition Interp.h:2669
bool CastMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off, const RecordDecl *BaseDecl)
DerivedToBaseMemberPointer.
Definition Interp.cpp:2513
bool Mul(InterpState &S, CodePtr OpPC)
Definition Interp.h:378
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:2187
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.cpp:2433
bool Pop(InterpState &S, CodePtr OpPC)
Definition Interp.h:1371
bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
Definition Interp.h:923
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:23
bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
Definition Interp.h:895
bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition Interp.h:912
bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC)
Definition Interp.h:2126
bool CheckPseudoDtor(InterpState &S, CodePtr OpPC)
Definition Interp.h:3415
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition Interp.cpp:1271
bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow)
Definition Interp.h:963
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition Interp.cpp:2075
bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems)
bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE, uint32_t BuiltinID)
Definition Interp.cpp:1842
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Definition Interp.cpp:752
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition Interp.h:1914
bool Neg(InterpState &S, CodePtr OpPC)
Definition Interp.h:702
bool StartSpeculation(InterpState &S, CodePtr OpPC)
Definition Interp.h:3337
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition Interp.cpp:373
std::optional< Pointer > OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr, bool IsPointerArith=false)
Definition Interp.h:2286
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:581
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition Interp.h:1066
bool Inv(InterpState &S, CodePtr OpPC)
Definition Interp.h:691
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool WillBeActivated)
Checks if a value can be stored in a block.
Definition Interp.cpp:854
bool Load(InterpState &S, CodePtr OpPC)
Definition Interp.h:1996
bool isConstexprUnknown(const Pointer &P)
Definition Interp.cpp:261
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1557
bool Cast(InterpState &S, CodePtr OpPC)
Definition Interp.h:2542
bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC)
Definition Interp.h:2144
bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow)
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 EQ(InterpState &S, CodePtr OpPC)
Definition Interp.h:1292
bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:1015
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK)
Definition Interp.h:1881
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:1490
bool Add(InterpState &S, CodePtr OpPC)
Definition Interp.h:338
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition Interp.h:1250
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition Interp.h:2399
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition Interp.h:1396
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition Interp.cpp:644
bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
Definition Interp.h:860
constexpr bool isIntegerType(PrimType T)
Definition PrimType.h:52
bool Memcpy(InterpState &S, CodePtr OpPC)
Definition Interp.h:2253
bool GE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1353
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition Interp.cpp:1853
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition Interp.h:1140
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
Definition Interp.h:2750
PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC)
Definition Interp.h:246
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition Interp.cpp:1756
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
Definition Interp.h:2602
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition Interp.h:1069
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition Interp.cpp:558
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
Definition Interp.h:2560
bool PopMSVCCE(InterpState &S, CodePtr OpPC)
Definition Interp.h:3370
bool EnableLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:2526
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
Definition Interp.h:3575
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1533
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:366
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition Interp.h:1980
llvm::APSInt APSInt
Definition FixedPoint.h:20
bool GetLocalEnabled(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:2532
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1563
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Definition Interp.cpp:2398
bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS, APSInt RHS, LT *Result)
A version of DoShift that works on IntegralAP.
Definition Interp.h:2975
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
Definition Interp.h:2271
bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.h:1714
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition Interp.cpp:1496
bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
Definition Interp.h:871
bool Flip(InterpState &S, CodePtr OpPC)
[Value1, Value2] -> [Value2, Value1]
Definition Interp.h:1378
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition Interp.h:1299
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:2578
bool Invalid(InterpState &S, CodePtr OpPC)
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition Interp.h:1086
bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
Definition Interp.h:1025
bool Assume(InterpState &S, CodePtr OpPC)
Definition Interp.h:3422
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.h:1904
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)
Definition Interp.h:985
static bool IsConstantContext(InterpState &S, CodePtr OpPC)
Definition Interp.h:3613
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition Interp.h:3536
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition Interp.h:3465
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ 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:44
@ CSK_ArrayToPointer
Definition State.h:48
@ CSK_Derived
Definition State.h:46
@ CSK_Base
Definition State.h:45
@ CSK_ArrayIndex
Definition State.h:49
@ CSK_Field
Definition State.h:47
@ Result
The result type of a method or function.
Definition TypeBase.h:905
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition State.h:28
@ AK_Increment
Definition State.h:32
@ AK_Read
Definition State.h:29
@ AK_Assign
Definition State.h:31
@ AK_Decrement
Definition State.h:33
@ ConstantFold
Fold the expression to a constant.
Definition State.h:69
U cast(CodeGen::Address addr)
Definition Address.h:327
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition Expr.h:636
A quantity in bits.
size_t getQuantity() const
unsigned Base
Start of the current subfield.
Definition Pointer.h:40
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:38
Describes a memory block created by an allocation site.
Definition Descriptor.h:121
unsigned getSize() const
Returns the size of the object without metadata.
Definition Descriptor.h:235
QualType getType() const
PrimType getPrimType() const
Definition Descriptor.h:240
const Expr * asExpr() const
Definition Descriptor.h:211
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:270
const Function * Func
Definition Pointer.h:57
Descriptor used for global variables.
Definition Descriptor.h:50
const Descriptor * Desc
Definition Pointer.h:48
Mapping from primitive types to their representation.
Definition PrimType.h:140