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