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