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