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