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