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