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