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