clang 19.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 "Boolean.h"
17#include "Floating.h"
18#include "Function.h"
19#include "FunctionPointer.h"
20#include "InterpFrame.h"
21#include "InterpStack.h"
22#include "InterpState.h"
23#include "Opcode.h"
24#include "PrimType.h"
25#include "Program.h"
26#include "State.h"
30#include "clang/AST/Expr.h"
31#include "llvm/ADT/APFloat.h"
32#include "llvm/ADT/APSInt.h"
33#include "llvm/Support/Endian.h"
34#include <limits>
35#include <type_traits>
36
37namespace clang {
38namespace interp {
39
40using APSInt = llvm::APSInt;
41
42/// Convert a value to an APValue.
43template <typename T> bool ReturnValue(const T &V, APValue &R) {
44 R = V.toAPValue();
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
61/// Checks if a pointer is null.
62bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64
65/// Checks if a pointer is in range.
66bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
67 AccessKinds AK);
68
69/// Checks if a field from which a pointer is going to be derived is valid.
70bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72
73/// Checks if Ptr is a one-past-the-end pointer.
74bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76
77/// Checks if a pointer points to const storage.
78bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79
80/// Checks if the Descriptor is of a constexpr or const global variable.
81bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
82
83/// Checks if a pointer points to a mutable field.
84bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86/// Checks if a value can be loaded from a block.
87bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88
89bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
90 AccessKinds AK);
91/// Check if a global variable is initialized.
92bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93
94/// Checks if a value can be stored in a block.
95bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
96
97/// Checks if a method can be invoked on an object.
98bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
99
100/// Checks if a value can be initialized.
101bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
102
103/// Checks if a method can be called.
104bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
105
106/// Checks if calling the currently active function would exceed
107/// the allowed call depth.
108bool CheckCallDepth(InterpState &S, CodePtr OpPC);
109
110/// Checks the 'this' pointer.
111bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
112
113/// Checks if a method is pure virtual.
114bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
115
116/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
117bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
118 const CallExpr *CE, unsigned ArgSize);
119
120/// Sets the given integral value to the pointer, which is of
121/// a std::{weak,partial,strong}_ordering type.
122bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
123 const Pointer &Ptr, const APSInt &IntValue);
124
125/// Copy the contents of Src into Dest.
126bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
127
128/// Checks if the shift operation is legal.
129template <typename LT, typename RT>
130bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
131 unsigned Bits) {
132 if (RHS.isNegative()) {
133 const SourceInfo &Loc = S.Current->getSource(OpPC);
134 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
135 return false;
136 }
137
138 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
139 // the shifted type.
140 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
141 const Expr *E = S.Current->getExpr(OpPC);
142 const APSInt Val = RHS.toAPSInt();
143 QualType Ty = E->getType();
144 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
145 return true; // We will do the shift anyway but fix up the shift amount.
146 }
147
148 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
149 const Expr *E = S.Current->getExpr(OpPC);
150 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
151 // operand, and must not overflow the corresponding unsigned type.
152 if (LHS.isNegative())
153 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
154 else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
155 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
156 }
157
158 // C++2a [expr.shift]p2: [P0907R4]:
159 // E1 << E2 is the unique value congruent to
160 // E1 x 2^E2 module 2^N.
161 return true;
162}
163
164/// Checks if Div/Rem operation on LHS and RHS is valid.
165template <typename T>
166bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
167 if (RHS.isZero()) {
168 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
169 S.FFDiag(Op, diag::note_expr_divide_by_zero)
170 << Op->getRHS()->getSourceRange();
171 if constexpr (!std::is_same_v<T, Floating>)
172 return false;
173 }
174
175 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
176 APSInt LHSInt = LHS.toAPSInt();
177 SmallString<32> Trunc;
178 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
179 const SourceInfo &Loc = S.Current->getSource(OpPC);
180 const Expr *E = S.Current->getExpr(OpPC);
181 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
182 return false;
183 }
184 return true;
185}
186
187/// Checks if the result of a floating-point operation is valid
188/// in the current context.
189bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
190 APFloat::opStatus Status);
191
192/// Checks why the given DeclRefExpr is invalid.
193bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
194
195/// Interpreter entry point.
196bool Interpret(InterpState &S, APValue &Result);
197
198/// Interpret a builtin function.
199bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
200 const CallExpr *Call);
201
202/// Interpret an offsetof operation.
203bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
204 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
205
206inline bool Invalid(InterpState &S, CodePtr OpPC);
207
208enum class ArithOp { Add, Sub };
209
210//===----------------------------------------------------------------------===//
211// Returning values
212//===----------------------------------------------------------------------===//
213
214void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
215
216template <PrimType Name, class T = typename PrimConv<Name>::T>
218 const T &Ret = S.Stk.pop<T>();
219
220 // Make sure returned pointers are live. We might be trying to return a
221 // pointer or reference to a local variable.
222 // Just return false, since a diagnostic has already been emitted in Sema.
223 if constexpr (std::is_same_v<T, Pointer>) {
224 // FIXME: We could be calling isLive() here, but the emitted diagnostics
225 // seem a little weird, at least if the returned expression is of
226 // pointer type.
227 // Null pointers are considered live here.
228 if (!Ret.isZero() && !Ret.isLive())
229 return false;
230 }
231
232 assert(S.Current);
233 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
234 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
236
237 if (InterpFrame *Caller = S.Current->Caller) {
238 PC = S.Current->getRetPC();
239 delete S.Current;
240 S.Current = Caller;
241 S.Stk.push<T>(Ret);
242 } else {
243 delete S.Current;
244 S.Current = nullptr;
245 if (!ReturnValue<T>(Ret, Result))
246 return false;
247 }
248 return true;
249}
250
251inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
252 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
253
254 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
256
257 if (InterpFrame *Caller = S.Current->Caller) {
258 PC = S.Current->getRetPC();
259 delete S.Current;
260 S.Current = Caller;
261 } else {
262 delete S.Current;
263 S.Current = nullptr;
264 }
265 return true;
266}
267
268//===----------------------------------------------------------------------===//
269// Add, Sub, Mul
270//===----------------------------------------------------------------------===//
271
272template <typename T, bool (*OpFW)(T, T, unsigned, T *),
273 template <typename U> class OpAP>
274bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
275 const T &RHS) {
276 // Fast path - add the numbers with fixed width.
277 T Result;
278 if (!OpFW(LHS, RHS, Bits, &Result)) {
279 S.Stk.push<T>(Result);
280 return true;
281 }
282
283 // If for some reason evaluation continues, use the truncated results.
284 S.Stk.push<T>(Result);
285
286 // Slow path - compute the result using another bit of precision.
287 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
288
289 // Report undefined behaviour, stopping if required.
290 const Expr *E = S.Current->getExpr(OpPC);
291 QualType Type = E->getType();
292 if (S.checkingForUndefinedBehavior()) {
293 SmallString<32> Trunc;
294 Value.trunc(Result.bitWidth())
295 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
296 /*UpperCase=*/true, /*InsertSeparators=*/true);
297 auto Loc = E->getExprLoc();
298 S.report(Loc, diag::warn_integer_constant_overflow)
299 << Trunc << Type << E->getSourceRange();
300 return true;
301 } else {
302 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
303 if (!S.noteUndefinedBehavior()) {
304 S.Stk.pop<T>();
305 return false;
306 }
307 return true;
308 }
309}
310
311template <PrimType Name, class T = typename PrimConv<Name>::T>
312bool Add(InterpState &S, CodePtr OpPC) {
313 const T &RHS = S.Stk.pop<T>();
314 const T &LHS = S.Stk.pop<T>();
315 const unsigned Bits = RHS.bitWidth() + 1;
316 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
317}
318
319inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
320 const Floating &RHS = S.Stk.pop<Floating>();
321 const Floating &LHS = S.Stk.pop<Floating>();
322
324 auto Status = Floating::add(LHS, RHS, RM, &Result);
325 S.Stk.push<Floating>(Result);
326 return CheckFloatResult(S, OpPC, Result, Status);
327}
328
329template <PrimType Name, class T = typename PrimConv<Name>::T>
330bool Sub(InterpState &S, CodePtr OpPC) {
331 const T &RHS = S.Stk.pop<T>();
332 const T &LHS = S.Stk.pop<T>();
333 const unsigned Bits = RHS.bitWidth() + 1;
334 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
335}
336
337inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
338 const Floating &RHS = S.Stk.pop<Floating>();
339 const Floating &LHS = S.Stk.pop<Floating>();
340
342 auto Status = Floating::sub(LHS, RHS, RM, &Result);
343 S.Stk.push<Floating>(Result);
344 return CheckFloatResult(S, OpPC, Result, Status);
345}
346
347template <PrimType Name, class T = typename PrimConv<Name>::T>
348bool Mul(InterpState &S, CodePtr OpPC) {
349 const T &RHS = S.Stk.pop<T>();
350 const T &LHS = S.Stk.pop<T>();
351 const unsigned Bits = RHS.bitWidth() * 2;
352 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
353}
354
355inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
356 const Floating &RHS = S.Stk.pop<Floating>();
357 const Floating &LHS = S.Stk.pop<Floating>();
358
360 auto Status = Floating::mul(LHS, RHS, RM, &Result);
361 S.Stk.push<Floating>(Result);
362 return CheckFloatResult(S, OpPC, Result, Status);
363}
364/// 1) Pops the RHS from the stack.
365/// 2) Pops the LHS from the stack.
366/// 3) Pushes 'LHS & RHS' on the stack
367template <PrimType Name, class T = typename PrimConv<Name>::T>
368bool BitAnd(InterpState &S, CodePtr OpPC) {
369 const T &RHS = S.Stk.pop<T>();
370 const T &LHS = S.Stk.pop<T>();
371
372 unsigned Bits = RHS.bitWidth();
373 T Result;
374 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
375 S.Stk.push<T>(Result);
376 return true;
377 }
378 return false;
379}
380
381/// 1) Pops the RHS from the stack.
382/// 2) Pops the LHS from the stack.
383/// 3) Pushes 'LHS | RHS' on the stack
384template <PrimType Name, class T = typename PrimConv<Name>::T>
385bool BitOr(InterpState &S, CodePtr OpPC) {
386 const T &RHS = S.Stk.pop<T>();
387 const T &LHS = S.Stk.pop<T>();
388
389 unsigned Bits = RHS.bitWidth();
390 T Result;
391 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
392 S.Stk.push<T>(Result);
393 return true;
394 }
395 return false;
396}
397
398/// 1) Pops the RHS from the stack.
399/// 2) Pops the LHS from the stack.
400/// 3) Pushes 'LHS ^ RHS' on the stack
401template <PrimType Name, class T = typename PrimConv<Name>::T>
402bool BitXor(InterpState &S, CodePtr OpPC) {
403 const T &RHS = S.Stk.pop<T>();
404 const T &LHS = S.Stk.pop<T>();
405
406 unsigned Bits = RHS.bitWidth();
407 T Result;
408 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
409 S.Stk.push<T>(Result);
410 return true;
411 }
412 return false;
413}
414
415/// 1) Pops the RHS from the stack.
416/// 2) Pops the LHS from the stack.
417/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
418template <PrimType Name, class T = typename PrimConv<Name>::T>
419bool Rem(InterpState &S, CodePtr OpPC) {
420 const T &RHS = S.Stk.pop<T>();
421 const T &LHS = S.Stk.pop<T>();
422
423 if (!CheckDivRem(S, OpPC, LHS, RHS))
424 return false;
425
426 const unsigned Bits = RHS.bitWidth() * 2;
427 T Result;
428 if (!T::rem(LHS, RHS, Bits, &Result)) {
429 S.Stk.push<T>(Result);
430 return true;
431 }
432 return false;
433}
434
435/// 1) Pops the RHS from the stack.
436/// 2) Pops the LHS from the stack.
437/// 3) Pushes 'LHS / RHS' on the stack
438template <PrimType Name, class T = typename PrimConv<Name>::T>
439bool Div(InterpState &S, CodePtr OpPC) {
440 const T &RHS = S.Stk.pop<T>();
441 const T &LHS = S.Stk.pop<T>();
442
443 if (!CheckDivRem(S, OpPC, LHS, RHS))
444 return false;
445
446 const unsigned Bits = RHS.bitWidth() * 2;
447 T Result;
448 if (!T::div(LHS, RHS, Bits, &Result)) {
449 S.Stk.push<T>(Result);
450 return true;
451 }
452 return false;
453}
454
455inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
456 const Floating &RHS = S.Stk.pop<Floating>();
457 const Floating &LHS = S.Stk.pop<Floating>();
458
459 if (!CheckDivRem(S, OpPC, LHS, RHS))
460 return false;
461
463 auto Status = Floating::div(LHS, RHS, RM, &Result);
464 S.Stk.push<Floating>(Result);
465 return CheckFloatResult(S, OpPC, Result, Status);
466}
467
468//===----------------------------------------------------------------------===//
469// Inv
470//===----------------------------------------------------------------------===//
471
472template <PrimType Name, class T = typename PrimConv<Name>::T>
473bool Inv(InterpState &S, CodePtr OpPC) {
474 using BoolT = PrimConv<PT_Bool>::T;
475 const T &Val = S.Stk.pop<T>();
476 const unsigned Bits = Val.bitWidth();
477 Boolean R;
478 Boolean::inv(BoolT::from(Val, Bits), &R);
479
480 S.Stk.push<BoolT>(R);
481 return true;
482}
483
484//===----------------------------------------------------------------------===//
485// Neg
486//===----------------------------------------------------------------------===//
487
488template <PrimType Name, class T = typename PrimConv<Name>::T>
489bool Neg(InterpState &S, CodePtr OpPC) {
490 const T &Value = S.Stk.pop<T>();
491 T Result;
492
493 if (!T::neg(Value, &Result)) {
494 S.Stk.push<T>(Result);
495 return true;
496 }
497
498 assert(isIntegralType(Name) &&
499 "don't expect other types to fail at constexpr negation");
500 S.Stk.push<T>(Result);
501
502 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
503 const Expr *E = S.Current->getExpr(OpPC);
504 QualType Type = E->getType();
505
506 if (S.checkingForUndefinedBehavior()) {
507 SmallString<32> Trunc;
508 NegatedValue.trunc(Result.bitWidth())
509 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
510 /*UpperCase=*/true, /*InsertSeparators=*/true);
511 auto Loc = E->getExprLoc();
512 S.report(Loc, diag::warn_integer_constant_overflow)
513 << Trunc << Type << E->getSourceRange();
514 return true;
515 }
516
517 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
518 return S.noteUndefinedBehavior();
519}
520
521enum class PushVal : bool {
522 No,
523 Yes,
524};
525enum class IncDecOp {
526 Inc,
527 Dec,
528};
529
530template <typename T, IncDecOp Op, PushVal DoPush>
531bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
532 assert(!Ptr.isDummy());
533
534 if constexpr (std::is_same_v<T, Boolean>) {
535 if (!S.getLangOpts().CPlusPlus14)
536 return Invalid(S, OpPC);
537 }
538
539 const T &Value = Ptr.deref<T>();
540 T Result;
541
542 if constexpr (DoPush == PushVal::Yes)
543 S.Stk.push<T>(Value);
544
545 if constexpr (Op == IncDecOp::Inc) {
546 if (!T::increment(Value, &Result)) {
547 Ptr.deref<T>() = Result;
548 return true;
549 }
550 } else {
551 if (!T::decrement(Value, &Result)) {
552 Ptr.deref<T>() = Result;
553 return true;
554 }
555 }
556
557 // Something went wrong with the previous operation. Compute the
558 // result with another bit of precision.
559 unsigned Bits = Value.bitWidth() + 1;
560 APSInt APResult;
561 if constexpr (Op == IncDecOp::Inc)
562 APResult = ++Value.toAPSInt(Bits);
563 else
564 APResult = --Value.toAPSInt(Bits);
565
566 // Report undefined behaviour, stopping if required.
567 const Expr *E = S.Current->getExpr(OpPC);
568 QualType Type = E->getType();
569 if (S.checkingForUndefinedBehavior()) {
570 SmallString<32> Trunc;
571 APResult.trunc(Result.bitWidth())
572 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
573 /*UpperCase=*/true, /*InsertSeparators=*/true);
574 auto Loc = E->getExprLoc();
575 S.report(Loc, diag::warn_integer_constant_overflow)
576 << Trunc << Type << E->getSourceRange();
577 return true;
578 }
579
580 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
581 return S.noteUndefinedBehavior();
582}
583
584/// 1) Pops a pointer from the stack
585/// 2) Load the value from the pointer
586/// 3) Writes the value increased by one back to the pointer
587/// 4) Pushes the original (pre-inc) value on the stack.
588template <PrimType Name, class T = typename PrimConv<Name>::T>
589bool Inc(InterpState &S, CodePtr OpPC) {
590 const Pointer &Ptr = S.Stk.pop<Pointer>();
591 if (!CheckDummy(S, OpPC, Ptr))
592 return false;
593 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
594 return false;
595
596 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
597}
598
599/// 1) Pops a pointer from the stack
600/// 2) Load the value from the pointer
601/// 3) Writes the value increased by one back to the pointer
602template <PrimType Name, class T = typename PrimConv<Name>::T>
603bool IncPop(InterpState &S, CodePtr OpPC) {
604 const Pointer &Ptr = S.Stk.pop<Pointer>();
605 if (!CheckDummy(S, OpPC, Ptr))
606 return false;
607 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
608 return false;
609
610 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
611}
612
613/// 1) Pops a pointer from the stack
614/// 2) Load the value from the pointer
615/// 3) Writes the value decreased by one back to the pointer
616/// 4) Pushes the original (pre-dec) value on the stack.
617template <PrimType Name, class T = typename PrimConv<Name>::T>
618bool Dec(InterpState &S, CodePtr OpPC) {
619 const Pointer &Ptr = S.Stk.pop<Pointer>();
620 if (!CheckDummy(S, OpPC, Ptr))
621 return false;
622 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
623 return false;
624
625 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
626}
627
628/// 1) Pops a pointer from the stack
629/// 2) Load the value from the pointer
630/// 3) Writes the value decreased by one back to the pointer
631template <PrimType Name, class T = typename PrimConv<Name>::T>
632bool DecPop(InterpState &S, CodePtr OpPC) {
633 const Pointer &Ptr = S.Stk.pop<Pointer>();
634 if (!CheckDummy(S, OpPC, Ptr))
635 return false;
636 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
637 return false;
638
639 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
640}
641
642template <IncDecOp Op, PushVal DoPush>
644 llvm::RoundingMode RM) {
645 Floating Value = Ptr.deref<Floating>();
647
648 if constexpr (DoPush == PushVal::Yes)
649 S.Stk.push<Floating>(Value);
650
651 llvm::APFloat::opStatus Status;
652 if constexpr (Op == IncDecOp::Inc)
653 Status = Floating::increment(Value, RM, &Result);
654 else
655 Status = Floating::decrement(Value, RM, &Result);
656
657 Ptr.deref<Floating>() = Result;
658
659 return CheckFloatResult(S, OpPC, Result, Status);
660}
661
662inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
663 const Pointer &Ptr = S.Stk.pop<Pointer>();
664 if (Ptr.isDummy())
665 return false;
666 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
667 return false;
668
669 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
670}
671
672inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
673 const Pointer &Ptr = S.Stk.pop<Pointer>();
674 if (Ptr.isDummy())
675 return false;
676 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
677 return false;
678
679 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
680}
681
682inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
683 const Pointer &Ptr = S.Stk.pop<Pointer>();
684
685 if (Ptr.isDummy())
686 return false;
687
688 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
689 return false;
690
691 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
692}
693
694inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
695 const Pointer &Ptr = S.Stk.pop<Pointer>();
696
697 if (Ptr.isDummy())
698 return false;
699 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
700 return false;
701
702 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
703}
704
705/// 1) Pops the value from the stack.
706/// 2) Pushes the bitwise complemented value on the stack (~V).
707template <PrimType Name, class T = typename PrimConv<Name>::T>
708bool Comp(InterpState &S, CodePtr OpPC) {
709 const T &Val = S.Stk.pop<T>();
710 T Result;
711 if (!T::comp(Val, &Result)) {
712 S.Stk.push<T>(Result);
713 return true;
714 }
715
716 return false;
717}
718
719//===----------------------------------------------------------------------===//
720// EQ, NE, GT, GE, LT, LE
721//===----------------------------------------------------------------------===//
722
723using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
724
725template <typename T>
727 using BoolT = PrimConv<PT_Bool>::T;
728 const T &RHS = S.Stk.pop<T>();
729 const T &LHS = S.Stk.pop<T>();
730 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
731 return true;
732}
733
734template <typename T>
736 return CmpHelper<T>(S, OpPC, Fn);
737}
738
739/// Function pointers cannot be compared in an ordered way.
740template <>
742 CompareFn Fn) {
743 const auto &RHS = S.Stk.pop<FunctionPointer>();
744 const auto &LHS = S.Stk.pop<FunctionPointer>();
745
746 const SourceInfo &Loc = S.Current->getSource(OpPC);
747 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
748 << LHS.toDiagnosticString(S.getCtx())
749 << RHS.toDiagnosticString(S.getCtx());
750 return false;
751}
752
753template <>
755 CompareFn Fn) {
756 const auto &RHS = S.Stk.pop<FunctionPointer>();
757 const auto &LHS = S.Stk.pop<FunctionPointer>();
758
759 // We cannot compare against weak declarations at compile time.
760 for (const auto &FP : {LHS, RHS}) {
761 if (FP.isWeak()) {
762 const SourceInfo &Loc = S.Current->getSource(OpPC);
763 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
764 << FP.toDiagnosticString(S.getCtx());
765 return false;
766 }
767 }
768
769 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
770 return true;
771}
772
773template <>
775 using BoolT = PrimConv<PT_Bool>::T;
776 const Pointer &RHS = S.Stk.pop<Pointer>();
777 const Pointer &LHS = S.Stk.pop<Pointer>();
778
779 if (!Pointer::hasSameBase(LHS, RHS)) {
780 const SourceInfo &Loc = S.Current->getSource(OpPC);
781 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
782 << LHS.toDiagnosticString(S.getCtx())
783 << RHS.toDiagnosticString(S.getCtx());
784 return false;
785 } else {
786 unsigned VL = LHS.getByteOffset();
787 unsigned VR = RHS.getByteOffset();
788 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
789 return true;
790 }
791}
792
793template <>
795 using BoolT = PrimConv<PT_Bool>::T;
796 const Pointer &RHS = S.Stk.pop<Pointer>();
797 const Pointer &LHS = S.Stk.pop<Pointer>();
798
799 if (LHS.isZero() && RHS.isZero()) {
800 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
801 return true;
802 }
803
804 for (const auto &P : {LHS, RHS}) {
805 if (P.isZero())
806 continue;
807 if (P.isWeak()) {
808 const SourceInfo &Loc = S.Current->getSource(OpPC);
809 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
810 << P.toDiagnosticString(S.getCtx());
811 return false;
812 }
813 }
814
815 if (!Pointer::hasSameBase(LHS, RHS)) {
816 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
817 return true;
818 } else {
819 unsigned VL = LHS.getByteOffset();
820 unsigned VR = RHS.getByteOffset();
821
822 // In our Pointer class, a pointer to an array and a pointer to the first
823 // element in the same array are NOT equal. They have the same Base value,
824 // but a different Offset. This is a pretty rare case, so we fix this here
825 // by comparing pointers to the first elements.
826 if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
827 VL = LHS.atIndex(0).getByteOffset();
828 if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
829 VR = RHS.atIndex(0).getByteOffset();
830
831 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
832 return true;
833 }
834}
835
836template <PrimType Name, class T = typename PrimConv<Name>::T>
837bool EQ(InterpState &S, CodePtr OpPC) {
838 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
840 });
841}
842
843template <PrimType Name, class T = typename PrimConv<Name>::T>
844bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
845 const T &RHS = S.Stk.pop<T>();
846 const T &LHS = S.Stk.pop<T>();
847 const Pointer &P = S.Stk.peek<Pointer>();
848
849 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
850 if (CmpResult == ComparisonCategoryResult::Unordered) {
851 // This should only happen with pointers.
852 const SourceInfo &Loc = S.Current->getSource(OpPC);
853 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
854 << LHS.toDiagnosticString(S.getCtx())
855 << RHS.toDiagnosticString(S.getCtx());
856 return false;
857 }
858
859 assert(CmpInfo);
860 const auto *CmpValueInfo =
861 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
862 assert(CmpValueInfo);
863 assert(CmpValueInfo->hasValidIntValue());
864 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
865}
866
867template <PrimType Name, class T = typename PrimConv<Name>::T>
868bool NE(InterpState &S, CodePtr OpPC) {
869 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
871 });
872}
873
874template <PrimType Name, class T = typename PrimConv<Name>::T>
875bool LT(InterpState &S, CodePtr OpPC) {
876 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
878 });
879}
880
881template <PrimType Name, class T = typename PrimConv<Name>::T>
882bool LE(InterpState &S, CodePtr OpPC) {
883 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
884 return R == ComparisonCategoryResult::Less ||
886 });
887}
888
889template <PrimType Name, class T = typename PrimConv<Name>::T>
890bool GT(InterpState &S, CodePtr OpPC) {
891 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
893 });
894}
895
896template <PrimType Name, class T = typename PrimConv<Name>::T>
897bool GE(InterpState &S, CodePtr OpPC) {
898 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
901 });
902}
903
904//===----------------------------------------------------------------------===//
905// InRange
906//===----------------------------------------------------------------------===//
907
908template <PrimType Name, class T = typename PrimConv<Name>::T>
910 const T RHS = S.Stk.pop<T>();
911 const T LHS = S.Stk.pop<T>();
912 const T Value = S.Stk.pop<T>();
913
914 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
915 return true;
916}
917
918//===----------------------------------------------------------------------===//
919// Dup, Pop, Test
920//===----------------------------------------------------------------------===//
921
922template <PrimType Name, class T = typename PrimConv<Name>::T>
923bool Dup(InterpState &S, CodePtr OpPC) {
924 S.Stk.push<T>(S.Stk.peek<T>());
925 return true;
926}
927
928template <PrimType Name, class T = typename PrimConv<Name>::T>
929bool Pop(InterpState &S, CodePtr OpPC) {
930 S.Stk.pop<T>();
931 return true;
932}
933
934//===----------------------------------------------------------------------===//
935// Const
936//===----------------------------------------------------------------------===//
937
938template <PrimType Name, class T = typename PrimConv<Name>::T>
939bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
940 S.Stk.push<T>(Arg);
941 return true;
942}
943
944//===----------------------------------------------------------------------===//
945// Get/Set Local/Param/Global/This
946//===----------------------------------------------------------------------===//
947
948template <PrimType Name, class T = typename PrimConv<Name>::T>
949bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
950 const Pointer &Ptr = S.Current->getLocalPointer(I);
951 if (!CheckLoad(S, OpPC, Ptr))
952 return false;
953 S.Stk.push<T>(Ptr.deref<T>());
954 return true;
955}
956
957/// 1) Pops the value from the stack.
958/// 2) Writes the value to the local variable with the
959/// given offset.
960template <PrimType Name, class T = typename PrimConv<Name>::T>
961bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
962 S.Current->setLocal<T>(I, S.Stk.pop<T>());
963 return true;
964}
965
966template <PrimType Name, class T = typename PrimConv<Name>::T>
967bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
968 if (S.checkingPotentialConstantExpression()) {
969 return false;
970 }
971 S.Stk.push<T>(S.Current->getParam<T>(I));
972 return true;
973}
974
975template <PrimType Name, class T = typename PrimConv<Name>::T>
976bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
977 S.Current->setParam<T>(I, S.Stk.pop<T>());
978 return true;
979}
980
981/// 1) Peeks a pointer on the stack
982/// 2) Pushes the value of the pointer's field on the stack
983template <PrimType Name, class T = typename PrimConv<Name>::T>
984bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
985 const Pointer &Obj = S.Stk.peek<Pointer>();
986 if (!CheckNull(S, OpPC, Obj, CSK_Field))
987 return false;
988 if (!CheckRange(S, OpPC, Obj, CSK_Field))
989 return false;
990 const Pointer &Field = Obj.atField(I);
991 if (!CheckLoad(S, OpPC, Field))
992 return false;
993 S.Stk.push<T>(Field.deref<T>());
994 return true;
995}
996
997template <PrimType Name, class T = typename PrimConv<Name>::T>
998bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
999 const T &Value = S.Stk.pop<T>();
1000 const Pointer &Obj = S.Stk.peek<Pointer>();
1001 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1002 return false;
1003 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1004 return false;
1005 const Pointer &Field = Obj.atField(I);
1006 if (!CheckStore(S, OpPC, Field))
1007 return false;
1008 Field.initialize();
1009 Field.deref<T>() = Value;
1010 return true;
1011}
1012
1013/// 1) Pops a pointer from the stack
1014/// 2) Pushes the value of the pointer's field on the stack
1015template <PrimType Name, class T = typename PrimConv<Name>::T>
1016bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1017 const Pointer &Obj = S.Stk.pop<Pointer>();
1018 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1019 return false;
1020 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1021 return false;
1022 const Pointer &Field = Obj.atField(I);
1023 if (!CheckLoad(S, OpPC, Field))
1024 return false;
1025 S.Stk.push<T>(Field.deref<T>());
1026 return true;
1027}
1028
1029template <PrimType Name, class T = typename PrimConv<Name>::T>
1030bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1031 if (S.checkingPotentialConstantExpression())
1032 return false;
1033 const Pointer &This = S.Current->getThis();
1034 if (!CheckThis(S, OpPC, This))
1035 return false;
1036 const Pointer &Field = This.atField(I);
1037 if (!CheckLoad(S, OpPC, Field))
1038 return false;
1039 S.Stk.push<T>(Field.deref<T>());
1040 return true;
1041}
1042
1043template <PrimType Name, class T = typename PrimConv<Name>::T>
1044bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1045 if (S.checkingPotentialConstantExpression())
1046 return false;
1047 const T &Value = S.Stk.pop<T>();
1048 const Pointer &This = S.Current->getThis();
1049 if (!CheckThis(S, OpPC, This))
1050 return false;
1051 const Pointer &Field = This.atField(I);
1052 if (!CheckStore(S, OpPC, Field))
1053 return false;
1054 Field.deref<T>() = Value;
1055 return true;
1056}
1057
1058template <PrimType Name, class T = typename PrimConv<Name>::T>
1059bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1060 const Pointer &Ptr = S.P.getPtrGlobal(I);
1061 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1062 return false;
1063 if (Ptr.isExtern())
1064 return false;
1065
1066 // If a global variable is uninitialized, that means the initializer we've
1067 // compiled for it wasn't a constant expression. Diagnose that.
1068 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1069 return false;
1070
1071 S.Stk.push<T>(Ptr.deref<T>());
1072 return true;
1073}
1074
1075/// Same as GetGlobal, but without the checks.
1076template <PrimType Name, class T = typename PrimConv<Name>::T>
1077bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1078 auto *B = S.P.getGlobal(I);
1079 S.Stk.push<T>(B->deref<T>());
1080 return true;
1081}
1082
1083template <PrimType Name, class T = typename PrimConv<Name>::T>
1084bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1085 // TODO: emit warning.
1086 return false;
1087}
1088
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1090bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1091 const Pointer &P = S.P.getGlobal(I);
1092 P.deref<T>() = S.Stk.pop<T>();
1093 P.initialize();
1094 return true;
1095}
1096
1097/// 1) Converts the value on top of the stack to an APValue
1098/// 2) Sets that APValue on \Temp
1099/// 3) Initializes global with index \I with that
1100template <PrimType Name, class T = typename PrimConv<Name>::T>
1101bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1102 const LifetimeExtendedTemporaryDecl *Temp) {
1103 assert(Temp);
1104 const T Value = S.Stk.peek<T>();
1105 APValue APV = Value.toAPValue();
1106 APValue *Cached = Temp->getOrCreateValue(true);
1107 *Cached = APV;
1108
1109 const Pointer &P = S.P.getGlobal(I);
1110 P.deref<T>() = S.Stk.pop<T>();
1111 P.initialize();
1112
1113 return true;
1114}
1115
1116/// 1) Converts the value on top of the stack to an APValue
1117/// 2) Sets that APValue on \Temp
1118/// 3) Initialized global with index \I with that
1120 const LifetimeExtendedTemporaryDecl *Temp) {
1121 assert(Temp);
1122 const Pointer &P = S.Stk.peek<Pointer>();
1123 APValue *Cached = Temp->getOrCreateValue(true);
1124
1125 if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
1126 *Cached = *APV;
1127 return true;
1128 }
1129
1130 return false;
1131}
1132
1133template <PrimType Name, class T = typename PrimConv<Name>::T>
1134bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1135 if (S.checkingPotentialConstantExpression())
1136 return false;
1137 const Pointer &This = S.Current->getThis();
1138 if (!CheckThis(S, OpPC, This))
1139 return false;
1140 const Pointer &Field = This.atField(I);
1141 Field.deref<T>() = S.Stk.pop<T>();
1142 Field.initialize();
1143 return true;
1144}
1145
1146// FIXME: The Field pointer here is too much IMO and we could instead just
1147// pass an Offset + BitWidth pair.
1148template <PrimType Name, class T = typename PrimConv<Name>::T>
1149bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1150 uint32_t FieldOffset) {
1151 assert(F->isBitField());
1152 if (S.checkingPotentialConstantExpression())
1153 return false;
1154 const Pointer &This = S.Current->getThis();
1155 if (!CheckThis(S, OpPC, This))
1156 return false;
1157 const Pointer &Field = This.atField(FieldOffset);
1158 const auto &Value = S.Stk.pop<T>();
1159 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1160 Field.initialize();
1161 return true;
1162}
1163
1164template <PrimType Name, class T = typename PrimConv<Name>::T>
1165bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1166 if (S.checkingPotentialConstantExpression())
1167 return false;
1168 const Pointer &This = S.Current->getThis();
1169 if (!CheckThis(S, OpPC, This))
1170 return false;
1171 const Pointer &Field = This.atField(I);
1172 Field.deref<T>() = S.Stk.pop<T>();
1173 Field.activate();
1174 Field.initialize();
1175 return true;
1176}
1177
1178/// 1) Pops the value from the stack
1179/// 2) Peeks a pointer from the stack
1180/// 3) Pushes the value to field I of the pointer on the stack
1181template <PrimType Name, class T = typename PrimConv<Name>::T>
1182bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1183 const T &Value = S.Stk.pop<T>();
1184 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1185 Field.deref<T>() = Value;
1186 Field.activate();
1187 Field.initialize();
1188 return true;
1189}
1190
1191template <PrimType Name, class T = typename PrimConv<Name>::T>
1192bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1193 assert(F->isBitField());
1194 const T &Value = S.Stk.pop<T>();
1195 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1196 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1197 Field.activate();
1198 Field.initialize();
1199 return true;
1200}
1201
1202template <PrimType Name, class T = typename PrimConv<Name>::T>
1203bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1204 const T &Value = S.Stk.pop<T>();
1205 const Pointer &Ptr = S.Stk.pop<Pointer>();
1206 const Pointer &Field = Ptr.atField(I);
1207 Field.deref<T>() = Value;
1208 Field.activate();
1209 Field.initialize();
1210 return true;
1211}
1212
1213//===----------------------------------------------------------------------===//
1214// GetPtr Local/Param/Global/Field/This
1215//===----------------------------------------------------------------------===//
1216
1217inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1218 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1219 return true;
1220}
1221
1222inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1223 if (S.checkingPotentialConstantExpression()) {
1224 return false;
1225 }
1226 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1227 return true;
1228}
1229
1230inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1231 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1232 return true;
1233}
1234
1235/// 1) Pops a Pointer from the stack
1236/// 2) Pushes Pointer.atField(Off) on the stack
1237inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1238 const Pointer &Ptr = S.Stk.pop<Pointer>();
1239
1240 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1241 !CheckNull(S, OpPC, Ptr, CSK_Field))
1242 return false;
1243
1244 if (CheckDummy(S, OpPC, Ptr)) {
1245 if (!CheckExtern(S, OpPC, Ptr))
1246 return false;
1247 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1248 return false;
1249 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1250 return false;
1251 }
1252 S.Stk.push<Pointer>(Ptr.atField(Off));
1253 return true;
1254}
1255
1256inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1257 if (S.checkingPotentialConstantExpression())
1258 return false;
1259 const Pointer &This = S.Current->getThis();
1260 if (!CheckThis(S, OpPC, This))
1261 return false;
1262 S.Stk.push<Pointer>(This.atField(Off));
1263 return true;
1264}
1265
1266inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1267 const Pointer &Ptr = S.Stk.pop<Pointer>();
1268 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1269 return false;
1270 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1271 return false;
1272 Pointer Field = Ptr.atField(Off);
1273 Ptr.deactivate();
1274 Field.activate();
1275 S.Stk.push<Pointer>(std::move(Field));
1276 return true;
1277}
1278
1279inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1280 if (S.checkingPotentialConstantExpression())
1281 return false;
1282 const Pointer &This = S.Current->getThis();
1283 if (!CheckThis(S, OpPC, This))
1284 return false;
1285 Pointer Field = This.atField(Off);
1286 This.deactivate();
1287 Field.activate();
1288 S.Stk.push<Pointer>(std::move(Field));
1289 return true;
1290}
1291
1292inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1293 const Pointer &Ptr = S.Stk.pop<Pointer>();
1294 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1295 return false;
1296 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1297 return false;
1298 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1299 return true;
1300}
1301
1302inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1303 const Pointer &Ptr = S.Stk.peek<Pointer>();
1304 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1305 return false;
1306 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1307 return false;
1308 S.Stk.push<Pointer>(Ptr.atField(Off));
1309 return true;
1310}
1311
1312inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1313 const Pointer &Ptr = S.Stk.pop<Pointer>();
1314 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1315 return false;
1316 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1317 return false;
1318 S.Stk.push<Pointer>(Ptr.atField(Off));
1319 return true;
1320}
1321
1322inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1323 if (S.checkingPotentialConstantExpression())
1324 return false;
1325 const Pointer &This = S.Current->getThis();
1326 if (!CheckThis(S, OpPC, This))
1327 return false;
1328 S.Stk.push<Pointer>(This.atField(Off));
1329 return true;
1330}
1331
1332inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1333 const Pointer &Ptr = S.Stk.pop<Pointer>();
1334 if (Ptr.canBeInitialized())
1335 Ptr.initialize();
1336 return true;
1337}
1338
1339inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1340 const Pointer &Ptr = S.Stk.peek<Pointer>();
1341
1342 if (Ptr.canBeInitialized())
1343 Ptr.initialize();
1344 return true;
1345}
1346
1347inline bool Dump(InterpState &S, CodePtr OpPC) {
1348 S.Stk.dump();
1349 return true;
1350}
1351
1352inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1353 const Pointer &Ptr) {
1354 Pointer Base = Ptr;
1355 while (Base.isBaseClass())
1356 Base = Base.getBase();
1357
1358 auto *Field = Base.getRecord()->getVirtualBase(Decl);
1359 S.Stk.push<Pointer>(Base.atField(Field->Offset));
1360 return true;
1361}
1362
1363inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1364 const Pointer &Ptr = S.Stk.pop<Pointer>();
1365 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1366 return false;
1367 return VirtBaseHelper(S, OpPC, D, Ptr);
1368}
1369
1371 const RecordDecl *D) {
1372 if (S.checkingPotentialConstantExpression())
1373 return false;
1374 const Pointer &This = S.Current->getThis();
1375 if (!CheckThis(S, OpPC, This))
1376 return false;
1377 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1378}
1379
1380//===----------------------------------------------------------------------===//
1381// Load, Store, Init
1382//===----------------------------------------------------------------------===//
1383
1384template <PrimType Name, class T = typename PrimConv<Name>::T>
1385bool Load(InterpState &S, CodePtr OpPC) {
1386 const Pointer &Ptr = S.Stk.peek<Pointer>();
1387 if (!CheckLoad(S, OpPC, Ptr))
1388 return false;
1389 if (!Ptr.isBlockPointer())
1390 return false;
1391 S.Stk.push<T>(Ptr.deref<T>());
1392 return true;
1393}
1394
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1397 const Pointer &Ptr = S.Stk.pop<Pointer>();
1398 if (!CheckLoad(S, OpPC, Ptr))
1399 return false;
1400 if (!Ptr.isBlockPointer())
1401 return false;
1402 S.Stk.push<T>(Ptr.deref<T>());
1403 return true;
1404}
1405
1406template <PrimType Name, class T = typename PrimConv<Name>::T>
1407bool Store(InterpState &S, CodePtr OpPC) {
1408 const T &Value = S.Stk.pop<T>();
1409 const Pointer &Ptr = S.Stk.peek<Pointer>();
1410 if (!CheckStore(S, OpPC, Ptr))
1411 return false;
1412 if (Ptr.canBeInitialized())
1413 Ptr.initialize();
1414 Ptr.deref<T>() = Value;
1415 return true;
1416}
1417
1418template <PrimType Name, class T = typename PrimConv<Name>::T>
1420 const T &Value = S.Stk.pop<T>();
1421 const Pointer &Ptr = S.Stk.pop<Pointer>();
1422 if (!CheckStore(S, OpPC, Ptr))
1423 return false;
1424 if (Ptr.canBeInitialized())
1425 Ptr.initialize();
1426 Ptr.deref<T>() = Value;
1427 return true;
1428}
1429
1430template <PrimType Name, class T = typename PrimConv<Name>::T>
1432 const T &Value = S.Stk.pop<T>();
1433 const Pointer &Ptr = S.Stk.peek<Pointer>();
1434 if (!CheckStore(S, OpPC, Ptr))
1435 return false;
1436 if (Ptr.canBeInitialized())
1437 Ptr.initialize();
1438 if (const auto *FD = Ptr.getField())
1439 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1440 else
1441 Ptr.deref<T>() = Value;
1442 return true;
1443}
1444
1445template <PrimType Name, class T = typename PrimConv<Name>::T>
1447 const T &Value = S.Stk.pop<T>();
1448 const Pointer &Ptr = S.Stk.pop<Pointer>();
1449 if (!CheckStore(S, OpPC, Ptr))
1450 return false;
1451 if (Ptr.canBeInitialized())
1452 Ptr.initialize();
1453 if (const auto *FD = Ptr.getField())
1454 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1455 else
1456 Ptr.deref<T>() = Value;
1457 return true;
1458}
1459
1460template <PrimType Name, class T = typename PrimConv<Name>::T>
1461bool Init(InterpState &S, CodePtr OpPC) {
1462 const T &Value = S.Stk.pop<T>();
1463 const Pointer &Ptr = S.Stk.peek<Pointer>();
1464 if (!CheckInit(S, OpPC, Ptr)) {
1465 assert(false);
1466 return false;
1467 }
1468 Ptr.initialize();
1469 new (&Ptr.deref<T>()) T(Value);
1470 return true;
1471}
1472
1473template <PrimType Name, class T = typename PrimConv<Name>::T>
1475 const T &Value = S.Stk.pop<T>();
1476 const Pointer &Ptr = S.Stk.pop<Pointer>();
1477 if (!CheckInit(S, OpPC, Ptr))
1478 return false;
1479 Ptr.initialize();
1480 new (&Ptr.deref<T>()) T(Value);
1481 return true;
1482}
1483
1484/// 1) Pops the value from the stack
1485/// 2) Peeks a pointer and gets its index \Idx
1486/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1487template <PrimType Name, class T = typename PrimConv<Name>::T>
1488bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1489 const T &Value = S.Stk.pop<T>();
1490 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1491 if (Ptr.isUnknownSizeArray())
1492 return false;
1493 if (!CheckInit(S, OpPC, Ptr))
1494 return false;
1495 Ptr.initialize();
1496 new (&Ptr.deref<T>()) T(Value);
1497 return true;
1498}
1499
1500/// The same as InitElem, but pops the pointer as well.
1501template <PrimType Name, class T = typename PrimConv<Name>::T>
1502bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1503 const T &Value = S.Stk.pop<T>();
1504 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1505 if (Ptr.isUnknownSizeArray())
1506 return false;
1507 if (!CheckInit(S, OpPC, Ptr))
1508 return false;
1509 Ptr.initialize();
1510 new (&Ptr.deref<T>()) T(Value);
1511 return true;
1512}
1513
1514inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1515 const Pointer &Src = S.Stk.pop<Pointer>();
1516 Pointer &Dest = S.Stk.peek<Pointer>();
1517
1518 if (!CheckLoad(S, OpPC, Src))
1519 return false;
1520
1521 return DoMemcpy(S, OpPC, Src, Dest);
1522}
1523
1524//===----------------------------------------------------------------------===//
1525// AddOffset, SubOffset
1526//===----------------------------------------------------------------------===//
1527
1528template <class T, ArithOp Op>
1529bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1530 const Pointer &Ptr) {
1531 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1532 return false;
1533
1534 // A zero offset does not change the pointer.
1535 if (Offset.isZero()) {
1536 S.Stk.push<Pointer>(Ptr);
1537 return true;
1538 }
1539
1540 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1541 // The CheckNull will have emitted a note already, but we only
1542 // abort in C++, since this is fine in C.
1543 if (S.getLangOpts().CPlusPlus)
1544 return false;
1545 }
1546
1547 // Arrays of unknown bounds cannot have pointers into them.
1548 if (!CheckArray(S, OpPC, Ptr))
1549 return false;
1550
1551 // Get a version of the index comparable to the type.
1552 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1553 // Compute the largest index into the array.
1554 T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
1555
1556 bool Invalid = false;
1557 // Helper to report an invalid offset, computed as APSInt.
1558 auto DiagInvalidOffset = [&]() -> void {
1559 const unsigned Bits = Offset.bitWidth();
1560 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1561 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1562 APSInt NewIndex =
1563 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1564 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1565 << NewIndex
1566 << /*array*/ static_cast<int>(!Ptr.inArray())
1567 << static_cast<unsigned>(MaxIndex);
1568 Invalid = true;
1569 };
1570
1571 if (Ptr.isBlockPointer()) {
1572 T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
1573 if constexpr (Op == ArithOp::Add) {
1574 // If the new offset would be negative, bail out.
1575 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1576 DiagInvalidOffset();
1577
1578 // If the new offset would be out of bounds, bail out.
1579 if (Offset.isPositive() && Offset > MaxOffset)
1580 DiagInvalidOffset();
1581 } else {
1582 // If the new offset would be negative, bail out.
1583 if (Offset.isPositive() && Index < Offset)
1584 DiagInvalidOffset();
1585
1586 // If the new offset would be out of bounds, bail out.
1587 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1588 DiagInvalidOffset();
1589 }
1590 }
1591
1592 if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
1593 return false;
1594
1595 // Offset is valid - compute it on unsigned.
1596 int64_t WideIndex = static_cast<int64_t>(Index);
1597 int64_t WideOffset = static_cast<int64_t>(Offset);
1598 int64_t Result;
1599 if constexpr (Op == ArithOp::Add)
1600 Result = WideIndex + WideOffset;
1601 else
1602 Result = WideIndex - WideOffset;
1603
1604 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1605 return true;
1606}
1607
1608template <PrimType Name, class T = typename PrimConv<Name>::T>
1610 const T &Offset = S.Stk.pop<T>();
1611 const Pointer &Ptr = S.Stk.pop<Pointer>();
1612 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1613}
1614
1615template <PrimType Name, class T = typename PrimConv<Name>::T>
1617 const T &Offset = S.Stk.pop<T>();
1618 const Pointer &Ptr = S.Stk.pop<Pointer>();
1619 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1620}
1621
1622template <ArithOp Op>
1623static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1624 const Pointer &Ptr) {
1625 if (Ptr.isDummy())
1626 return false;
1627
1628 using OneT = Integral<8, false>;
1629
1630 const Pointer &P = Ptr.deref<Pointer>();
1631 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1632 return false;
1633
1634 // Get the current value on the stack.
1635 S.Stk.push<Pointer>(P);
1636
1637 // Now the current Ptr again and a constant 1.
1638 OneT One = OneT::from(1);
1639 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1640 return false;
1641
1642 // Store the new value.
1643 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1644 return true;
1645}
1646
1647static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1648 const Pointer &Ptr = S.Stk.pop<Pointer>();
1649
1650 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1651 return false;
1652
1653 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1654}
1655
1656static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1657 const Pointer &Ptr = S.Stk.pop<Pointer>();
1658
1659 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1660 return false;
1661
1662 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1663}
1664
1665/// 1) Pops a Pointer from the stack.
1666/// 2) Pops another Pointer from the stack.
1667/// 3) Pushes the different of the indices of the two pointers on the stack.
1668template <PrimType Name, class T = typename PrimConv<Name>::T>
1669inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1670 const Pointer &LHS = S.Stk.pop<Pointer>();
1671 const Pointer &RHS = S.Stk.pop<Pointer>();
1672
1673 if (RHS.isZero()) {
1674 S.Stk.push<T>(T::from(LHS.getIndex()));
1675 return true;
1676 }
1677
1678 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1679 // TODO: Diagnose.
1680 return false;
1681 }
1682
1683 if (LHS.isZero() && RHS.isZero()) {
1684 S.Stk.push<T>();
1685 return true;
1686 }
1687
1688 T A = T::from(LHS.getIndex());
1689 T B = T::from(RHS.getIndex());
1690 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1691}
1692
1693//===----------------------------------------------------------------------===//
1694// Destroy
1695//===----------------------------------------------------------------------===//
1696
1697inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1698 S.Current->destroy(I);
1699 return true;
1700}
1701
1702//===----------------------------------------------------------------------===//
1703// Cast, CastFP
1704//===----------------------------------------------------------------------===//
1705
1706template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1707 using T = typename PrimConv<TIn>::T;
1708 using U = typename PrimConv<TOut>::T;
1709 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1710 return true;
1711}
1712
1713/// 1) Pops a Floating from the stack.
1714/// 2) Pushes a new floating on the stack that uses the given semantics.
1715inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1716 llvm::RoundingMode RM) {
1717 Floating F = S.Stk.pop<Floating>();
1718 Floating Result = F.toSemantics(Sem, RM);
1719 S.Stk.push<Floating>(Result);
1720 return true;
1721}
1722
1723/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1724/// to know what bitwidth the result should be.
1725template <PrimType Name, class T = typename PrimConv<Name>::T>
1726bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1727 S.Stk.push<IntegralAP<false>>(
1728 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1729 return true;
1730}
1731
1732template <PrimType Name, class T = typename PrimConv<Name>::T>
1733bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1734 S.Stk.push<IntegralAP<true>>(
1735 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1736 return true;
1737}
1738
1739template <PrimType Name, class T = typename PrimConv<Name>::T>
1741 const llvm::fltSemantics *Sem,
1742 llvm::RoundingMode RM) {
1743 const T &From = S.Stk.pop<T>();
1744 APSInt FromAP = From.toAPSInt();
1746
1747 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1748 S.Stk.push<Floating>(Result);
1749
1750 return CheckFloatResult(S, OpPC, Result, Status);
1751}
1752
1753template <PrimType Name, class T = typename PrimConv<Name>::T>
1755 const Floating &F = S.Stk.pop<Floating>();
1756
1757 if constexpr (std::is_same_v<T, Boolean>) {
1758 S.Stk.push<T>(T(F.isNonZero()));
1759 return true;
1760 } else {
1761 APSInt Result(std::max(8u, T::bitWidth()),
1762 /*IsUnsigned=*/!T::isSigned());
1763 auto Status = F.convertToInteger(Result);
1764
1765 // Float-to-Integral overflow check.
1766 if ((Status & APFloat::opStatus::opInvalidOp)) {
1767 const Expr *E = S.Current->getExpr(OpPC);
1768 QualType Type = E->getType();
1769
1770 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1771 if (S.noteUndefinedBehavior()) {
1772 S.Stk.push<T>(T(Result));
1773 return true;
1774 }
1775 return false;
1776 }
1777
1778 S.Stk.push<T>(T(Result));
1779 return CheckFloatResult(S, OpPC, F, Status);
1780 }
1781}
1782
1783static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1784 uint32_t BitWidth) {
1785 const Floating &F = S.Stk.pop<Floating>();
1786
1787 APSInt Result(BitWidth, /*IsUnsigned=*/true);
1788 auto Status = F.convertToInteger(Result);
1789
1790 // Float-to-Integral overflow check.
1791 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1792 const Expr *E = S.Current->getExpr(OpPC);
1793 QualType Type = E->getType();
1794
1795 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1796 return S.noteUndefinedBehavior();
1797 }
1798
1800 return CheckFloatResult(S, OpPC, F, Status);
1801}
1802
1803static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1804 uint32_t BitWidth) {
1805 const Floating &F = S.Stk.pop<Floating>();
1806
1807 APSInt Result(BitWidth, /*IsUnsigned=*/false);
1808 auto Status = F.convertToInteger(Result);
1809
1810 // Float-to-Integral overflow check.
1811 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1812 const Expr *E = S.Current->getExpr(OpPC);
1813 QualType Type = E->getType();
1814
1815 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1816 return S.noteUndefinedBehavior();
1817 }
1818
1820 return CheckFloatResult(S, OpPC, F, Status);
1821}
1822
1823template <PrimType Name, class T = typename PrimConv<Name>::T>
1825 const Pointer &Ptr = S.Stk.pop<Pointer>();
1826
1827 const SourceInfo &E = S.Current->getSource(OpPC);
1828 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1829 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1830
1831 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1832 return true;
1833}
1834
1835//===----------------------------------------------------------------------===//
1836// Zero, Nullptr
1837//===----------------------------------------------------------------------===//
1838
1839template <PrimType Name, class T = typename PrimConv<Name>::T>
1840bool Zero(InterpState &S, CodePtr OpPC) {
1841 S.Stk.push<T>(T::zero());
1842 return true;
1843}
1844
1845static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1846 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
1847 return true;
1848}
1849
1850static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1851 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
1852 return true;
1853}
1854
1855template <PrimType Name, class T = typename PrimConv<Name>::T>
1856inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
1857 // Note: Desc can be null.
1858 S.Stk.push<T>(0, Desc);
1859 return true;
1860}
1861
1862//===----------------------------------------------------------------------===//
1863// This, ImplicitThis
1864//===----------------------------------------------------------------------===//
1865
1866inline bool This(InterpState &S, CodePtr OpPC) {
1867 // Cannot read 'this' in this mode.
1868 if (S.checkingPotentialConstantExpression()) {
1869 return false;
1870 }
1871
1872 const Pointer &This = S.Current->getThis();
1873 if (!CheckThis(S, OpPC, This))
1874 return false;
1875
1876 // Ensure the This pointer has been cast to the correct base.
1877 if (!This.isDummy()) {
1878 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
1879 assert(This.getRecord());
1880 assert(
1881 This.getRecord()->getDecl() ==
1882 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
1883 }
1884
1885 S.Stk.push<Pointer>(This);
1886 return true;
1887}
1888
1889inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1890 assert(S.Current->getFunction()->hasRVO());
1891 if (S.checkingPotentialConstantExpression())
1892 return false;
1893 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1894 return true;
1895}
1896
1897//===----------------------------------------------------------------------===//
1898// Shr, Shl
1899//===----------------------------------------------------------------------===//
1900
1901template <PrimType NameL, PrimType NameR>
1902inline bool Shr(InterpState &S, CodePtr OpPC) {
1903 using LT = typename PrimConv<NameL>::T;
1904 using RT = typename PrimConv<NameR>::T;
1905 const auto &RHS = S.Stk.pop<RT>();
1906 const auto &LHS = S.Stk.pop<LT>();
1907 const unsigned Bits = LHS.bitWidth();
1908
1909 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1910 return false;
1911
1912 // Limit the shift amount to Bits - 1. If this happened,
1913 // it has already been diagnosed by CheckShift() above,
1914 // but we still need to handle it.
1915 typename LT::AsUnsigned R;
1916 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1917 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1918 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1919 else
1920 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1921 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1922 S.Stk.push<LT>(LT::from(R));
1923 return true;
1924}
1925
1926template <PrimType NameL, PrimType NameR>
1927inline bool Shl(InterpState &S, CodePtr OpPC) {
1928 using LT = typename PrimConv<NameL>::T;
1929 using RT = typename PrimConv<NameR>::T;
1930 const auto &RHS = S.Stk.pop<RT>();
1931 const auto &LHS = S.Stk.pop<LT>();
1932 const unsigned Bits = LHS.bitWidth();
1933
1934 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1935 return false;
1936
1937 // Limit the shift amount to Bits - 1. If this happened,
1938 // it has already been diagnosed by CheckShift() above,
1939 // but we still need to handle it.
1940 typename LT::AsUnsigned R;
1941 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1942 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1943 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1944 else
1945 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1946 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1947
1948 S.Stk.push<LT>(LT::from(R));
1949 return true;
1950}
1951
1952//===----------------------------------------------------------------------===//
1953// NoRet
1954//===----------------------------------------------------------------------===//
1955
1956inline bool NoRet(InterpState &S, CodePtr OpPC) {
1957 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1958 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1959 return false;
1960}
1961
1962//===----------------------------------------------------------------------===//
1963// NarrowPtr, ExpandPtr
1964//===----------------------------------------------------------------------===//
1965
1966inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1967 const Pointer &Ptr = S.Stk.pop<Pointer>();
1968 S.Stk.push<Pointer>(Ptr.narrow());
1969 return true;
1970}
1971
1972inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1973 const Pointer &Ptr = S.Stk.pop<Pointer>();
1974 S.Stk.push<Pointer>(Ptr.expand());
1975 return true;
1976}
1977
1978// 1) Pops an integral value from the stack
1979// 2) Peeks a pointer
1980// 3) Pushes a new pointer that's a narrowed array
1981// element of the peeked pointer with the value
1982// from 1) added as offset.
1983//
1984// This leaves the original pointer on the stack and pushes a new one
1985// with the offset applied and narrowed.
1986template <PrimType Name, class T = typename PrimConv<Name>::T>
1987inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1988 const T &Offset = S.Stk.pop<T>();
1989 const Pointer &Ptr = S.Stk.peek<Pointer>();
1990
1991 if (!Ptr.isZero()) {
1992 if (!CheckArray(S, OpPC, Ptr))
1993 return false;
1994
1995 if (Ptr.isDummy()) {
1996 S.Stk.push<Pointer>(Ptr);
1997 return true;
1998 }
1999 }
2000
2001 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2002 return false;
2003
2004 return NarrowPtr(S, OpPC);
2005}
2006
2007template <PrimType Name, class T = typename PrimConv<Name>::T>
2008inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2009 const T &Offset = S.Stk.pop<T>();
2010 const Pointer &Ptr = S.Stk.pop<Pointer>();
2011
2012 if (!Ptr.isZero()) {
2013 if (!CheckArray(S, OpPC, Ptr))
2014 return false;
2015
2016 if (Ptr.isDummy()) {
2017 S.Stk.push<Pointer>(Ptr);
2018 return true;
2019 }
2020 }
2021
2022 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2023 return false;
2024
2025 return NarrowPtr(S, OpPC);
2026}
2027
2028template <PrimType Name, class T = typename PrimConv<Name>::T>
2029inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2030 const Pointer &Ptr = S.Stk.peek<Pointer>();
2031
2032 if (!CheckLoad(S, OpPC, Ptr))
2033 return false;
2034
2035 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2036 return true;
2037}
2038
2039template <PrimType Name, class T = typename PrimConv<Name>::T>
2040inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2041 const Pointer &Ptr = S.Stk.pop<Pointer>();
2042
2043 if (!CheckLoad(S, OpPC, Ptr))
2044 return false;
2045
2046 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2047 return true;
2048}
2049
2050/// Just takes a pointer and checks if it's an incomplete
2051/// array type.
2052inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2053 const Pointer &Ptr = S.Stk.pop<Pointer>();
2054
2055 if (Ptr.isZero() || Ptr.isDummy()) {
2056 S.Stk.push<Pointer>(Ptr);
2057 return true;
2058 }
2059
2060 if (!Ptr.isUnknownSizeArray()) {
2061 S.Stk.push<Pointer>(Ptr.atIndex(0));
2062 return true;
2063 }
2064
2065 const SourceInfo &E = S.Current->getSource(OpPC);
2066 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2067
2068 return false;
2069}
2070
2071inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2072 uint32_t VarArgSize) {
2073 if (Func->hasThisPointer()) {
2074 size_t ArgSize = Func->getArgSize() + VarArgSize;
2075 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2076 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2077
2078 // If the current function is a lambda static invoker and
2079 // the function we're about to call is a lambda call operator,
2080 // skip the CheckInvoke, since the ThisPtr is a null pointer
2081 // anyway.
2082 if (!(S.Current->getFunction() &&
2083 S.Current->getFunction()->isLambdaStaticInvoker() &&
2084 Func->isLambdaCallOperator())) {
2085 if (!CheckInvoke(S, OpPC, ThisPtr))
2086 return false;
2087 }
2088
2089 if (S.checkingPotentialConstantExpression())
2090 return false;
2091 }
2092
2093 if (!CheckCallable(S, OpPC, Func))
2094 return false;
2095
2096 if (!CheckCallDepth(S, OpPC))
2097 return false;
2098
2099 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2100 InterpFrame *FrameBefore = S.Current;
2101 S.Current = NewFrame.get();
2102
2103 APValue CallResult;
2104 // Note that we cannot assert(CallResult.hasValue()) here since
2105 // Ret() above only sets the APValue if the curent frame doesn't
2106 // have a caller set.
2107 if (Interpret(S, CallResult)) {
2108 NewFrame.release(); // Frame was delete'd already.
2109 assert(S.Current == FrameBefore);
2110 return true;
2111 }
2112
2113 // Interpreting the function failed somehow. Reset to
2114 // previous state.
2115 S.Current = FrameBefore;
2116 return false;
2117
2118 return false;
2119}
2120
2121inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2122 uint32_t VarArgSize) {
2123 if (Func->hasThisPointer()) {
2124 size_t ArgSize = Func->getArgSize() + VarArgSize;
2125 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2126
2127 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2128
2129 // If the current function is a lambda static invoker and
2130 // the function we're about to call is a lambda call operator,
2131 // skip the CheckInvoke, since the ThisPtr is a null pointer
2132 // anyway.
2133 if (!(S.Current->getFunction() &&
2134 S.Current->getFunction()->isLambdaStaticInvoker() &&
2135 Func->isLambdaCallOperator())) {
2136 if (!CheckInvoke(S, OpPC, ThisPtr))
2137 return false;
2138 }
2139
2140 if (S.checkingPotentialConstantExpression())
2141 return false;
2142 }
2143
2144 if (!CheckCallable(S, OpPC, Func))
2145 return false;
2146
2147 if (!CheckCallDepth(S, OpPC))
2148 return false;
2149
2150 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2151 InterpFrame *FrameBefore = S.Current;
2152 S.Current = NewFrame.get();
2153
2154 APValue CallResult;
2155 // Note that we cannot assert(CallResult.hasValue()) here since
2156 // Ret() above only sets the APValue if the curent frame doesn't
2157 // have a caller set.
2158 if (Interpret(S, CallResult)) {
2159 NewFrame.release(); // Frame was delete'd already.
2160 assert(S.Current == FrameBefore);
2161 return true;
2162 }
2163
2164 // Interpreting the function failed somehow. Reset to
2165 // previous state.
2166 S.Current = FrameBefore;
2167 return false;
2168}
2169
2170inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2171 uint32_t VarArgSize) {
2172 assert(Func->hasThisPointer());
2173 assert(Func->isVirtual());
2174 size_t ArgSize = Func->getArgSize() + VarArgSize;
2175 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2176 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2177
2178 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2179 const CXXRecordDecl *DynamicDecl;
2180 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2181 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2182 else
2183 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2184 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2185 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2186 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2187 DynamicDecl, StaticDecl, InitialFunction);
2188
2189 if (Overrider != InitialFunction) {
2190 // DR1872: An instantiated virtual constexpr function can't be called in a
2191 // constant expression (prior to C++20). We can still constant-fold such a
2192 // call.
2193 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2194 const Expr *E = S.Current->getExpr(OpPC);
2195 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2196 }
2197
2198 Func = S.getContext().getOrCreateFunction(Overrider);
2199
2200 const CXXRecordDecl *ThisFieldDecl =
2201 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2202 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2203 // If the function we call is further DOWN the hierarchy than the
2204 // FieldDesc of our pointer, just get the DeclDesc instead, which
2205 // is the furthest we might go up in the hierarchy.
2206 ThisPtr = ThisPtr.getDeclPtr();
2207 }
2208 }
2209
2210 return Call(S, OpPC, Func, VarArgSize);
2211}
2212
2213inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2214 const CallExpr *CE) {
2215 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2216
2217 InterpFrame *FrameBefore = S.Current;
2218 S.Current = NewFrame.get();
2219
2220 if (InterpretBuiltin(S, PC, Func, CE)) {
2221 NewFrame.release();
2222 return true;
2223 }
2224 S.Current = FrameBefore;
2225 return false;
2226}
2227
2228inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2229 const CallExpr *CE) {
2230 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2231
2232 const Function *F = FuncPtr.getFunction();
2233 if (!F) {
2234 const Expr *E = S.Current->getExpr(OpPC);
2235 S.FFDiag(E, diag::note_constexpr_null_callee)
2236 << const_cast<Expr *>(E) << E->getSourceRange();
2237 return false;
2238 }
2239
2240 if (!FuncPtr.isValid())
2241 return false;
2242
2243 assert(F);
2244
2245 // Check argument nullability state.
2246 if (F->hasNonNullAttr()) {
2247 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2248 return false;
2249 }
2250
2251 assert(ArgSize >= F->getWrittenArgSize());
2252 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2253
2254 if (F->isVirtual())
2255 return CallVirt(S, OpPC, F, VarArgSize);
2256
2257 return Call(S, OpPC, F, VarArgSize);
2258}
2259
2260inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2261 assert(Func);
2262 S.Stk.push<FunctionPointer>(Func);
2263 return true;
2264}
2265
2266template <PrimType Name, class T = typename PrimConv<Name>::T>
2267inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2268 const T &IntVal = S.Stk.pop<T>();
2269
2270 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2271 return true;
2272}
2273
2274/// Just emit a diagnostic. The expression that caused emission of this
2275/// op is not valid in a constant context.
2276inline bool Invalid(InterpState &S, CodePtr OpPC) {
2277 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2278 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2279 << S.Current->getRange(OpPC);
2280 return false;
2281}
2282
2283/// Do nothing and just abort execution.
2284inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2285
2286/// Same here, but only for casts.
2287inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2288 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2289
2290 // FIXME: Support diagnosing other invalid cast kinds.
2291 if (Kind == CastKind::Reinterpret)
2292 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
2293 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2294 return false;
2295}
2296
2298 const DeclRefExpr *DR) {
2299 assert(DR);
2300 return CheckDeclRef(S, OpPC, DR);
2301}
2302
2303template <PrimType Name, class T = typename PrimConv<Name>::T>
2304inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2305 llvm::SmallVector<int64_t> ArrayIndices;
2306 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2307 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2308
2309 int64_t Result;
2310 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2311 return false;
2312
2313 S.Stk.push<T>(T::from(Result));
2314
2315 return true;
2316}
2317
2318template <PrimType Name, class T = typename PrimConv<Name>::T>
2319inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2320 const T &Arg = S.Stk.peek<T>();
2321 if (!Arg.isZero())
2322 return true;
2323
2324 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2325 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2326
2327 return false;
2328}
2329
2330/// OldPtr -> Integer -> NewPtr.
2331template <PrimType TIn, PrimType TOut>
2332inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2333 static_assert(isPtrType(TIn) && isPtrType(TOut));
2334 using FromT = typename PrimConv<TIn>::T;
2335 using ToT = typename PrimConv<TOut>::T;
2336
2337 const FromT &OldPtr = S.Stk.pop<FromT>();
2338 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2339 return true;
2340}
2341
2342//===----------------------------------------------------------------------===//
2343// Read opcode arguments
2344//===----------------------------------------------------------------------===//
2345
2346template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2347 if constexpr (std::is_pointer<T>::value) {
2348 uint32_t ID = OpPC.read<uint32_t>();
2349 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2350 } else {
2351 return OpPC.read<T>();
2352 }
2353}
2354
2355template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2357 OpPC += align(F.bytesToSerialize());
2358 return F;
2359}
2360
2361template <>
2362inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2363 CodePtr &OpPC) {
2364 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
2365 OpPC += align(I.bytesToSerialize());
2366 return I;
2367}
2368
2369template <>
2370inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2371 CodePtr &OpPC) {
2372 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
2373 OpPC += align(I.bytesToSerialize());
2374 return I;
2375}
2376
2377} // namespace interp
2378} // namespace clang
2379
2380#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3273
ASTImporterLookupTable & LT
StringRef P
static char ID
Definition: Arena.cpp:183
llvm::APSInt APSInt
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
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:2057
bool isVirtual() const
Definition: DeclCXX.h:2112
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:2820
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1260
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
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
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3226
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3076
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2465
unsigned getNumExpressions() const
Definition: Expr.h:2541
A (possibly-)qualified type.
Definition: Type.h:738
Represents a struct/union/class.
Definition: Decl.h:4169
Encodes a location in the source.
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:1607
Wrapper around boolean types.
Definition: Boolean.h:25
static bool inv(Boolean A, Boolean *R)
Definition: Boolean.h:145
static Boolean from(T Value)
Definition: Boolean.h:98
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:55
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:77
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:281
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:50
Frame storing local variables.
Definition: InterpFrame.h:28
Interpreter context.
Definition: InterpState.h:35
A pointer to a memory block, live or dead.
Definition: Pointer.h:80
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:295
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:170
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:291
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:497
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:163
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:443
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:543
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:137
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:154
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:577
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:534
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:387
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:370
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:375
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:206
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:243
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:608
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:127
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:212
bool isBlockPointer() const
Definition: Pointer.h:426
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:306
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:411
void initialize() const
Initializes a field.
Definition: Pointer.cpp:243
unsigned getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:527
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:72
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:130
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1474
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:473
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1902
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:1101
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:603
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2040
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1312
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:337
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2029
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:890
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:500
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:632
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1030
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1966
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1134
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:694
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2355
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1850
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:662
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:967
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1502
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1431
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1396
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:694
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1803
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1647
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:655
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:923
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:568
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:579
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:998
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2319
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:1623
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1217
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1783
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:166
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition: Interp.cpp:296
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:274
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Pops a Pointer from the stack 2) Pushes Pointer.atField(Off) on the stack
Definition: Interp.h:1237
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:439
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:395
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2260
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1077
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1279
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1669
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:363
bool ReturnValue(const T &V, APValue &R)
Convert a value to an APValue.
Definition: Interp.h:43
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1230
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1987
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:868
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1956
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2267
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1845
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:319
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1927
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1889
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:408
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1824
constexpr bool isPtrType(PrimType T)
Definition: PrimType.h:49
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1616
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:99
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:402
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:345
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:217
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1733
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1972
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1165
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:597
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1407
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:984
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2008
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1866
bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:355
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:1182
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
Definition: Interp.h:643
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:735
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:723
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2346
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:266
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2052
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:1119
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:531
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1754
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:949
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2304
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:368
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:1740
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:882
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1840
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1149
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:474
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:336
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:1715
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:1044
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1446
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2071
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1656
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1203
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:419
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1352
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:451
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:672
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1347
bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:1856
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1256
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1266
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:258
bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:682
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:434
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1292
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:672
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1302
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:976
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:741
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:708
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition: Interp.h:2332
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1419
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:194
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
Definition: Interp.h:2213
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:961
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1339
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:348
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:1488
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1697
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:929
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind)
Same here, but only for casts.
Definition: Interp.h:2287
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:22
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:1192
bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1363
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:2297
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1332
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:909
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:754
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:489
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:244
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:455
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:385
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1385
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1084
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1706
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:837
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:1016
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:508
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:660
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1609
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:939
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:1514
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:897
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.h:2228
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:794
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:70
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2170
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:726
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:373
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1222
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1059
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1370
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1090
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:251
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:844
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:1726
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:774
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:490
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1322
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:606
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1529
The JSON file list parser is used to communicate input to InstallAPI.
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_Decrement
Definition: State.h:31
const FunctionProtoType * T
#define bool
Definition: stdbool.h:20
Describes a memory block created by an allocation site.
Definition: Descriptor.h:88
Mapping from primitive types to their representation.
Definition: PrimType.h:73