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