clang 20.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 "Boolean.h"
18#include "DynamicAllocator.h"
19#include "Floating.h"
20#include "Function.h"
21#include "FunctionPointer.h"
22#include "InterpFrame.h"
23#include "InterpStack.h"
24#include "InterpState.h"
25#include "MemberPointer.h"
26#include "Opcode.h"
27#include "PrimType.h"
28#include "Program.h"
29#include "State.h"
31#include "clang/AST/Expr.h"
32#include "llvm/ADT/APFloat.h"
33#include "llvm/ADT/APSInt.h"
34#include <type_traits>
35
36namespace clang {
37namespace interp {
38
39using APSInt = llvm::APSInt;
40
41/// Convert a value to an APValue.
42template <typename T>
43bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
44 R = V.toAPValue(S.getCtx());
45 return true;
46}
47
48/// Checks if the variable has externally defined storage.
49bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50
51/// Checks if the array is offsetable.
52bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53
54/// Checks if a pointer is live and accessible.
55bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56 AccessKinds AK);
57
58/// Checks if a pointer is a dummy pointer.
59bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60 AccessKinds AK);
61
62/// Checks if a pointer is null.
63bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
65
66/// Checks if a pointer is in range.
67bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 AccessKinds AK);
69
70/// Checks if a field from which a pointer is going to be derived is valid.
71bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
73
74/// Checks if Ptr is a one-past-the-end pointer.
75bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
77
78/// Checks if the dowcast using the given offset is possible with the given
79/// pointer.
80bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
81 uint32_t Offset);
82
83/// Checks if a pointer points to const storage.
84bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86/// Checks if the Descriptor is of a constexpr or const global variable.
87bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
88
89/// Checks if a pointer points to a mutable field.
90bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
91
92/// Checks if a value can be loaded from a block.
93bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
94 AccessKinds AK = AK_Read);
95bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
96
97bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
98 AccessKinds AK);
99/// Check if a global variable is initialized.
100bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
101
102/// Checks if a value can be stored in a block.
103bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
104
105/// Checks if a method can be invoked on an object.
106bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
107
108/// Checks if a value can be initialized.
109bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
110
111/// Checks if a method can be called.
112bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
113
114/// Checks if calling the currently active function would exceed
115/// the allowed call depth.
116bool CheckCallDepth(InterpState &S, CodePtr OpPC);
117
118/// Checks the 'this' pointer.
119bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
120
121/// Checks if a method is pure virtual.
122bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
123
124/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
125bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
126 const CallExpr *CE, unsigned ArgSize);
127
128/// Checks if dynamic memory allocation is available in the current
129/// language mode.
130bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
131
132/// Diagnose mismatched new[]/delete or new/delete[] pairs.
133bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
134 bool DeleteIsArray, const Descriptor *D,
135 const Expr *NewExpr);
136
137/// Check the source of the pointer passed to delete/delete[] has actually
138/// been heap allocated by us.
139bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
140 const Pointer &Ptr);
141
142/// Sets the given integral value to the pointer, which is of
143/// a std::{weak,partial,strong}_ordering type.
144bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
145 const Pointer &Ptr, const APSInt &IntValue);
146
147/// Copy the contents of Src into Dest.
148bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
149
150/// Checks if the shift operation is legal.
151template <typename LT, typename RT>
152bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
153 unsigned Bits) {
154 if (RHS.isNegative()) {
155 const SourceInfo &Loc = S.Current->getSource(OpPC);
156 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
157 if (!S.noteUndefinedBehavior())
158 return false;
159 }
160
161 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
162 // the shifted type.
163 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
164 const Expr *E = S.Current->getExpr(OpPC);
165 const APSInt Val = RHS.toAPSInt();
166 QualType Ty = E->getType();
167 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
168 if (!S.noteUndefinedBehavior())
169 return false;
170 }
171
172 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
173 const Expr *E = S.Current->getExpr(OpPC);
174 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
175 // operand, and must not overflow the corresponding unsigned type.
176 if (LHS.isNegative()) {
177 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
178 if (!S.noteUndefinedBehavior())
179 return false;
180 } else if (LHS.toUnsigned().countLeadingZeros() <
181 static_cast<unsigned>(RHS)) {
182 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
183 if (!S.noteUndefinedBehavior())
184 return false;
185 }
186 }
187
188 // C++2a [expr.shift]p2: [P0907R4]:
189 // E1 << E2 is the unique value congruent to
190 // E1 x 2^E2 module 2^N.
191 return true;
192}
193
194/// Checks if Div/Rem operation on LHS and RHS is valid.
195template <typename T>
196bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
197 if (RHS.isZero()) {
198 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
199 if constexpr (std::is_same_v<T, Floating>) {
200 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
201 << Op->getRHS()->getSourceRange();
202 return true;
203 }
204
205 S.FFDiag(Op, diag::note_expr_divide_by_zero)
206 << Op->getRHS()->getSourceRange();
207 return false;
208 }
209
210 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
211 APSInt LHSInt = LHS.toAPSInt();
212 SmallString<32> Trunc;
213 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
214 const SourceInfo &Loc = S.Current->getSource(OpPC);
215 const Expr *E = S.Current->getExpr(OpPC);
216 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
217 return false;
218 }
219 return true;
220}
221
222template <typename SizeT>
223bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
224 unsigned ElemSize, bool IsNoThrow) {
225 // FIXME: Both the SizeT::from() as well as the
226 // NumElements.toAPSInt() in this function are rather expensive.
227
228 // FIXME: GH63562
229 // APValue stores array extents as unsigned,
230 // so anything that is greater that unsigned would overflow when
231 // constructing the array, we catch this here.
232 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
233 if (NumElements->toAPSInt().getActiveBits() >
235 *NumElements > MaxElements) {
236 if (!IsNoThrow) {
237 const SourceInfo &Loc = S.Current->getSource(OpPC);
238 S.FFDiag(Loc, diag::note_constexpr_new_too_large)
239 << NumElements->toDiagnosticString(S.getCtx());
240 }
241 return false;
242 }
243 return true;
244}
245
246/// Checks if the result of a floating-point operation is valid
247/// in the current context.
248bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
249 APFloat::opStatus Status);
250
251/// Checks why the given DeclRefExpr is invalid.
252bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
253
254/// Interpreter entry point.
255bool Interpret(InterpState &S, APValue &Result);
256
257/// Interpret a builtin function.
258bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
259 const CallExpr *Call);
260
261/// Interpret an offsetof operation.
262bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
263 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
264
265inline bool Invalid(InterpState &S, CodePtr OpPC);
266
267enum class ArithOp { Add, Sub };
268
269//===----------------------------------------------------------------------===//
270// Returning values
271//===----------------------------------------------------------------------===//
272
273void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
274
275template <PrimType Name, class T = typename PrimConv<Name>::T>
277 const T &Ret = S.Stk.pop<T>();
278
279 // Make sure returned pointers are live. We might be trying to return a
280 // pointer or reference to a local variable.
281 // Just return false, since a diagnostic has already been emitted in Sema.
282 if constexpr (std::is_same_v<T, Pointer>) {
283 // FIXME: We could be calling isLive() here, but the emitted diagnostics
284 // seem a little weird, at least if the returned expression is of
285 // pointer type.
286 // Null pointers are considered live here.
287 if (!Ret.isZero() && !Ret.isLive())
288 return false;
289 }
290
291 assert(S.Current);
292 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
293 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
295
296 if (InterpFrame *Caller = S.Current->Caller) {
297 PC = S.Current->getRetPC();
298 delete S.Current;
299 S.Current = Caller;
300 S.Stk.push<T>(Ret);
301 } else {
302 delete S.Current;
303 S.Current = nullptr;
304 if (!ReturnValue<T>(S, Ret, Result))
305 return false;
306 }
307 return true;
308}
309
310inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
311 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
312
313 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
315
316 if (InterpFrame *Caller = S.Current->Caller) {
317 PC = S.Current->getRetPC();
318 delete S.Current;
319 S.Current = Caller;
320 } else {
321 delete S.Current;
322 S.Current = nullptr;
323 }
324 return true;
325}
326
327//===----------------------------------------------------------------------===//
328// Add, Sub, Mul
329//===----------------------------------------------------------------------===//
330
331template <typename T, bool (*OpFW)(T, T, unsigned, T *),
332 template <typename U> class OpAP>
333bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
334 const T &RHS) {
335 // Fast path - add the numbers with fixed width.
336 T Result;
337 if (!OpFW(LHS, RHS, Bits, &Result)) {
338 S.Stk.push<T>(Result);
339 return true;
340 }
341
342 // If for some reason evaluation continues, use the truncated results.
343 S.Stk.push<T>(Result);
344
345 // Slow path - compute the result using another bit of precision.
346 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
347
348 // Report undefined behaviour, stopping if required.
349 const Expr *E = S.Current->getExpr(OpPC);
350 QualType Type = E->getType();
351 if (S.checkingForUndefinedBehavior()) {
352 SmallString<32> Trunc;
353 Value.trunc(Result.bitWidth())
354 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
355 /*UpperCase=*/true, /*InsertSeparators=*/true);
356 auto Loc = E->getExprLoc();
357 S.report(Loc, diag::warn_integer_constant_overflow)
358 << Trunc << Type << E->getSourceRange();
359 }
360
361 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
362
363 if (!S.noteUndefinedBehavior()) {
364 S.Stk.pop<T>();
365 return false;
366 }
367
368 return true;
369}
370
371template <PrimType Name, class T = typename PrimConv<Name>::T>
372bool Add(InterpState &S, CodePtr OpPC) {
373 const T &RHS = S.Stk.pop<T>();
374 const T &LHS = S.Stk.pop<T>();
375 const unsigned Bits = RHS.bitWidth() + 1;
376 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
377}
378
379inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
380 const Floating &RHS = S.Stk.pop<Floating>();
381 const Floating &LHS = S.Stk.pop<Floating>();
382
384 auto Status = Floating::add(LHS, RHS, RM, &Result);
385 S.Stk.push<Floating>(Result);
386 return CheckFloatResult(S, OpPC, Result, Status);
387}
388
389template <PrimType Name, class T = typename PrimConv<Name>::T>
390bool Sub(InterpState &S, CodePtr OpPC) {
391 const T &RHS = S.Stk.pop<T>();
392 const T &LHS = S.Stk.pop<T>();
393 const unsigned Bits = RHS.bitWidth() + 1;
394 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
395}
396
397inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
398 const Floating &RHS = S.Stk.pop<Floating>();
399 const Floating &LHS = S.Stk.pop<Floating>();
400
402 auto Status = Floating::sub(LHS, RHS, RM, &Result);
403 S.Stk.push<Floating>(Result);
404 return CheckFloatResult(S, OpPC, Result, Status);
405}
406
407template <PrimType Name, class T = typename PrimConv<Name>::T>
408bool Mul(InterpState &S, CodePtr OpPC) {
409 const T &RHS = S.Stk.pop<T>();
410 const T &LHS = S.Stk.pop<T>();
411 const unsigned Bits = RHS.bitWidth() * 2;
412 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
413}
414
415inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
416 const Floating &RHS = S.Stk.pop<Floating>();
417 const Floating &LHS = S.Stk.pop<Floating>();
418
420 auto Status = Floating::mul(LHS, RHS, RM, &Result);
421 S.Stk.push<Floating>(Result);
422 return CheckFloatResult(S, OpPC, Result, Status);
423}
424
425template <PrimType Name, class T = typename PrimConv<Name>::T>
426inline bool Mulc(InterpState &S, CodePtr OpPC) {
427 const Pointer &RHS = S.Stk.pop<Pointer>();
428 const Pointer &LHS = S.Stk.pop<Pointer>();
429 const Pointer &Result = S.Stk.peek<Pointer>();
430
431 if constexpr (std::is_same_v<T, Floating>) {
432 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
433 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
434 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
435 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
436
437 APFloat ResR(A.getSemantics());
438 APFloat ResI(A.getSemantics());
439 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
440
441 // Copy into the result.
442 Result.atIndex(0).deref<Floating>() = Floating(ResR);
443 Result.atIndex(0).initialize();
444 Result.atIndex(1).deref<Floating>() = Floating(ResI);
445 Result.atIndex(1).initialize();
446 Result.initialize();
447 } else {
448 // Integer element type.
449 const T &LHSR = LHS.atIndex(0).deref<T>();
450 const T &LHSI = LHS.atIndex(1).deref<T>();
451 const T &RHSR = RHS.atIndex(0).deref<T>();
452 const T &RHSI = RHS.atIndex(1).deref<T>();
453 unsigned Bits = LHSR.bitWidth();
454
455 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
456 T A;
457 if (T::mul(LHSR, RHSR, Bits, &A))
458 return false;
459 T B;
460 if (T::mul(LHSI, RHSI, Bits, &B))
461 return false;
462 if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
463 return false;
464 Result.atIndex(0).initialize();
465
466 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
467 if (T::mul(LHSR, RHSI, Bits, &A))
468 return false;
469 if (T::mul(LHSI, RHSR, Bits, &B))
470 return false;
471 if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
472 return false;
473 Result.atIndex(1).initialize();
474 Result.initialize();
475 }
476
477 return true;
478}
479
480template <PrimType Name, class T = typename PrimConv<Name>::T>
481inline bool Divc(InterpState &S, CodePtr OpPC) {
482 const Pointer &RHS = S.Stk.pop<Pointer>();
483 const Pointer &LHS = S.Stk.pop<Pointer>();
484 const Pointer &Result = S.Stk.peek<Pointer>();
485
486 if constexpr (std::is_same_v<T, Floating>) {
487 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
488 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
489 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
490 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
491
492 APFloat ResR(A.getSemantics());
493 APFloat ResI(A.getSemantics());
494 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
495
496 // Copy into the result.
497 Result.atIndex(0).deref<Floating>() = Floating(ResR);
498 Result.atIndex(0).initialize();
499 Result.atIndex(1).deref<Floating>() = Floating(ResI);
500 Result.atIndex(1).initialize();
501 Result.initialize();
502 } else {
503 // Integer element type.
504 const T &LHSR = LHS.atIndex(0).deref<T>();
505 const T &LHSI = LHS.atIndex(1).deref<T>();
506 const T &RHSR = RHS.atIndex(0).deref<T>();
507 const T &RHSI = RHS.atIndex(1).deref<T>();
508 unsigned Bits = LHSR.bitWidth();
509 const T Zero = T::from(0, Bits);
510
513 const SourceInfo &E = S.Current->getSource(OpPC);
514 S.FFDiag(E, diag::note_expr_divide_by_zero);
515 return false;
516 }
517
518 // Den = real(RHS)² + imag(RHS)²
519 T A, B;
520 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
521 return false;
522 T Den;
523 if (T::add(A, B, Bits, &Den))
524 return false;
525
526 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
527 T &ResultR = Result.atIndex(0).deref<T>();
528 T &ResultI = Result.atIndex(1).deref<T>();
529
530 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
531 return false;
532 if (T::add(A, B, Bits, &ResultR))
533 return false;
534 if (T::div(ResultR, Den, Bits, &ResultR))
535 return false;
536 Result.atIndex(0).initialize();
537
538 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
539 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
540 return false;
541 if (T::sub(A, B, Bits, &ResultI))
542 return false;
543 if (T::div(ResultI, Den, Bits, &ResultI))
544 return false;
545 Result.atIndex(1).initialize();
546 Result.initialize();
547 }
548
549 return true;
550}
551
552/// 1) Pops the RHS from the stack.
553/// 2) Pops the LHS from the stack.
554/// 3) Pushes 'LHS & RHS' on the stack
555template <PrimType Name, class T = typename PrimConv<Name>::T>
556bool BitAnd(InterpState &S, CodePtr OpPC) {
557 const T &RHS = S.Stk.pop<T>();
558 const T &LHS = S.Stk.pop<T>();
559
560 unsigned Bits = RHS.bitWidth();
561 T Result;
562 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
563 S.Stk.push<T>(Result);
564 return true;
565 }
566 return false;
567}
568
569/// 1) Pops the RHS from the stack.
570/// 2) Pops the LHS from the stack.
571/// 3) Pushes 'LHS | RHS' on the stack
572template <PrimType Name, class T = typename PrimConv<Name>::T>
573bool BitOr(InterpState &S, CodePtr OpPC) {
574 const T &RHS = S.Stk.pop<T>();
575 const T &LHS = S.Stk.pop<T>();
576
577 unsigned Bits = RHS.bitWidth();
578 T Result;
579 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
580 S.Stk.push<T>(Result);
581 return true;
582 }
583 return false;
584}
585
586/// 1) Pops the RHS from the stack.
587/// 2) Pops the LHS from the stack.
588/// 3) Pushes 'LHS ^ RHS' on the stack
589template <PrimType Name, class T = typename PrimConv<Name>::T>
590bool BitXor(InterpState &S, CodePtr OpPC) {
591 const T &RHS = S.Stk.pop<T>();
592 const T &LHS = S.Stk.pop<T>();
593
594 unsigned Bits = RHS.bitWidth();
595 T Result;
596 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
597 S.Stk.push<T>(Result);
598 return true;
599 }
600 return false;
601}
602
603/// 1) Pops the RHS from the stack.
604/// 2) Pops the LHS from the stack.
605/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
606template <PrimType Name, class T = typename PrimConv<Name>::T>
607bool Rem(InterpState &S, CodePtr OpPC) {
608 const T &RHS = S.Stk.pop<T>();
609 const T &LHS = S.Stk.pop<T>();
610
611 if (!CheckDivRem(S, OpPC, LHS, RHS))
612 return false;
613
614 const unsigned Bits = RHS.bitWidth() * 2;
615 T Result;
616 if (!T::rem(LHS, RHS, Bits, &Result)) {
617 S.Stk.push<T>(Result);
618 return true;
619 }
620 return false;
621}
622
623/// 1) Pops the RHS from the stack.
624/// 2) Pops the LHS from the stack.
625/// 3) Pushes 'LHS / RHS' on the stack
626template <PrimType Name, class T = typename PrimConv<Name>::T>
627bool Div(InterpState &S, CodePtr OpPC) {
628 const T &RHS = S.Stk.pop<T>();
629 const T &LHS = S.Stk.pop<T>();
630
631 if (!CheckDivRem(S, OpPC, LHS, RHS))
632 return false;
633
634 const unsigned Bits = RHS.bitWidth() * 2;
635 T Result;
636 if (!T::div(LHS, RHS, Bits, &Result)) {
637 S.Stk.push<T>(Result);
638 return true;
639 }
640 return false;
641}
642
643inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
644 const Floating &RHS = S.Stk.pop<Floating>();
645 const Floating &LHS = S.Stk.pop<Floating>();
646
647 if (!CheckDivRem(S, OpPC, LHS, RHS))
648 return false;
649
651 auto Status = Floating::div(LHS, RHS, RM, &Result);
652 S.Stk.push<Floating>(Result);
653 return CheckFloatResult(S, OpPC, Result, Status);
654}
655
656//===----------------------------------------------------------------------===//
657// Inv
658//===----------------------------------------------------------------------===//
659
660inline bool Inv(InterpState &S, CodePtr OpPC) {
661 const auto &Val = S.Stk.pop<Boolean>();
662 S.Stk.push<Boolean>(!Val);
663 return true;
664}
665
666//===----------------------------------------------------------------------===//
667// Neg
668//===----------------------------------------------------------------------===//
669
670template <PrimType Name, class T = typename PrimConv<Name>::T>
671bool Neg(InterpState &S, CodePtr OpPC) {
672 const T &Value = S.Stk.pop<T>();
673 T Result;
674
675 if (!T::neg(Value, &Result)) {
676 S.Stk.push<T>(Result);
677 return true;
678 }
679
680 assert(isIntegralType(Name) &&
681 "don't expect other types to fail at constexpr negation");
682 S.Stk.push<T>(Result);
683
684 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
685 const Expr *E = S.Current->getExpr(OpPC);
686 QualType Type = E->getType();
687
688 if (S.checkingForUndefinedBehavior()) {
689 SmallString<32> Trunc;
690 NegatedValue.trunc(Result.bitWidth())
691 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
692 /*UpperCase=*/true, /*InsertSeparators=*/true);
693 auto Loc = E->getExprLoc();
694 S.report(Loc, diag::warn_integer_constant_overflow)
695 << Trunc << Type << E->getSourceRange();
696 return true;
697 }
698
699 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
700 return S.noteUndefinedBehavior();
701}
702
703enum class PushVal : bool {
704 No,
705 Yes,
706};
707enum class IncDecOp {
708 Inc,
709 Dec,
710};
711
712template <typename T, IncDecOp Op, PushVal DoPush>
713bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
714 assert(!Ptr.isDummy());
715
716 if constexpr (std::is_same_v<T, Boolean>) {
717 if (!S.getLangOpts().CPlusPlus14)
718 return Invalid(S, OpPC);
719 }
720
721 const T &Value = Ptr.deref<T>();
722 T Result;
723
724 if constexpr (DoPush == PushVal::Yes)
725 S.Stk.push<T>(Value);
726
727 if constexpr (Op == IncDecOp::Inc) {
728 if (!T::increment(Value, &Result)) {
729 Ptr.deref<T>() = Result;
730 return true;
731 }
732 } else {
733 if (!T::decrement(Value, &Result)) {
734 Ptr.deref<T>() = Result;
735 return true;
736 }
737 }
738
739 // Something went wrong with the previous operation. Compute the
740 // result with another bit of precision.
741 unsigned Bits = Value.bitWidth() + 1;
742 APSInt APResult;
743 if constexpr (Op == IncDecOp::Inc)
744 APResult = ++Value.toAPSInt(Bits);
745 else
746 APResult = --Value.toAPSInt(Bits);
747
748 // Report undefined behaviour, stopping if required.
749 const Expr *E = S.Current->getExpr(OpPC);
750 QualType Type = E->getType();
751 if (S.checkingForUndefinedBehavior()) {
752 SmallString<32> Trunc;
753 APResult.trunc(Result.bitWidth())
754 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
755 /*UpperCase=*/true, /*InsertSeparators=*/true);
756 auto Loc = E->getExprLoc();
757 S.report(Loc, diag::warn_integer_constant_overflow)
758 << Trunc << Type << E->getSourceRange();
759 return true;
760 }
761
762 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
763 return S.noteUndefinedBehavior();
764}
765
766/// 1) Pops a pointer from the stack
767/// 2) Load the value from the pointer
768/// 3) Writes the value increased by one back to the pointer
769/// 4) Pushes the original (pre-inc) value on the stack.
770template <PrimType Name, class T = typename PrimConv<Name>::T>
771bool Inc(InterpState &S, CodePtr OpPC) {
772 const Pointer &Ptr = S.Stk.pop<Pointer>();
773 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
774 return false;
775
776 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
777}
778
779/// 1) Pops a pointer from the stack
780/// 2) Load the value from the pointer
781/// 3) Writes the value increased by one back to the pointer
782template <PrimType Name, class T = typename PrimConv<Name>::T>
783bool IncPop(InterpState &S, CodePtr OpPC) {
784 const Pointer &Ptr = S.Stk.pop<Pointer>();
785 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
786 return false;
787
788 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
789}
790
791/// 1) Pops a pointer from the stack
792/// 2) Load the value from the pointer
793/// 3) Writes the value decreased by one back to the pointer
794/// 4) Pushes the original (pre-dec) value on the stack.
795template <PrimType Name, class T = typename PrimConv<Name>::T>
796bool Dec(InterpState &S, CodePtr OpPC) {
797 const Pointer &Ptr = S.Stk.pop<Pointer>();
798 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
799 return false;
800
801 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
802}
803
804/// 1) Pops a pointer from the stack
805/// 2) Load the value from the pointer
806/// 3) Writes the value decreased by one back to the pointer
807template <PrimType Name, class T = typename PrimConv<Name>::T>
808bool DecPop(InterpState &S, CodePtr OpPC) {
809 const Pointer &Ptr = S.Stk.pop<Pointer>();
810 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
811 return false;
812
813 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
814}
815
816template <IncDecOp Op, PushVal DoPush>
818 llvm::RoundingMode RM) {
819 Floating Value = Ptr.deref<Floating>();
821
822 if constexpr (DoPush == PushVal::Yes)
823 S.Stk.push<Floating>(Value);
824
825 llvm::APFloat::opStatus Status;
826 if constexpr (Op == IncDecOp::Inc)
827 Status = Floating::increment(Value, RM, &Result);
828 else
829 Status = Floating::decrement(Value, RM, &Result);
830
831 Ptr.deref<Floating>() = Result;
832
833 return CheckFloatResult(S, OpPC, Result, Status);
834}
835
836inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
837 const Pointer &Ptr = S.Stk.pop<Pointer>();
838 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
839 return false;
840
841 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
842}
843
844inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
845 const Pointer &Ptr = S.Stk.pop<Pointer>();
846 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
847 return false;
848
849 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
850}
851
852inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
853 const Pointer &Ptr = S.Stk.pop<Pointer>();
854 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
855 return false;
856
857 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
858}
859
860inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
861 const Pointer &Ptr = S.Stk.pop<Pointer>();
862 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
863 return false;
864
865 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
866}
867
868/// 1) Pops the value from the stack.
869/// 2) Pushes the bitwise complemented value on the stack (~V).
870template <PrimType Name, class T = typename PrimConv<Name>::T>
871bool Comp(InterpState &S, CodePtr OpPC) {
872 const T &Val = S.Stk.pop<T>();
873 T Result;
874 if (!T::comp(Val, &Result)) {
875 S.Stk.push<T>(Result);
876 return true;
877 }
878
879 return false;
880}
881
882//===----------------------------------------------------------------------===//
883// EQ, NE, GT, GE, LT, LE
884//===----------------------------------------------------------------------===//
885
886using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
887
888template <typename T>
890 assert((!std::is_same_v<T, MemberPointer>) &&
891 "Non-equality comparisons on member pointer types should already be "
892 "rejected in Sema.");
893 using BoolT = PrimConv<PT_Bool>::T;
894 const T &RHS = S.Stk.pop<T>();
895 const T &LHS = S.Stk.pop<T>();
896 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
897 return true;
898}
899
900template <typename T>
902 return CmpHelper<T>(S, OpPC, Fn);
903}
904
905/// Function pointers cannot be compared in an ordered way.
906template <>
908 CompareFn Fn) {
909 const auto &RHS = S.Stk.pop<FunctionPointer>();
910 const auto &LHS = S.Stk.pop<FunctionPointer>();
911
912 const SourceInfo &Loc = S.Current->getSource(OpPC);
913 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
914 << LHS.toDiagnosticString(S.getCtx())
915 << RHS.toDiagnosticString(S.getCtx());
916 return false;
917}
918
919template <>
921 CompareFn Fn) {
922 const auto &RHS = S.Stk.pop<FunctionPointer>();
923 const auto &LHS = S.Stk.pop<FunctionPointer>();
924
925 // We cannot compare against weak declarations at compile time.
926 for (const auto &FP : {LHS, RHS}) {
927 if (FP.isWeak()) {
928 const SourceInfo &Loc = S.Current->getSource(OpPC);
929 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
930 << FP.toDiagnosticString(S.getCtx());
931 return false;
932 }
933 }
934
935 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
936 return true;
937}
938
939template <>
941 using BoolT = PrimConv<PT_Bool>::T;
942 const Pointer &RHS = S.Stk.pop<Pointer>();
943 const Pointer &LHS = S.Stk.pop<Pointer>();
944
945 if (!Pointer::hasSameBase(LHS, RHS)) {
946 const SourceInfo &Loc = S.Current->getSource(OpPC);
947 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
948 << LHS.toDiagnosticString(S.getCtx())
949 << RHS.toDiagnosticString(S.getCtx());
950 return false;
951 } else {
952 unsigned VL = LHS.getByteOffset();
953 unsigned VR = RHS.getByteOffset();
954 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
955 return true;
956 }
957}
958
959template <>
961 using BoolT = PrimConv<PT_Bool>::T;
962 const Pointer &RHS = S.Stk.pop<Pointer>();
963 const Pointer &LHS = S.Stk.pop<Pointer>();
964
965 if (LHS.isZero() && RHS.isZero()) {
966 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
967 return true;
968 }
969
970 // Reject comparisons to weak pointers.
971 for (const auto &P : {LHS, RHS}) {
972 if (P.isZero())
973 continue;
974 if (P.isWeak()) {
975 const SourceInfo &Loc = S.Current->getSource(OpPC);
976 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
977 << P.toDiagnosticString(S.getCtx());
978 return false;
979 }
980 }
981
982 if (!Pointer::hasSameBase(LHS, RHS)) {
983 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
984 RHS.getOffset() == 0) {
985 const SourceInfo &Loc = S.Current->getSource(OpPC);
986 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
987 << LHS.toDiagnosticString(S.getCtx());
988 return false;
989 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
990 LHS.getOffset() == 0) {
991 const SourceInfo &Loc = S.Current->getSource(OpPC);
992 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
993 << RHS.toDiagnosticString(S.getCtx());
994 return false;
995 }
996
997 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
998 return true;
999 } else {
1000 unsigned VL = LHS.getByteOffset();
1001 unsigned VR = RHS.getByteOffset();
1002
1003 // In our Pointer class, a pointer to an array and a pointer to the first
1004 // element in the same array are NOT equal. They have the same Base value,
1005 // but a different Offset. This is a pretty rare case, so we fix this here
1006 // by comparing pointers to the first elements.
1007 if (!LHS.isZero() && LHS.isArrayRoot())
1008 VL = LHS.atIndex(0).getByteOffset();
1009 if (!RHS.isZero() && RHS.isArrayRoot())
1010 VR = RHS.atIndex(0).getByteOffset();
1011
1012 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1013 return true;
1014 }
1015}
1016
1017template <>
1019 CompareFn Fn) {
1020 const auto &RHS = S.Stk.pop<MemberPointer>();
1021 const auto &LHS = S.Stk.pop<MemberPointer>();
1022
1023 // If either operand is a pointer to a weak function, the comparison is not
1024 // constant.
1025 for (const auto &MP : {LHS, RHS}) {
1026 if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
1027 const SourceInfo &Loc = S.Current->getSource(OpPC);
1028 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
1029 return false;
1030 }
1031 }
1032
1033 // C++11 [expr.eq]p2:
1034 // If both operands are null, they compare equal. Otherwise if only one is
1035 // null, they compare unequal.
1036 if (LHS.isZero() && RHS.isZero()) {
1038 return true;
1039 }
1040 if (LHS.isZero() || RHS.isZero()) {
1042 return true;
1043 }
1044
1045 // We cannot compare against virtual declarations at compile time.
1046 for (const auto &MP : {LHS, RHS}) {
1047 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1048 MD && MD->isVirtual()) {
1049 const SourceInfo &Loc = S.Current->getSource(OpPC);
1050 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1051 }
1052 }
1053
1054 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1055 return true;
1056}
1057
1058template <PrimType Name, class T = typename PrimConv<Name>::T>
1059bool EQ(InterpState &S, CodePtr OpPC) {
1060 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1062 });
1063}
1064
1065template <PrimType Name, class T = typename PrimConv<Name>::T>
1066bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1067 const T &RHS = S.Stk.pop<T>();
1068 const T &LHS = S.Stk.pop<T>();
1069 const Pointer &P = S.Stk.peek<Pointer>();
1070
1071 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1072 if (CmpResult == ComparisonCategoryResult::Unordered) {
1073 // This should only happen with pointers.
1074 const SourceInfo &Loc = S.Current->getSource(OpPC);
1075 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1076 << LHS.toDiagnosticString(S.getCtx())
1077 << RHS.toDiagnosticString(S.getCtx());
1078 return false;
1079 }
1080
1081 assert(CmpInfo);
1082 const auto *CmpValueInfo =
1083 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1084 assert(CmpValueInfo);
1085 assert(CmpValueInfo->hasValidIntValue());
1086 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1087}
1088
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1090bool NE(InterpState &S, CodePtr OpPC) {
1091 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1093 });
1094}
1095
1096template <PrimType Name, class T = typename PrimConv<Name>::T>
1097bool LT(InterpState &S, CodePtr OpPC) {
1098 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1100 });
1101}
1102
1103template <PrimType Name, class T = typename PrimConv<Name>::T>
1104bool LE(InterpState &S, CodePtr OpPC) {
1105 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1106 return R == ComparisonCategoryResult::Less ||
1108 });
1109}
1110
1111template <PrimType Name, class T = typename PrimConv<Name>::T>
1112bool GT(InterpState &S, CodePtr OpPC) {
1113 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1115 });
1116}
1117
1118template <PrimType Name, class T = typename PrimConv<Name>::T>
1119bool GE(InterpState &S, CodePtr OpPC) {
1120 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1123 });
1124}
1125
1126//===----------------------------------------------------------------------===//
1127// InRange
1128//===----------------------------------------------------------------------===//
1129
1130template <PrimType Name, class T = typename PrimConv<Name>::T>
1132 const T RHS = S.Stk.pop<T>();
1133 const T LHS = S.Stk.pop<T>();
1134 const T Value = S.Stk.pop<T>();
1135
1136 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1137 return true;
1138}
1139
1140//===----------------------------------------------------------------------===//
1141// Dup, Pop, Test
1142//===----------------------------------------------------------------------===//
1143
1144template <PrimType Name, class T = typename PrimConv<Name>::T>
1145bool Dup(InterpState &S, CodePtr OpPC) {
1146 S.Stk.push<T>(S.Stk.peek<T>());
1147 return true;
1148}
1149
1150template <PrimType Name, class T = typename PrimConv<Name>::T>
1151bool Pop(InterpState &S, CodePtr OpPC) {
1152 S.Stk.pop<T>();
1153 return true;
1154}
1155
1156/// [Value1, Value2] -> [Value2, Value1]
1157template <PrimType TopName, PrimType BottomName>
1158bool Flip(InterpState &S, CodePtr OpPC) {
1159 using TopT = typename PrimConv<TopName>::T;
1160 using BottomT = typename PrimConv<BottomName>::T;
1161
1162 const auto &Top = S.Stk.pop<TopT>();
1163 const auto &Bottom = S.Stk.pop<BottomT>();
1164
1165 S.Stk.push<TopT>(Top);
1166 S.Stk.push<BottomT>(Bottom);
1167
1168 return true;
1169}
1170
1171//===----------------------------------------------------------------------===//
1172// Const
1173//===----------------------------------------------------------------------===//
1174
1175template <PrimType Name, class T = typename PrimConv<Name>::T>
1176bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1177 S.Stk.push<T>(Arg);
1178 return true;
1179}
1180
1181//===----------------------------------------------------------------------===//
1182// Get/Set Local/Param/Global/This
1183//===----------------------------------------------------------------------===//
1184
1185template <PrimType Name, class T = typename PrimConv<Name>::T>
1186bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1187 const Pointer &Ptr = S.Current->getLocalPointer(I);
1188 if (!CheckLoad(S, OpPC, Ptr))
1189 return false;
1190 S.Stk.push<T>(Ptr.deref<T>());
1191 return true;
1192}
1193
1194/// 1) Pops the value from the stack.
1195/// 2) Writes the value to the local variable with the
1196/// given offset.
1197template <PrimType Name, class T = typename PrimConv<Name>::T>
1198bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1199 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1200 return true;
1201}
1202
1203template <PrimType Name, class T = typename PrimConv<Name>::T>
1204bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1205 if (S.checkingPotentialConstantExpression()) {
1206 return false;
1207 }
1208 S.Stk.push<T>(S.Current->getParam<T>(I));
1209 return true;
1210}
1211
1212template <PrimType Name, class T = typename PrimConv<Name>::T>
1213bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1214 S.Current->setParam<T>(I, S.Stk.pop<T>());
1215 return true;
1216}
1217
1218/// 1) Peeks a pointer on the stack
1219/// 2) Pushes the value of the pointer's field on the stack
1220template <PrimType Name, class T = typename PrimConv<Name>::T>
1221bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1222 const Pointer &Obj = S.Stk.peek<Pointer>();
1223 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1224 return false;
1225 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1226 return false;
1227 const Pointer &Field = Obj.atField(I);
1228 if (!CheckLoad(S, OpPC, Field))
1229 return false;
1230 S.Stk.push<T>(Field.deref<T>());
1231 return true;
1232}
1233
1234template <PrimType Name, class T = typename PrimConv<Name>::T>
1235bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1236 const T &Value = S.Stk.pop<T>();
1237 const Pointer &Obj = S.Stk.peek<Pointer>();
1238 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1239 return false;
1240 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1241 return false;
1242 const Pointer &Field = Obj.atField(I);
1243 if (!CheckStore(S, OpPC, Field))
1244 return false;
1245 Field.initialize();
1246 Field.deref<T>() = Value;
1247 return true;
1248}
1249
1250/// 1) Pops a pointer from the stack
1251/// 2) Pushes the value of the pointer's field on the stack
1252template <PrimType Name, class T = typename PrimConv<Name>::T>
1253bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1254 const Pointer &Obj = S.Stk.pop<Pointer>();
1255 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1256 return false;
1257 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1258 return false;
1259 const Pointer &Field = Obj.atField(I);
1260 if (!CheckLoad(S, OpPC, Field))
1261 return false;
1262 S.Stk.push<T>(Field.deref<T>());
1263 return true;
1264}
1265
1266template <PrimType Name, class T = typename PrimConv<Name>::T>
1267bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1268 if (S.checkingPotentialConstantExpression())
1269 return false;
1270 const Pointer &This = S.Current->getThis();
1271 if (!CheckThis(S, OpPC, This))
1272 return false;
1273 const Pointer &Field = This.atField(I);
1274 if (!CheckLoad(S, OpPC, Field))
1275 return false;
1276 S.Stk.push<T>(Field.deref<T>());
1277 return true;
1278}
1279
1280template <PrimType Name, class T = typename PrimConv<Name>::T>
1281bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1282 if (S.checkingPotentialConstantExpression())
1283 return false;
1284 const T &Value = S.Stk.pop<T>();
1285 const Pointer &This = S.Current->getThis();
1286 if (!CheckThis(S, OpPC, This))
1287 return false;
1288 const Pointer &Field = This.atField(I);
1289 if (!CheckStore(S, OpPC, Field))
1290 return false;
1291 Field.deref<T>() = Value;
1292 return true;
1293}
1294
1295template <PrimType Name, class T = typename PrimConv<Name>::T>
1296bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1297 const Pointer &Ptr = S.P.getPtrGlobal(I);
1298 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1299 return false;
1300 if (Ptr.isExtern())
1301 return false;
1302
1303 // If a global variable is uninitialized, that means the initializer we've
1304 // compiled for it wasn't a constant expression. Diagnose that.
1305 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1306 return false;
1307
1308 S.Stk.push<T>(Ptr.deref<T>());
1309 return true;
1310}
1311
1312/// Same as GetGlobal, but without the checks.
1313template <PrimType Name, class T = typename PrimConv<Name>::T>
1314bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1315 const Pointer &Ptr = S.P.getPtrGlobal(I);
1316 if (!Ptr.isInitialized())
1317 return false;
1318 S.Stk.push<T>(Ptr.deref<T>());
1319 return true;
1320}
1321
1322template <PrimType Name, class T = typename PrimConv<Name>::T>
1323bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1324 // TODO: emit warning.
1325 return false;
1326}
1327
1328template <PrimType Name, class T = typename PrimConv<Name>::T>
1329bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1330 const Pointer &P = S.P.getGlobal(I);
1331 P.deref<T>() = S.Stk.pop<T>();
1332 P.initialize();
1333 return true;
1334}
1335
1336/// 1) Converts the value on top of the stack to an APValue
1337/// 2) Sets that APValue on \Temp
1338/// 3) Initializes global with index \I with that
1339template <PrimType Name, class T = typename PrimConv<Name>::T>
1340bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1341 const LifetimeExtendedTemporaryDecl *Temp) {
1342 const Pointer &Ptr = S.P.getGlobal(I);
1343
1344 const T Value = S.Stk.peek<T>();
1345 APValue APV = Value.toAPValue(S.getCtx());
1346 APValue *Cached = Temp->getOrCreateValue(true);
1347 *Cached = APV;
1348
1349 assert(Ptr.getDeclDesc()->asExpr());
1350
1351 S.SeenGlobalTemporaries.push_back(
1352 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1353
1354 Ptr.deref<T>() = S.Stk.pop<T>();
1355 Ptr.initialize();
1356 return true;
1357}
1358
1359/// 1) Converts the value on top of the stack to an APValue
1360/// 2) Sets that APValue on \Temp
1361/// 3) Initialized global with index \I with that
1363 const LifetimeExtendedTemporaryDecl *Temp) {
1364 assert(Temp);
1365 const Pointer &P = S.Stk.peek<Pointer>();
1366 APValue *Cached = Temp->getOrCreateValue(true);
1367
1368 S.SeenGlobalTemporaries.push_back(
1369 std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1370
1371 if (std::optional<APValue> APV =
1372 P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
1373 *Cached = *APV;
1374 return true;
1375 }
1376
1377 return false;
1378}
1379
1380template <PrimType Name, class T = typename PrimConv<Name>::T>
1381bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1382 if (S.checkingPotentialConstantExpression())
1383 return false;
1384 const Pointer &This = S.Current->getThis();
1385 if (!CheckThis(S, OpPC, This))
1386 return false;
1387 const Pointer &Field = This.atField(I);
1388 Field.deref<T>() = S.Stk.pop<T>();
1389 Field.activate();
1390 Field.initialize();
1391 return true;
1392}
1393
1394// FIXME: The Field pointer here is too much IMO and we could instead just
1395// pass an Offset + BitWidth pair.
1396template <PrimType Name, class T = typename PrimConv<Name>::T>
1397bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1398 uint32_t FieldOffset) {
1399 assert(F->isBitField());
1400 if (S.checkingPotentialConstantExpression())
1401 return false;
1402 const Pointer &This = S.Current->getThis();
1403 if (!CheckThis(S, OpPC, This))
1404 return false;
1405 const Pointer &Field = This.atField(FieldOffset);
1406 const auto &Value = S.Stk.pop<T>();
1407 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1408 Field.initialize();
1409 return true;
1410}
1411
1412/// 1) Pops the value from the stack
1413/// 2) Peeks a pointer from the stack
1414/// 3) Pushes the value to field I of the pointer on the stack
1415template <PrimType Name, class T = typename PrimConv<Name>::T>
1416bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1417 const T &Value = S.Stk.pop<T>();
1418 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1419 Field.deref<T>() = Value;
1420 Field.activate();
1421 Field.initialize();
1422 return true;
1423}
1424
1425template <PrimType Name, class T = typename PrimConv<Name>::T>
1426bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1427 assert(F->isBitField());
1428 const T &Value = S.Stk.pop<T>();
1429 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1430 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1431 Field.activate();
1432 Field.initialize();
1433 return true;
1434}
1435
1436//===----------------------------------------------------------------------===//
1437// GetPtr Local/Param/Global/Field/This
1438//===----------------------------------------------------------------------===//
1439
1440inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1441 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1442 return true;
1443}
1444
1445inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1446 if (S.checkingPotentialConstantExpression()) {
1447 return false;
1448 }
1449 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1450 return true;
1451}
1452
1453inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1454 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1455 return true;
1456}
1457
1458/// 1) Peeks a Pointer
1459/// 2) Pushes Pointer.atField(Off) on the stack
1460inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1461 const Pointer &Ptr = S.Stk.peek<Pointer>();
1462
1463 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1464 !CheckNull(S, OpPC, Ptr, CSK_Field))
1465 return false;
1466
1467 if (!CheckExtern(S, OpPC, Ptr))
1468 return false;
1469 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1470 return false;
1471 if (!CheckArray(S, OpPC, Ptr))
1472 return false;
1473 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1474 return false;
1475
1476 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1477 return false;
1478
1479 if (Ptr.isIntegralPointer()) {
1480 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1481 return true;
1482 }
1483
1484 S.Stk.push<Pointer>(Ptr.atField(Off));
1485 return true;
1486}
1487
1488inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1489 const Pointer &Ptr = S.Stk.pop<Pointer>();
1490
1491 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1492 !CheckNull(S, OpPC, Ptr, CSK_Field))
1493 return false;
1494
1495 if (!CheckExtern(S, OpPC, Ptr))
1496 return false;
1497 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1498 return false;
1499 if (!CheckArray(S, OpPC, Ptr))
1500 return false;
1501 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1502 return false;
1503
1504 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1505 return false;
1506
1507 if (Ptr.isIntegralPointer()) {
1508 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1509 return true;
1510 }
1511
1512 S.Stk.push<Pointer>(Ptr.atField(Off));
1513 return true;
1514}
1515
1516inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1517 if (S.checkingPotentialConstantExpression())
1518 return false;
1519 const Pointer &This = S.Current->getThis();
1520 if (!CheckThis(S, OpPC, This))
1521 return false;
1522 S.Stk.push<Pointer>(This.atField(Off));
1523 return true;
1524}
1525
1526inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1527 const Pointer &Ptr = S.Stk.pop<Pointer>();
1528 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1529 return false;
1530 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1531 return false;
1532 Pointer Field = Ptr.atField(Off);
1533 Ptr.deactivate();
1534 Field.activate();
1535 S.Stk.push<Pointer>(std::move(Field));
1536 return true;
1537}
1538
1539inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1540 if (S.checkingPotentialConstantExpression())
1541 return false;
1542 const Pointer &This = S.Current->getThis();
1543 if (!CheckThis(S, OpPC, This))
1544 return false;
1545 Pointer Field = This.atField(Off);
1546 This.deactivate();
1547 Field.activate();
1548 S.Stk.push<Pointer>(std::move(Field));
1549 return true;
1550}
1551
1552inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1553 const Pointer &Ptr = S.Stk.pop<Pointer>();
1554 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1555 return false;
1556 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1557 return false;
1558 if (!CheckDowncast(S, OpPC, Ptr, Off))
1559 return false;
1560
1561 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1562 return true;
1563}
1564
1565inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1566 const Pointer &Ptr = S.Stk.peek<Pointer>();
1567 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1568 return false;
1569 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1570 return false;
1571 const Pointer &Result = Ptr.atField(Off);
1572 if (Result.isPastEnd() || !Result.isBaseClass())
1573 return false;
1574 S.Stk.push<Pointer>(Result);
1575 return true;
1576}
1577
1578inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1579 const Pointer &Ptr = S.Stk.pop<Pointer>();
1580 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1581 return false;
1582 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1583 return false;
1584 const Pointer &Result = Ptr.atField(Off);
1585 if (Result.isPastEnd() || !Result.isBaseClass())
1586 return false;
1587 S.Stk.push<Pointer>(Result);
1588 return true;
1589}
1590
1591inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1592 const auto &Ptr = S.Stk.pop<MemberPointer>();
1593 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1594 return true;
1595}
1596
1597inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1598 if (S.checkingPotentialConstantExpression())
1599 return false;
1600 const Pointer &This = S.Current->getThis();
1601 if (!CheckThis(S, OpPC, This))
1602 return false;
1603 S.Stk.push<Pointer>(This.atField(Off));
1604 return true;
1605}
1606
1607inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1608 const Pointer &Ptr = S.Stk.pop<Pointer>();
1609 if (Ptr.canBeInitialized()) {
1610 Ptr.initialize();
1611 Ptr.activate();
1612 }
1613 return true;
1614}
1615
1616inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1617 const Pointer &Ptr = S.Stk.peek<Pointer>();
1618 if (Ptr.canBeInitialized()) {
1619 Ptr.initialize();
1620 Ptr.activate();
1621 }
1622 return true;
1623}
1624
1625inline bool Dump(InterpState &S, CodePtr OpPC) {
1626 S.Stk.dump();
1627 return true;
1628}
1629
1630inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1631 const Pointer &Ptr) {
1632 Pointer Base = Ptr;
1633 while (Base.isBaseClass())
1634 Base = Base.getBase();
1635
1636 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1637 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1638 return true;
1639}
1640
1642 const RecordDecl *D) {
1643 assert(D);
1644 const Pointer &Ptr = S.Stk.pop<Pointer>();
1645 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1646 return false;
1647 return VirtBaseHelper(S, OpPC, D, Ptr);
1648}
1649
1651 const RecordDecl *D) {
1652 assert(D);
1653 if (S.checkingPotentialConstantExpression())
1654 return false;
1655 const Pointer &This = S.Current->getThis();
1656 if (!CheckThis(S, OpPC, This))
1657 return false;
1658 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1659}
1660
1661//===----------------------------------------------------------------------===//
1662// Load, Store, Init
1663//===----------------------------------------------------------------------===//
1664
1665template <PrimType Name, class T = typename PrimConv<Name>::T>
1666bool Load(InterpState &S, CodePtr OpPC) {
1667 const Pointer &Ptr = S.Stk.peek<Pointer>();
1668 if (!CheckLoad(S, OpPC, Ptr))
1669 return false;
1670 if (!Ptr.isBlockPointer())
1671 return false;
1672 S.Stk.push<T>(Ptr.deref<T>());
1673 return true;
1674}
1675
1676template <PrimType Name, class T = typename PrimConv<Name>::T>
1678 const Pointer &Ptr = S.Stk.pop<Pointer>();
1679 if (!CheckLoad(S, OpPC, Ptr))
1680 return false;
1681 if (!Ptr.isBlockPointer())
1682 return false;
1683 S.Stk.push<T>(Ptr.deref<T>());
1684 return true;
1685}
1686
1687template <PrimType Name, class T = typename PrimConv<Name>::T>
1688bool Store(InterpState &S, CodePtr OpPC) {
1689 const T &Value = S.Stk.pop<T>();
1690 const Pointer &Ptr = S.Stk.peek<Pointer>();
1691 if (!CheckStore(S, OpPC, Ptr))
1692 return false;
1693 if (Ptr.canBeInitialized()) {
1694 Ptr.initialize();
1695 Ptr.activate();
1696 }
1697 Ptr.deref<T>() = Value;
1698 return true;
1699}
1700
1701template <PrimType Name, class T = typename PrimConv<Name>::T>
1703 const T &Value = S.Stk.pop<T>();
1704 const Pointer &Ptr = S.Stk.pop<Pointer>();
1705 if (!CheckStore(S, OpPC, Ptr))
1706 return false;
1707 if (Ptr.canBeInitialized()) {
1708 Ptr.initialize();
1709 Ptr.activate();
1710 }
1711 Ptr.deref<T>() = Value;
1712 return true;
1713}
1714
1715template <PrimType Name, class T = typename PrimConv<Name>::T>
1717 const T &Value = S.Stk.pop<T>();
1718 const Pointer &Ptr = S.Stk.peek<Pointer>();
1719 if (!CheckStore(S, OpPC, Ptr))
1720 return false;
1721 if (Ptr.canBeInitialized())
1722 Ptr.initialize();
1723 if (const auto *FD = Ptr.getField())
1724 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1725 else
1726 Ptr.deref<T>() = Value;
1727 return true;
1728}
1729
1730template <PrimType Name, class T = typename PrimConv<Name>::T>
1732 const T &Value = S.Stk.pop<T>();
1733 const Pointer &Ptr = S.Stk.pop<Pointer>();
1734 if (!CheckStore(S, OpPC, Ptr))
1735 return false;
1736 if (Ptr.canBeInitialized())
1737 Ptr.initialize();
1738 if (const auto *FD = Ptr.getField())
1739 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1740 else
1741 Ptr.deref<T>() = Value;
1742 return true;
1743}
1744
1745template <PrimType Name, class T = typename PrimConv<Name>::T>
1746bool Init(InterpState &S, CodePtr OpPC) {
1747 const T &Value = S.Stk.pop<T>();
1748 const Pointer &Ptr = S.Stk.peek<Pointer>();
1749 if (!CheckInit(S, OpPC, Ptr)) {
1750 assert(false);
1751 return false;
1752 }
1753 Ptr.initialize();
1754 new (&Ptr.deref<T>()) T(Value);
1755 return true;
1756}
1757
1758template <PrimType Name, class T = typename PrimConv<Name>::T>
1760 const T &Value = S.Stk.pop<T>();
1761 const Pointer &Ptr = S.Stk.pop<Pointer>();
1762 if (!CheckInit(S, OpPC, Ptr))
1763 return false;
1764 Ptr.initialize();
1765 new (&Ptr.deref<T>()) T(Value);
1766 return true;
1767}
1768
1769/// 1) Pops the value from the stack
1770/// 2) Peeks a pointer and gets its index \Idx
1771/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1772template <PrimType Name, class T = typename PrimConv<Name>::T>
1773bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1774 const T &Value = S.Stk.pop<T>();
1775 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1776 if (Ptr.isUnknownSizeArray())
1777 return false;
1778 if (!CheckInit(S, OpPC, Ptr))
1779 return false;
1780 Ptr.initialize();
1781 new (&Ptr.deref<T>()) T(Value);
1782 return true;
1783}
1784
1785/// The same as InitElem, but pops the pointer as well.
1786template <PrimType Name, class T = typename PrimConv<Name>::T>
1787bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1788 const T &Value = S.Stk.pop<T>();
1789 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1790 if (Ptr.isUnknownSizeArray())
1791 return false;
1792 if (!CheckInit(S, OpPC, Ptr))
1793 return false;
1794 Ptr.initialize();
1795 new (&Ptr.deref<T>()) T(Value);
1796 return true;
1797}
1798
1799inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1800 const Pointer &Src = S.Stk.pop<Pointer>();
1801 Pointer &Dest = S.Stk.peek<Pointer>();
1802
1803 if (!CheckLoad(S, OpPC, Src))
1804 return false;
1805
1806 return DoMemcpy(S, OpPC, Src, Dest);
1807}
1808
1809inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1810 const auto &Member = S.Stk.pop<MemberPointer>();
1811 const auto &Base = S.Stk.pop<Pointer>();
1812
1813 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1814 return true;
1815}
1816
1817inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1818 const auto &MP = S.Stk.pop<MemberPointer>();
1819
1820 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1821 S.Stk.push<Pointer>(*Ptr);
1822 return true;
1823 }
1824 return false;
1825}
1826
1827//===----------------------------------------------------------------------===//
1828// AddOffset, SubOffset
1829//===----------------------------------------------------------------------===//
1830
1831template <class T, ArithOp Op>
1832bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1833 const Pointer &Ptr) {
1834 // A zero offset does not change the pointer.
1835 if (Offset.isZero()) {
1836 S.Stk.push<Pointer>(Ptr);
1837 return true;
1838 }
1839
1840 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1841 // The CheckNull will have emitted a note already, but we only
1842 // abort in C++, since this is fine in C.
1843 if (S.getLangOpts().CPlusPlus)
1844 return false;
1845 }
1846
1847 // Arrays of unknown bounds cannot have pointers into them.
1848 if (!CheckArray(S, OpPC, Ptr))
1849 return false;
1850
1851 // This is much simpler for integral pointers, so handle them first.
1852 if (Ptr.isIntegralPointer()) {
1853 uint64_t V = Ptr.getIntegerRepresentation();
1854 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
1855 if constexpr (Op == ArithOp::Add)
1856 S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
1857 else
1858 S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
1859 return true;
1860 } else if (Ptr.isFunctionPointer()) {
1861 uint64_t O = static_cast<uint64_t>(Offset);
1862 uint64_t N;
1863 if constexpr (Op == ArithOp::Add)
1864 N = Ptr.getByteOffset() + O;
1865 else
1866 N = Ptr.getByteOffset() - O;
1867
1868 if (N > 1)
1869 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1870 << N << /*non-array*/ true << 0;
1871 S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N);
1872 return true;
1873 }
1874
1875 assert(Ptr.isBlockPointer());
1876
1877 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1878 uint64_t Index;
1879 if (Ptr.isOnePastEnd())
1880 Index = MaxIndex;
1881 else
1882 Index = Ptr.getIndex();
1883
1884 bool Invalid = false;
1885 // Helper to report an invalid offset, computed as APSInt.
1886 auto DiagInvalidOffset = [&]() -> void {
1887 const unsigned Bits = Offset.bitWidth();
1888 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1889 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1890 /*IsUnsigned=*/false);
1891 APSInt NewIndex =
1892 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1893 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1894 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1895 Invalid = true;
1896 };
1897
1898 if (Ptr.isBlockPointer()) {
1899 uint64_t IOffset = static_cast<uint64_t>(Offset);
1900 uint64_t MaxOffset = MaxIndex - Index;
1901
1902 if constexpr (Op == ArithOp::Add) {
1903 // If the new offset would be negative, bail out.
1904 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1905 DiagInvalidOffset();
1906
1907 // If the new offset would be out of bounds, bail out.
1908 if (Offset.isPositive() && IOffset > MaxOffset)
1909 DiagInvalidOffset();
1910 } else {
1911 // If the new offset would be negative, bail out.
1912 if (Offset.isPositive() && Index < IOffset)
1913 DiagInvalidOffset();
1914
1915 // If the new offset would be out of bounds, bail out.
1916 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1917 DiagInvalidOffset();
1918 }
1919 }
1920
1921 if (Invalid && S.getLangOpts().CPlusPlus)
1922 return false;
1923
1924 // Offset is valid - compute it on unsigned.
1925 int64_t WideIndex = static_cast<int64_t>(Index);
1926 int64_t WideOffset = static_cast<int64_t>(Offset);
1927 int64_t Result;
1928 if constexpr (Op == ArithOp::Add)
1929 Result = WideIndex + WideOffset;
1930 else
1931 Result = WideIndex - WideOffset;
1932
1933 // When the pointer is one-past-end, going back to index 0 is the only
1934 // useful thing we can do. Any other index has been diagnosed before and
1935 // we don't get here.
1936 if (Result == 0 && Ptr.isOnePastEnd()) {
1937 S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
1938 Ptr.asBlockPointer().Base);
1939 return true;
1940 }
1941
1942 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1943 return true;
1944}
1945
1946template <PrimType Name, class T = typename PrimConv<Name>::T>
1948 const T &Offset = S.Stk.pop<T>();
1949 const Pointer &Ptr = S.Stk.pop<Pointer>();
1950 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1951}
1952
1953template <PrimType Name, class T = typename PrimConv<Name>::T>
1955 const T &Offset = S.Stk.pop<T>();
1956 const Pointer &Ptr = S.Stk.pop<Pointer>();
1957 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1958}
1959
1960template <ArithOp Op>
1961static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1962 const Pointer &Ptr) {
1963 if (Ptr.isDummy())
1964 return false;
1965
1966 using OneT = Integral<8, false>;
1967
1968 const Pointer &P = Ptr.deref<Pointer>();
1969 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1970 return false;
1971
1972 // Get the current value on the stack.
1973 S.Stk.push<Pointer>(P);
1974
1975 // Now the current Ptr again and a constant 1.
1976 OneT One = OneT::from(1);
1977 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1978 return false;
1979
1980 // Store the new value.
1981 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1982 return true;
1983}
1984
1985static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1986 const Pointer &Ptr = S.Stk.pop<Pointer>();
1987
1988 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1989 return false;
1990
1991 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1992}
1993
1994static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1995 const Pointer &Ptr = S.Stk.pop<Pointer>();
1996
1997 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1998 return false;
1999
2000 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2001}
2002
2003/// 1) Pops a Pointer from the stack.
2004/// 2) Pops another Pointer from the stack.
2005/// 3) Pushes the different of the indices of the two pointers on the stack.
2006template <PrimType Name, class T = typename PrimConv<Name>::T>
2007inline bool SubPtr(InterpState &S, CodePtr OpPC) {
2008 const Pointer &LHS = S.Stk.pop<Pointer>();
2009 const Pointer &RHS = S.Stk.pop<Pointer>();
2010
2011 for (const Pointer &P : {LHS, RHS}) {
2012 if (P.isZeroSizeArray()) {
2013 QualType PtrT = P.getType();
2014 while (auto *AT = dyn_cast<ArrayType>(PtrT))
2015 PtrT = AT->getElementType();
2016
2017 QualType ArrayTy = S.getCtx().getConstantArrayType(
2018 PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2019 S.FFDiag(S.Current->getSource(OpPC),
2020 diag::note_constexpr_pointer_subtraction_zero_size)
2021 << ArrayTy;
2022
2023 return false;
2024 }
2025 }
2026
2027 if (RHS.isZero()) {
2028 S.Stk.push<T>(T::from(LHS.getIndex()));
2029 return true;
2030 }
2031
2032 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2033 // TODO: Diagnose.
2034 return false;
2035 }
2036
2037 if (LHS.isZero() && RHS.isZero()) {
2038 S.Stk.push<T>();
2039 return true;
2040 }
2041
2042 T A = LHS.isBlockPointer()
2043 ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
2044 : T::from(LHS.getIndex()))
2045 : T::from(LHS.getIntegerRepresentation());
2046 T B = RHS.isBlockPointer()
2047 ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2048 : T::from(RHS.getIndex()))
2049 : T::from(RHS.getIntegerRepresentation());
2050
2051 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2052}
2053
2054//===----------------------------------------------------------------------===//
2055// Destroy
2056//===----------------------------------------------------------------------===//
2057
2058inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2059 S.Current->destroy(I);
2060 return true;
2061}
2062
2063inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2064 S.Current->initScope(I);
2065 return true;
2066}
2067
2068//===----------------------------------------------------------------------===//
2069// Cast, CastFP
2070//===----------------------------------------------------------------------===//
2071
2072template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2073 using T = typename PrimConv<TIn>::T;
2074 using U = typename PrimConv<TOut>::T;
2075 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2076 return true;
2077}
2078
2079/// 1) Pops a Floating from the stack.
2080/// 2) Pushes a new floating on the stack that uses the given semantics.
2081inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2082 llvm::RoundingMode RM) {
2083 Floating F = S.Stk.pop<Floating>();
2084 Floating Result = F.toSemantics(Sem, RM);
2085 S.Stk.push<Floating>(Result);
2086 return true;
2087}
2088
2089/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2090/// to know what bitwidth the result should be.
2091template <PrimType Name, class T = typename PrimConv<Name>::T>
2092bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2093 S.Stk.push<IntegralAP<false>>(
2094 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2095 return true;
2096}
2097
2098template <PrimType Name, class T = typename PrimConv<Name>::T>
2099bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2100 S.Stk.push<IntegralAP<true>>(
2101 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2102 return true;
2103}
2104
2105template <PrimType Name, class T = typename PrimConv<Name>::T>
2107 const llvm::fltSemantics *Sem,
2108 llvm::RoundingMode RM) {
2109 const T &From = S.Stk.pop<T>();
2110 APSInt FromAP = From.toAPSInt();
2112
2113 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
2114 S.Stk.push<Floating>(Result);
2115
2116 return CheckFloatResult(S, OpPC, Result, Status);
2117}
2118
2119template <PrimType Name, class T = typename PrimConv<Name>::T>
2121 const Floating &F = S.Stk.pop<Floating>();
2122
2123 if constexpr (std::is_same_v<T, Boolean>) {
2124 S.Stk.push<T>(T(F.isNonZero()));
2125 return true;
2126 } else {
2127 APSInt Result(std::max(8u, T::bitWidth()),
2128 /*IsUnsigned=*/!T::isSigned());
2129 auto Status = F.convertToInteger(Result);
2130
2131 // Float-to-Integral overflow check.
2132 if ((Status & APFloat::opStatus::opInvalidOp)) {
2133 const Expr *E = S.Current->getExpr(OpPC);
2134 QualType Type = E->getType();
2135
2136 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2137 if (S.noteUndefinedBehavior()) {
2138 S.Stk.push<T>(T(Result));
2139 return true;
2140 }
2141 return false;
2142 }
2143
2144 S.Stk.push<T>(T(Result));
2145 return CheckFloatResult(S, OpPC, F, Status);
2146 }
2147}
2148
2149static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2150 uint32_t BitWidth) {
2151 const Floating &F = S.Stk.pop<Floating>();
2152
2153 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2154 auto Status = F.convertToInteger(Result);
2155
2156 // Float-to-Integral overflow check.
2157 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2158 const Expr *E = S.Current->getExpr(OpPC);
2159 QualType Type = E->getType();
2160
2161 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2162 return S.noteUndefinedBehavior();
2163 }
2164
2166 return CheckFloatResult(S, OpPC, F, Status);
2167}
2168
2169static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2170 uint32_t BitWidth) {
2171 const Floating &F = S.Stk.pop<Floating>();
2172
2173 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2174 auto Status = F.convertToInteger(Result);
2175
2176 // Float-to-Integral overflow check.
2177 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2178 const Expr *E = S.Current->getExpr(OpPC);
2179 QualType Type = E->getType();
2180
2181 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2182 return S.noteUndefinedBehavior();
2183 }
2184
2186 return CheckFloatResult(S, OpPC, F, Status);
2187}
2188
2189template <PrimType Name, class T = typename PrimConv<Name>::T>
2191 const Pointer &Ptr = S.Stk.pop<Pointer>();
2192
2193 if (Ptr.isDummy())
2194 return false;
2195
2196 const SourceInfo &E = S.Current->getSource(OpPC);
2197 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2198 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2199
2200 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2201 return true;
2202}
2203
2204static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
2205 uint32_t BitWidth) {
2206 const Pointer &Ptr = S.Stk.pop<Pointer>();
2207
2208 if (Ptr.isDummy())
2209 return false;
2210
2211 const SourceInfo &E = S.Current->getSource(OpPC);
2212 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2213 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2214
2215 S.Stk.push<IntegralAP<false>>(
2217 return true;
2218}
2219
2220static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
2221 uint32_t BitWidth) {
2222 const Pointer &Ptr = S.Stk.pop<Pointer>();
2223
2224 if (Ptr.isDummy())
2225 return false;
2226
2227 const SourceInfo &E = S.Current->getSource(OpPC);
2228 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2229 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2230
2231 S.Stk.push<IntegralAP<true>>(
2233 return true;
2234}
2235
2236static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2237 const auto &Ptr = S.Stk.peek<Pointer>();
2238
2239 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2240 bool HasValidResult = !Ptr.isZero();
2241
2242 if (HasValidResult) {
2243 // FIXME: note_constexpr_invalid_void_star_cast
2244 } else if (!S.getLangOpts().CPlusPlus26) {
2245 const SourceInfo &E = S.Current->getSource(OpPC);
2246 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2247 << 3 << "'void *'" << S.Current->getRange(OpPC);
2248 }
2249 } else {
2250 const SourceInfo &E = S.Current->getSource(OpPC);
2251 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2252 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2253 }
2254
2255 return true;
2256}
2257
2258//===----------------------------------------------------------------------===//
2259// Zero, Nullptr
2260//===----------------------------------------------------------------------===//
2261
2262template <PrimType Name, class T = typename PrimConv<Name>::T>
2263bool Zero(InterpState &S, CodePtr OpPC) {
2264 S.Stk.push<T>(T::zero());
2265 return true;
2266}
2267
2268static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2269 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2270 return true;
2271}
2272
2273static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2274 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2275 return true;
2276}
2277
2278template <PrimType Name, class T = typename PrimConv<Name>::T>
2279inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2280 // Note: Desc can be null.
2281 S.Stk.push<T>(0, Desc);
2282 return true;
2283}
2284
2285//===----------------------------------------------------------------------===//
2286// This, ImplicitThis
2287//===----------------------------------------------------------------------===//
2288
2289inline bool This(InterpState &S, CodePtr OpPC) {
2290 // Cannot read 'this' in this mode.
2291 if (S.checkingPotentialConstantExpression()) {
2292 return false;
2293 }
2294
2295 const Pointer &This = S.Current->getThis();
2296 if (!CheckThis(S, OpPC, This))
2297 return false;
2298
2299 // Ensure the This pointer has been cast to the correct base.
2300 if (!This.isDummy()) {
2301 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2302 assert(This.getRecord());
2303 assert(
2304 This.getRecord()->getDecl() ==
2305 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2306 }
2307
2308 S.Stk.push<Pointer>(This);
2309 return true;
2310}
2311
2312inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2313 assert(S.Current->getFunction()->hasRVO());
2314 if (S.checkingPotentialConstantExpression())
2315 return false;
2316 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2317 return true;
2318}
2319
2320//===----------------------------------------------------------------------===//
2321// Shr, Shl
2322//===----------------------------------------------------------------------===//
2323enum class ShiftDir { Left, Right };
2324
2325template <class LT, class RT, ShiftDir Dir>
2326inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2327 const unsigned Bits = LHS.bitWidth();
2328
2329 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2330 if (S.getLangOpts().OpenCL)
2331 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2332 RHS.bitWidth(), &RHS);
2333
2334 if (RHS.isNegative()) {
2335 // During constant-folding, a negative shift is an opposite shift. Such a
2336 // shift is not a constant expression.
2337 const SourceInfo &Loc = S.Current->getSource(OpPC);
2338 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2339 if (!S.noteUndefinedBehavior())
2340 return false;
2341 RHS = -RHS;
2342 return DoShift<LT, RT,
2344 S, OpPC, LHS, RHS);
2345 }
2346
2347 if constexpr (Dir == ShiftDir::Left) {
2348 if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
2349 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
2350 // operand, and must not overflow the corresponding unsigned type.
2351 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2352 // E1 x 2^E2 module 2^N.
2353 const SourceInfo &Loc = S.Current->getSource(OpPC);
2354 S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2355 if (!S.noteUndefinedBehavior())
2356 return false;
2357 }
2358 }
2359
2360 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2361 return false;
2362
2363 // Limit the shift amount to Bits - 1. If this happened,
2364 // it has already been diagnosed by CheckShift() above,
2365 // but we still need to handle it.
2366 typename LT::AsUnsigned R;
2367 if constexpr (Dir == ShiftDir::Left) {
2368 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2369 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2370 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2371 else
2372 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2373 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2374 } else {
2375 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2376 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2377 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2378 else
2379 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2380 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2381 }
2382
2383 // We did the shift above as unsigned. Restore the sign bit if we need to.
2384 if constexpr (Dir == ShiftDir::Right) {
2385 if (LHS.isSigned() && LHS.isNegative()) {
2386 typename LT::AsUnsigned SignBit;
2387 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(1, Bits),
2388 LT::AsUnsigned::from(Bits - 1, Bits), Bits,
2389 &SignBit);
2390 LT::AsUnsigned::bitOr(R, SignBit, Bits, &R);
2391 }
2392 }
2393
2394 S.Stk.push<LT>(LT::from(R));
2395 return true;
2396}
2397
2398template <PrimType NameL, PrimType NameR>
2399inline bool Shr(InterpState &S, CodePtr OpPC) {
2400 using LT = typename PrimConv<NameL>::T;
2401 using RT = typename PrimConv<NameR>::T;
2402 auto RHS = S.Stk.pop<RT>();
2403 auto LHS = S.Stk.pop<LT>();
2404
2405 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2406}
2407
2408template <PrimType NameL, PrimType NameR>
2409inline bool Shl(InterpState &S, CodePtr OpPC) {
2410 using LT = typename PrimConv<NameL>::T;
2411 using RT = typename PrimConv<NameR>::T;
2412 auto RHS = S.Stk.pop<RT>();
2413 auto LHS = S.Stk.pop<LT>();
2414
2415 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2416}
2417
2418//===----------------------------------------------------------------------===//
2419// NoRet
2420//===----------------------------------------------------------------------===//
2421
2422inline bool NoRet(InterpState &S, CodePtr OpPC) {
2423 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2424 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2425 return false;
2426}
2427
2428//===----------------------------------------------------------------------===//
2429// NarrowPtr, ExpandPtr
2430//===----------------------------------------------------------------------===//
2431
2432inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2433 const Pointer &Ptr = S.Stk.pop<Pointer>();
2434 S.Stk.push<Pointer>(Ptr.narrow());
2435 return true;
2436}
2437
2438inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2439 const Pointer &Ptr = S.Stk.pop<Pointer>();
2440 S.Stk.push<Pointer>(Ptr.expand());
2441 return true;
2442}
2443
2444// 1) Pops an integral value from the stack
2445// 2) Peeks a pointer
2446// 3) Pushes a new pointer that's a narrowed array
2447// element of the peeked pointer with the value
2448// from 1) added as offset.
2449//
2450// This leaves the original pointer on the stack and pushes a new one
2451// with the offset applied and narrowed.
2452template <PrimType Name, class T = typename PrimConv<Name>::T>
2453inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2454 const T &Offset = S.Stk.pop<T>();
2455 const Pointer &Ptr = S.Stk.peek<Pointer>();
2456
2457 if (!Ptr.isZero() && !Offset.isZero()) {
2458 if (!CheckArray(S, OpPC, Ptr))
2459 return false;
2460 }
2461
2462 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2463 return false;
2464
2465 return NarrowPtr(S, OpPC);
2466}
2467
2468template <PrimType Name, class T = typename PrimConv<Name>::T>
2469inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2470 const T &Offset = S.Stk.pop<T>();
2471 const Pointer &Ptr = S.Stk.pop<Pointer>();
2472
2473 if (!Ptr.isZero() && !Offset.isZero()) {
2474 if (!CheckArray(S, OpPC, Ptr))
2475 return false;
2476 }
2477
2478 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2479 return false;
2480
2481 return NarrowPtr(S, OpPC);
2482}
2483
2484template <PrimType Name, class T = typename PrimConv<Name>::T>
2485inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2486 const Pointer &Ptr = S.Stk.peek<Pointer>();
2487
2488 if (!CheckLoad(S, OpPC, Ptr))
2489 return false;
2490
2491 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2492 return true;
2493}
2494
2495template <PrimType Name, class T = typename PrimConv<Name>::T>
2496inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2497 const Pointer &Ptr = S.Stk.pop<Pointer>();
2498
2499 if (!CheckLoad(S, OpPC, Ptr))
2500 return false;
2501
2502 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2503 return true;
2504}
2505
2506template <PrimType Name, class T = typename PrimConv<Name>::T>
2507inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2508 uint32_t DestIndex, uint32_t Size) {
2509 const auto &SrcPtr = S.Stk.pop<Pointer>();
2510 const auto &DestPtr = S.Stk.peek<Pointer>();
2511
2512 for (uint32_t I = 0; I != Size; ++I) {
2513 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2514
2515 if (!CheckLoad(S, OpPC, SP))
2516 return false;
2517
2518 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2519 DP.deref<T>() = SP.deref<T>();
2520 DP.initialize();
2521 }
2522 return true;
2523}
2524
2525/// Just takes a pointer and checks if it's an incomplete
2526/// array type.
2527inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2528 const Pointer &Ptr = S.Stk.pop<Pointer>();
2529
2530 if (Ptr.isZero()) {
2531 S.Stk.push<Pointer>(Ptr);
2532 return true;
2533 }
2534
2535 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2536 return false;
2537
2538 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
2539 S.Stk.push<Pointer>(Ptr.atIndex(0));
2540 return true;
2541 }
2542
2543 const SourceInfo &E = S.Current->getSource(OpPC);
2544 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2545
2546 return false;
2547}
2548
2549inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2550 uint32_t VarArgSize) {
2551 if (Func->hasThisPointer()) {
2552 size_t ArgSize = Func->getArgSize() + VarArgSize;
2553 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2554 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2555
2556 // If the current function is a lambda static invoker and
2557 // the function we're about to call is a lambda call operator,
2558 // skip the CheckInvoke, since the ThisPtr is a null pointer
2559 // anyway.
2560 if (!(S.Current->getFunction() &&
2561 S.Current->getFunction()->isLambdaStaticInvoker() &&
2562 Func->isLambdaCallOperator())) {
2563 if (!CheckInvoke(S, OpPC, ThisPtr))
2564 return false;
2565 }
2566
2567 if (S.checkingPotentialConstantExpression())
2568 return false;
2569 }
2570
2571 if (!CheckCallable(S, OpPC, Func))
2572 return false;
2573
2574 if (!CheckCallDepth(S, OpPC))
2575 return false;
2576
2577 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2578 InterpFrame *FrameBefore = S.Current;
2579 S.Current = NewFrame.get();
2580
2581 APValue CallResult;
2582 // Note that we cannot assert(CallResult.hasValue()) here since
2583 // Ret() above only sets the APValue if the curent frame doesn't
2584 // have a caller set.
2585 if (Interpret(S, CallResult)) {
2586 NewFrame.release(); // Frame was delete'd already.
2587 assert(S.Current == FrameBefore);
2588 return true;
2589 }
2590
2591 // Interpreting the function failed somehow. Reset to
2592 // previous state.
2593 S.Current = FrameBefore;
2594 return false;
2595
2596 return false;
2597}
2598
2599inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2600 uint32_t VarArgSize) {
2601 if (Func->hasThisPointer()) {
2602 size_t ArgSize = Func->getArgSize() + VarArgSize;
2603 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2604
2605 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2606
2607 // If the current function is a lambda static invoker and
2608 // the function we're about to call is a lambda call operator,
2609 // skip the CheckInvoke, since the ThisPtr is a null pointer
2610 // anyway.
2611 if (!(S.Current->getFunction() &&
2612 S.Current->getFunction()->isLambdaStaticInvoker() &&
2613 Func->isLambdaCallOperator())) {
2614 if (!CheckInvoke(S, OpPC, ThisPtr))
2615 return false;
2616 }
2617 }
2618
2619 if (!CheckCallable(S, OpPC, Func))
2620 return false;
2621
2622 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2623 return false;
2624
2625 if (!CheckCallDepth(S, OpPC))
2626 return false;
2627
2628 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2629 InterpFrame *FrameBefore = S.Current;
2630 S.Current = NewFrame.get();
2631
2632 APValue CallResult;
2633 // Note that we cannot assert(CallResult.hasValue()) here since
2634 // Ret() above only sets the APValue if the curent frame doesn't
2635 // have a caller set.
2636 if (Interpret(S, CallResult)) {
2637 NewFrame.release(); // Frame was delete'd already.
2638 assert(S.Current == FrameBefore);
2639 return true;
2640 }
2641
2642 // Interpreting the function failed somehow. Reset to
2643 // previous state.
2644 S.Current = FrameBefore;
2645 return false;
2646}
2647
2648inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2649 uint32_t VarArgSize) {
2650 assert(Func->hasThisPointer());
2651 assert(Func->isVirtual());
2652 size_t ArgSize = Func->getArgSize() + VarArgSize;
2653 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2654 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2655
2656 const CXXRecordDecl *DynamicDecl = nullptr;
2657 {
2658 Pointer TypePtr = ThisPtr;
2659 while (TypePtr.isBaseClass())
2660 TypePtr = TypePtr.getBase();
2661
2662 QualType DynamicType = TypePtr.getType();
2663 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2664 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2665 else
2666 DynamicDecl = DynamicType->getAsCXXRecordDecl();
2667 }
2668 assert(DynamicDecl);
2669
2670 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2671 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2672 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2673 DynamicDecl, StaticDecl, InitialFunction);
2674
2675 if (Overrider != InitialFunction) {
2676 // DR1872: An instantiated virtual constexpr function can't be called in a
2677 // constant expression (prior to C++20). We can still constant-fold such a
2678 // call.
2679 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2680 const Expr *E = S.Current->getExpr(OpPC);
2681 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2682 }
2683
2684 Func = S.getContext().getOrCreateFunction(Overrider);
2685
2686 const CXXRecordDecl *ThisFieldDecl =
2687 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2688 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2689 // If the function we call is further DOWN the hierarchy than the
2690 // FieldDesc of our pointer, just go up the hierarchy of this field
2691 // the furthest we can go.
2692 while (ThisPtr.isBaseClass())
2693 ThisPtr = ThisPtr.getBase();
2694 }
2695 }
2696
2697 if (!Call(S, OpPC, Func, VarArgSize))
2698 return false;
2699
2700 // Covariant return types. The return type of Overrider is a pointer
2701 // or reference to a class type.
2702 if (Overrider != InitialFunction &&
2703 Overrider->getReturnType()->isPointerOrReferenceType() &&
2704 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
2705 QualType OverriderPointeeType =
2706 Overrider->getReturnType()->getPointeeType();
2707 QualType InitialPointeeType =
2708 InitialFunction->getReturnType()->getPointeeType();
2709 // We've called Overrider above, but calling code expects us to return what
2710 // InitialFunction returned. According to the rules for covariant return
2711 // types, what InitialFunction returns needs to be a base class of what
2712 // Overrider returns. So, we need to do an upcast here.
2713 unsigned Offset = S.getContext().collectBaseOffset(
2714 InitialPointeeType->getAsRecordDecl(),
2715 OverriderPointeeType->getAsRecordDecl());
2716 return GetPtrBasePop(S, OpPC, Offset);
2717 }
2718
2719 return true;
2720}
2721
2722inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2723 const CallExpr *CE) {
2724 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2725
2726 InterpFrame *FrameBefore = S.Current;
2727 S.Current = NewFrame.get();
2728
2729 if (InterpretBuiltin(S, PC, Func, CE)) {
2730 NewFrame.release();
2731 return true;
2732 }
2733 S.Current = FrameBefore;
2734 return false;
2735}
2736
2737inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2738 const CallExpr *CE) {
2739 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2740
2741 const Function *F = FuncPtr.getFunction();
2742 if (!F) {
2743 const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
2744 S.FFDiag(E, diag::note_constexpr_null_callee)
2745 << const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
2746 return false;
2747 }
2748
2749 if (!FuncPtr.isValid() || !F->getDecl())
2750 return Invalid(S, OpPC);
2751
2752 assert(F);
2753
2754 // This happens when the call expression has been cast to
2755 // something else, but we don't support that.
2756 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
2757 S.Ctx.classify(CE->getType()))
2758 return false;
2759
2760 // Check argument nullability state.
2761 if (F->hasNonNullAttr()) {
2762 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2763 return false;
2764 }
2765
2766 assert(ArgSize >= F->getWrittenArgSize());
2767 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2768
2769 // We need to do this explicitly here since we don't have the necessary
2770 // information to do it automatically.
2771 if (F->isThisPointerExplicit())
2772 VarArgSize -= align(primSize(PT_Ptr));
2773
2774 if (F->isVirtual())
2775 return CallVirt(S, OpPC, F, VarArgSize);
2776
2777 return Call(S, OpPC, F, VarArgSize);
2778}
2779
2780inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2781 assert(Func);
2782 S.Stk.push<FunctionPointer>(Func);
2783 return true;
2784}
2785
2786template <PrimType Name, class T = typename PrimConv<Name>::T>
2787inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2788 const T &IntVal = S.Stk.pop<T>();
2789
2790 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2791 return true;
2792}
2793
2794inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
2795 S.Stk.push<MemberPointer>(D);
2796 return true;
2797}
2798
2799inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2800 const auto &MP = S.Stk.pop<MemberPointer>();
2801
2802 S.Stk.push<Pointer>(MP.getBase());
2803 return true;
2804}
2805
2806inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2807 const auto &MP = S.Stk.pop<MemberPointer>();
2808
2809 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2810 const auto *Func = S.getContext().getOrCreateFunction(FD);
2811
2812 S.Stk.push<FunctionPointer>(Func);
2813 return true;
2814}
2815
2816/// Just emit a diagnostic. The expression that caused emission of this
2817/// op is not valid in a constant context.
2818inline bool Invalid(InterpState &S, CodePtr OpPC) {
2819 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2820 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2821 << S.Current->getRange(OpPC);
2822 return false;
2823}
2824
2825inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2826 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2827 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2828 << S.Current->getRange(OpPC);
2829 return false;
2830}
2831
2832/// Do nothing and just abort execution.
2833inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2834
2835/// Same here, but only for casts.
2836inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2837 bool Fatal) {
2838 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2839
2840 // FIXME: Support diagnosing other invalid cast kinds.
2841 if (Kind == CastKind::Reinterpret) {
2842 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2843 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2844 return !Fatal;
2845 }
2846 return false;
2847}
2848
2850 const DeclRefExpr *DR) {
2851 assert(DR);
2852 return CheckDeclRef(S, OpPC, DR);
2853}
2854
2856 if (S.inConstantContext()) {
2857 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2858 const Expr *E = S.Current->getExpr(OpPC);
2859 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2860 }
2861 return false;
2862}
2863
2864inline bool Assume(InterpState &S, CodePtr OpPC) {
2865 const auto Val = S.Stk.pop<Boolean>();
2866
2867 if (Val)
2868 return true;
2869
2870 // Else, diagnose.
2871 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2872 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2873 return false;
2874}
2875
2876template <PrimType Name, class T = typename PrimConv<Name>::T>
2877inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2878 llvm::SmallVector<int64_t> ArrayIndices;
2879 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2880 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2881
2882 int64_t Result;
2883 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2884 return false;
2885
2886 S.Stk.push<T>(T::from(Result));
2887
2888 return true;
2889}
2890
2891template <PrimType Name, class T = typename PrimConv<Name>::T>
2892inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2893 const T &Arg = S.Stk.peek<T>();
2894 if (!Arg.isZero())
2895 return true;
2896
2897 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2898 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2899
2900 return false;
2901}
2902
2903void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2904 const APSInt &Value);
2905
2906template <PrimType Name, class T = typename PrimConv<Name>::T>
2907inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2908 assert(ED);
2909 assert(!ED->isFixed());
2910 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2911
2912 if (S.inConstantContext())
2913 diagnoseEnumValue(S, OpPC, ED, Val);
2914 return true;
2915}
2916
2917/// OldPtr -> Integer -> NewPtr.
2918template <PrimType TIn, PrimType TOut>
2919inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2920 static_assert(isPtrType(TIn) && isPtrType(TOut));
2921 using FromT = typename PrimConv<TIn>::T;
2922 using ToT = typename PrimConv<TOut>::T;
2923
2924 const FromT &OldPtr = S.Stk.pop<FromT>();
2925
2926 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2927 std::is_same_v<ToT, Pointer>) {
2928 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2929 return true;
2930 } else if constexpr (std::is_same_v<FromT, Pointer> &&
2931 std::is_same_v<ToT, FunctionPointer>) {
2932 if (OldPtr.isFunctionPointer()) {
2933 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2934 OldPtr.getByteOffset());
2935 return true;
2936 }
2937 }
2938
2939 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2940 return true;
2941}
2942
2943inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2944 // An expression E is a core constant expression unless the evaluation of E
2945 // would evaluate one of the following: [C++23] - a control flow that passes
2946 // through a declaration of a variable with static or thread storage duration
2947 // unless that variable is usable in constant expressions.
2948 assert(VD->isLocalVarDecl() &&
2949 VD->isStaticLocal()); // Checked before emitting this.
2950
2951 if (VD == S.EvaluatingDecl)
2952 return true;
2953
2954 if (!VD->isUsableInConstantExpressions(S.getCtx())) {
2955 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2956 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2957 return false;
2958 }
2959 return true;
2960}
2961
2962inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2963 assert(Desc);
2964
2965 if (!CheckDynamicMemoryAllocation(S, OpPC))
2966 return false;
2967
2968 DynamicAllocator &Allocator = S.getAllocator();
2969 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
2970 assert(B);
2971
2972 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2973
2974 return true;
2975}
2976
2977template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2978inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2979 bool IsNoThrow) {
2980 if (!CheckDynamicMemoryAllocation(S, OpPC))
2981 return false;
2982
2983 SizeT NumElements = S.Stk.pop<SizeT>();
2984 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2985 if (!IsNoThrow)
2986 return false;
2987
2988 // If this failed and is nothrow, just return a null ptr.
2989 S.Stk.push<Pointer>(0, nullptr);
2990 return true;
2991 }
2992
2993 DynamicAllocator &Allocator = S.getAllocator();
2994 Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2995 S.Ctx.getEvalID());
2996 assert(B);
2997 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2998
2999 return true;
3000}
3001
3002template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3003inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
3004 bool IsNoThrow) {
3005 if (!CheckDynamicMemoryAllocation(S, OpPC))
3006 return false;
3007
3008 SizeT NumElements = S.Stk.pop<SizeT>();
3009 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
3010 IsNoThrow)) {
3011 if (!IsNoThrow)
3012 return false;
3013
3014 // If this failed and is nothrow, just return a null ptr.
3015 S.Stk.push<Pointer>(0, ElementDesc);
3016 return true;
3017 }
3018
3019 DynamicAllocator &Allocator = S.getAllocator();
3020 Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
3021 S.Ctx.getEvalID());
3022 assert(B);
3023
3024 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
3025
3026 return true;
3027}
3028
3029bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
3030static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
3031 if (!CheckDynamicMemoryAllocation(S, OpPC))
3032 return false;
3033
3034 const Expr *Source = nullptr;
3035 const Block *BlockToDelete = nullptr;
3036 {
3037 // Extra scope for this so the block doesn't have this pointer
3038 // pointing to it when we destroy it.
3039 const Pointer &Ptr = S.Stk.pop<Pointer>();
3040
3041 // Deleteing nullptr is always fine.
3042 if (Ptr.isZero())
3043 return true;
3044
3045 if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
3046 const SourceInfo &Loc = S.Current->getSource(OpPC);
3047 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
3048 << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
3049 return false;
3050 }
3051
3052 Source = Ptr.getDeclDesc()->asExpr();
3053 BlockToDelete = Ptr.block();
3054
3055 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
3056 return false;
3057 }
3058 assert(Source);
3059 assert(BlockToDelete);
3060
3061 // Invoke destructors before deallocating the memory.
3062 if (!RunDestructors(S, OpPC, BlockToDelete))
3063 return false;
3064
3065 DynamicAllocator &Allocator = S.getAllocator();
3066 bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
3067 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
3068
3069 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
3070 // Nothing has been deallocated, this must be a double-delete.
3071 const SourceInfo &Loc = S.Current->getSource(OpPC);
3072 S.FFDiag(Loc, diag::note_constexpr_double_delete);
3073 return false;
3074 }
3075 return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
3076 BlockDesc, Source);
3077}
3078
3079static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
3080 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
3081 return true;
3082}
3083
3084inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
3085 assert(T);
3086 assert(!S.getLangOpts().CPlusPlus23);
3087
3088 // C++1y: A constant initializer for an object o [...] may also invoke
3089 // constexpr constructors for o and its subobjects even if those objects
3090 // are of non-literal class types.
3091 //
3092 // C++11 missed this detail for aggregates, so classes like this:
3093 // struct foo_t { union { int i; volatile int j; } u; };
3094 // are not (obviously) initializable like so:
3095 // __attribute__((__require_constant_initialization__))
3096 // static const foo_t x = {{0}};
3097 // because "i" is a subobject with non-literal initialization (due to the
3098 // volatile member of the union). See:
3099 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
3100 // Therefore, we use the C++1y behavior.
3101
3102 if (S.EvaluatingDecl)
3103 return true;
3104
3105 if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
3106 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl)
3107 return true;
3108
3109 const Expr *E = S.Current->getExpr(OpPC);
3110 if (S.getLangOpts().CPlusPlus11)
3111 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
3112 else
3113 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
3114 return false;
3115}
3116
3117//===----------------------------------------------------------------------===//
3118// Read opcode arguments
3119//===----------------------------------------------------------------------===//
3120
3121template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3122 if constexpr (std::is_pointer<T>::value) {
3123 uint32_t ID = OpPC.read<uint32_t>();
3124 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3125 } else {
3126 return OpPC.read<T>();
3127 }
3128}
3129
3130template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3132 OpPC += align(F.bytesToSerialize());
3133 return F;
3134}
3135
3136template <>
3137inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3138 CodePtr &OpPC) {
3139 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3140 OpPC += align(I.bytesToSerialize());
3141 return I;
3142}
3143
3144template <>
3145inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3146 CodePtr &OpPC) {
3147 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3148 OpPC += align(I.bytesToSerialize());
3149 return I;
3150}
3151
3152} // namespace interp
3153} // namespace clang
3154
3155#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3341
ASTImporterLookupTable & LT
StringRef P
const Decl * D
Expr * E
llvm::APSInt APSInt
Definition: Compiler.cpp:22
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)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
SourceLocation Loc
Definition: SemaObjC.cpp:759
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2064
bool isVirtual() const
Definition: DeclCXX.h:2119
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2830
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
static unsigned getMaxSizeBits(const ASTContext &Context)
Determine the maximum number of active bits that an array's size can require, which limits the maximu...
Definition: Type.cpp:218
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
SourceLocation getLocation() const
Definition: DeclBase.h:446
Represents an enum.
Definition: Decl.h:3844
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
Definition: Decl.h:4058
This represents one expression.
Definition: Expr.h:110
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:142
QualType getReturnType() const
Definition: Decl.h:2717
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3233
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3094
Expr * getTemporaryExpr()
Retrieve the expression to which the temporary materialization conversion was applied.
Definition: DeclCXX.h:3279
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2475
A (possibly-)qualified type.
Definition: Type.h:941
Represents a struct/union/class.
Definition: Decl.h:4145
const LangOptions & getLangOpts() const
Definition: Sema.h:553
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:326
The base class of the type hierarchy.
Definition: Type.h:1829
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:705
bool isPointerOrReferenceType() const
Definition: Type.h:8012
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1886
bool isWeak() const
Determine whether this symbol is weakly-imported, or declared with the weak or weak-ref attr.
Definition: Decl.cpp:5364
Represents a variable declaration or definition.
Definition: Decl.h:879
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition: Decl.h:1156
ThreadStorageClassSpecifier getTSCSpec() const
Definition: Decl.h:1125
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition: Decl.h:1201
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:2493
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:78
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition: InterpBlock.h:67
Wrapper around boolean types.
Definition: Boolean.h:25
static Boolean from(T Value)
Definition: Boolean.h:94
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:60
Manages dynamic memory allocations done during bytecode interpretation.
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:200
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:153
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:181
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:174
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:119
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
size_t bytesToSerialize() const
Definition: Floating.h:139
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:168
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:194
bool isNonZero() const
Definition: Floating.h:92
bool isFinite() const
Definition: Floating.h:98
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:187
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition: Floating.h:50
const Function * getFunction() const
ComparisonCategoryResult compare(const FunctionPointer &RHS) const
std::string toDiagnosticString(const ASTContext &Ctx) const
Bytecode function.
Definition: Function.h:81
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:284
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:120
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
Wrapper around numeric types.
Definition: Integral.h:66
Frame storing local variables.
Definition: InterpFrame.h:26
Interpreter context.
Definition: InterpState.h:36
ComparisonCategoryResult compare(const MemberPointer &RHS) const
Definition: MemberPointer.h:97
A pointer to a memory block, live or dead.
Definition: Pointer.h:82
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:435
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:183
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:431
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:311
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:149
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:527
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:176
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:474
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:572
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:168
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:625
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:563
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:416
void activate() const
Activats a field.
Definition: Pointer.cpp:395
bool isIntegralPointer() const
Definition: Pointer.h:457
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:338
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:422
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:393
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:398
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:308
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:554
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:301
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:260
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:668
const IntPointer & asIntPointer() const
Definition: Pointer.h:447
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:428
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:283
unsigned getOffset() const
Returns the offset into an array.
Definition: Pointer.h:375
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:590
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:136
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:613
bool isBlockPointer() const
Definition: Pointer.h:456
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:451
const Block * block() const
Definition: Pointer.h:569
bool isFunctionPointer() const
Definition: Pointer.h:458
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:328
bool isBaseClass() const
Checks if a structure is a base class.
Definition: Pointer.h:522
size_t elemSize() const
Returns the element size of the innermost field.
Definition: Pointer.h:357
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:436
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:443
void initialize() const
Initializes a field.
Definition: Pointer.cpp:347
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:77
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:152
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1488
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1759
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2399
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:1340
llvm::APFloat APFloat
Definition: Floating.h:23
bool IncPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
Definition: Interp.h:783
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2496
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1578
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:397
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2485
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1112
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:615
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2799
bool DecPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition: Interp.h:808
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1267
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2432
bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
Definition: Interp.cpp:913
llvm::APInt APInt
Definition: Integral.h:29
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
Definition: Interp.h:1591
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1381
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:963
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3130
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2273
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:836
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1204
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1787
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1716
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:406
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1677
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:860
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2169
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1985
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:833
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1145
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:694
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:705
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1235
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2892
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
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}_ordering type.
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:1961
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1440
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2149
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:196
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition: Interp.cpp:323
bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)
Definition: Interp.h:2943
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:333
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
Definition: Interp.h:1460
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:627
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:454
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2780
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1314
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1539
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:2007
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:395
static bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2220
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1453
bool Mulc(InterpState &S, CodePtr OpPC)
Definition: Interp.h:426
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2453
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1090
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2422
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2787
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:536
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2268
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:379
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2409
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2312
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:493
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2190
constexpr bool isPtrType(PrimType T)
Definition: PrimType.h:51
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1954
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:126
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:590
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:375
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:276
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2099
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2438
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:723
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1688
bool Divc(InterpState &S, CodePtr OpPC)
Definition: Interp.h:481
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:1221
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2469
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2289
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2063
bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:415
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition: Interp.cpp:779
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:1416
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
Definition: Interp.h:817
bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size)
Definition: Interp.h:2507
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:901
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:886
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3121
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:293
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2527
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition: Interp.cpp:564
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:1362
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:713
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2120
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1186
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2877
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:556
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition: Interp.cpp:938
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:2106
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1104
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:33
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2263
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1397
bool Unsupported(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2825
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:587
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:364
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:814
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:2081
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1281
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1731
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2549
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1994
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2962
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1809
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:607
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1630
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:844
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1625
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2855
bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2279
static bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2204
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition: Interp.h:2236
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.h:3084
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1516
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1526
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:285
bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:852
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:519
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1552
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
Definition: Interp.cpp:859
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1565
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1213
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:838
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2806
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:907
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:871
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition: Interp.h:2919
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1641
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1702
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:219
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
Definition: Interp.h:2722
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:1198
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1616
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:408
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
Definition: Interp.h:2326
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:1773
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2058
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1151
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:1426
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D)
Definition: Interp.h:2794
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:2849
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1607
bool ReturnValue(const InterpState &S, const T &V, APValue &R)
Convert a value to an APValue.
Definition: Interp.h:43
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1131
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:920
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:671
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call)
Interpret a builtin function.
llvm::APSInt APSInt
Definition: Floating.h:24
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:270
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:643
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:573
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:660
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1666
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1323
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2072
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1059
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, bool DeleteIsArray, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
Definition: Interp.cpp:788
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:1253
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1018
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:623
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1947
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:1176
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool Memcpy(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1799
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1119
bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, unsigned ElemSize, bool IsNoThrow)
Definition: Interp.h:223
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.h:2737
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:960
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:72
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2648
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:889
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:426
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1445
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
Definition: Interp.h:3003
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1296
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1650
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1329
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Same here, but only for casts.
Definition: Interp.h:2836
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1817
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:310
bool Flip(InterpState &S, CodePtr OpPC)
[Value1, Value2] -> [Value2, Value1]
Definition: Interp.h:1158
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:1066
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:2092
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:940
bool Assume(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2864
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:603
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1597
static bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm)
Definition: Interp.h:3030
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status)
Checks if the result of a floating-point operation is valid in the current context.
Definition: Interp.cpp:732
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1832
static bool IsConstantContext(InterpState &S, CodePtr OpPC)
Definition: Interp.h:3079
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition: Interp.h:2978
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition: Interp.h:2907
The JSON file list parser is used to communicate input to InstallAPI.
@ 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:40
@ CSK_ArrayToPointer
Definition: State.h:44
@ CSK_Derived
Definition: State.h:42
@ CSK_Base
Definition: State.h:41
@ CSK_ArrayIndex
Definition: State.h:45
@ CSK_Field
Definition: State.h:43
@ Result
The result type of a method or function.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition: State.h:26
@ AK_Increment
Definition: State.h:30
@ AK_Read
Definition: State.h:27
@ AK_Decrement
Definition: State.h:31
const FunctionProtoType * T
#define bool
Definition: stdbool.h:24
unsigned Base
Start of the current subfield.
Definition: Pointer.h:41
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:39
Describes a memory block created by an allocation site.
Definition: Descriptor.h:111
unsigned getSize() const
Returns the size of the object without metadata.
Definition: Descriptor.h:219
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition: Descriptor.h:136
const Expr * asExpr() const
Definition: Descriptor.h:199
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:69
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:633
const Descriptor * Desc
Definition: Pointer.h:45
Mapping from primitive types to their representation.
Definition: PrimType.h:75