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.isZero() && FP.getFunction()->getDecl()->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 if (!Pointer::hasSameBase(LHS, RHS)) {
805 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
806 return true;
807 } else {
808 unsigned VL = LHS.getByteOffset();
809 unsigned VR = RHS.getByteOffset();
810
811 // In our Pointer class, a pointer to an array and a pointer to the first
812 // element in the same array are NOT equal. They have the same Base value,
813 // but a different Offset. This is a pretty rare case, so we fix this here
814 // by comparing pointers to the first elements.
815 if (!LHS.isDummy() && LHS.isArrayRoot())
816 VL = LHS.atIndex(0).getByteOffset();
817 if (!RHS.isDummy() && RHS.isArrayRoot())
818 VR = RHS.atIndex(0).getByteOffset();
819
820 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
821 return true;
822 }
823}
824
825template <PrimType Name, class T = typename PrimConv<Name>::T>
826bool EQ(InterpState &S, CodePtr OpPC) {
827 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
829 });
830}
831
832template <PrimType Name, class T = typename PrimConv<Name>::T>
833bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
834 const T &RHS = S.Stk.pop<T>();
835 const T &LHS = S.Stk.pop<T>();
836 const Pointer &P = S.Stk.peek<Pointer>();
837
838 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
839 if (CmpResult == ComparisonCategoryResult::Unordered) {
840 // This should only happen with pointers.
841 const SourceInfo &Loc = S.Current->getSource(OpPC);
842 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
843 << LHS.toDiagnosticString(S.getCtx())
844 << RHS.toDiagnosticString(S.getCtx());
845 return false;
846 }
847
848 assert(CmpInfo);
849 const auto *CmpValueInfo =
850 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
851 assert(CmpValueInfo);
852 assert(CmpValueInfo->hasValidIntValue());
853 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
854}
855
856template <PrimType Name, class T = typename PrimConv<Name>::T>
857bool NE(InterpState &S, CodePtr OpPC) {
858 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
860 });
861}
862
863template <PrimType Name, class T = typename PrimConv<Name>::T>
864bool LT(InterpState &S, CodePtr OpPC) {
865 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
867 });
868}
869
870template <PrimType Name, class T = typename PrimConv<Name>::T>
871bool LE(InterpState &S, CodePtr OpPC) {
872 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
873 return R == ComparisonCategoryResult::Less ||
875 });
876}
877
878template <PrimType Name, class T = typename PrimConv<Name>::T>
879bool GT(InterpState &S, CodePtr OpPC) {
880 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
882 });
883}
884
885template <PrimType Name, class T = typename PrimConv<Name>::T>
886bool GE(InterpState &S, CodePtr OpPC) {
887 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
890 });
891}
892
893//===----------------------------------------------------------------------===//
894// InRange
895//===----------------------------------------------------------------------===//
896
897template <PrimType Name, class T = typename PrimConv<Name>::T>
899 const T RHS = S.Stk.pop<T>();
900 const T LHS = S.Stk.pop<T>();
901 const T Value = S.Stk.pop<T>();
902
903 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
904 return true;
905}
906
907//===----------------------------------------------------------------------===//
908// Dup, Pop, Test
909//===----------------------------------------------------------------------===//
910
911template <PrimType Name, class T = typename PrimConv<Name>::T>
912bool Dup(InterpState &S, CodePtr OpPC) {
913 S.Stk.push<T>(S.Stk.peek<T>());
914 return true;
915}
916
917template <PrimType Name, class T = typename PrimConv<Name>::T>
918bool Pop(InterpState &S, CodePtr OpPC) {
919 S.Stk.pop<T>();
920 return true;
921}
922
923//===----------------------------------------------------------------------===//
924// Const
925//===----------------------------------------------------------------------===//
926
927template <PrimType Name, class T = typename PrimConv<Name>::T>
928bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
929 S.Stk.push<T>(Arg);
930 return true;
931}
932
933//===----------------------------------------------------------------------===//
934// Get/Set Local/Param/Global/This
935//===----------------------------------------------------------------------===//
936
937template <PrimType Name, class T = typename PrimConv<Name>::T>
938bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
939 const Pointer &Ptr = S.Current->getLocalPointer(I);
940 if (!CheckLoad(S, OpPC, Ptr))
941 return false;
942 S.Stk.push<T>(Ptr.deref<T>());
943 return true;
944}
945
946/// 1) Pops the value from the stack.
947/// 2) Writes the value to the local variable with the
948/// given offset.
949template <PrimType Name, class T = typename PrimConv<Name>::T>
950bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
951 S.Current->setLocal<T>(I, S.Stk.pop<T>());
952 return true;
953}
954
955template <PrimType Name, class T = typename PrimConv<Name>::T>
956bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
957 if (S.checkingPotentialConstantExpression()) {
958 return false;
959 }
960 S.Stk.push<T>(S.Current->getParam<T>(I));
961 return true;
962}
963
964template <PrimType Name, class T = typename PrimConv<Name>::T>
965bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
966 S.Current->setParam<T>(I, S.Stk.pop<T>());
967 return true;
968}
969
970/// 1) Peeks a pointer on the stack
971/// 2) Pushes the value of the pointer's field on the stack
972template <PrimType Name, class T = typename PrimConv<Name>::T>
973bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
974 const Pointer &Obj = S.Stk.peek<Pointer>();
975 if (!CheckNull(S, OpPC, Obj, CSK_Field))
976 return false;
977 if (!CheckRange(S, OpPC, Obj, CSK_Field))
978 return false;
979 const Pointer &Field = Obj.atField(I);
980 if (!CheckLoad(S, OpPC, Field))
981 return false;
982 S.Stk.push<T>(Field.deref<T>());
983 return true;
984}
985
986template <PrimType Name, class T = typename PrimConv<Name>::T>
987bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
988 const T &Value = S.Stk.pop<T>();
989 const Pointer &Obj = S.Stk.peek<Pointer>();
990 if (!CheckNull(S, OpPC, Obj, CSK_Field))
991 return false;
992 if (!CheckRange(S, OpPC, Obj, CSK_Field))
993 return false;
994 const Pointer &Field = Obj.atField(I);
995 if (!CheckStore(S, OpPC, Field))
996 return false;
997 Field.initialize();
998 Field.deref<T>() = Value;
999 return true;
1000}
1001
1002/// 1) Pops a pointer from the stack
1003/// 2) Pushes the value of the pointer's field on the stack
1004template <PrimType Name, class T = typename PrimConv<Name>::T>
1005bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1006 const Pointer &Obj = S.Stk.pop<Pointer>();
1007 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1008 return false;
1009 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1010 return false;
1011 const Pointer &Field = Obj.atField(I);
1012 if (!CheckLoad(S, OpPC, Field))
1013 return false;
1014 S.Stk.push<T>(Field.deref<T>());
1015 return true;
1016}
1017
1018template <PrimType Name, class T = typename PrimConv<Name>::T>
1019bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1020 if (S.checkingPotentialConstantExpression())
1021 return false;
1022 const Pointer &This = S.Current->getThis();
1023 if (!CheckThis(S, OpPC, This))
1024 return false;
1025 const Pointer &Field = This.atField(I);
1026 if (!CheckLoad(S, OpPC, Field))
1027 return false;
1028 S.Stk.push<T>(Field.deref<T>());
1029 return true;
1030}
1031
1032template <PrimType Name, class T = typename PrimConv<Name>::T>
1033bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1034 if (S.checkingPotentialConstantExpression())
1035 return false;
1036 const T &Value = S.Stk.pop<T>();
1037 const Pointer &This = S.Current->getThis();
1038 if (!CheckThis(S, OpPC, This))
1039 return false;
1040 const Pointer &Field = This.atField(I);
1041 if (!CheckStore(S, OpPC, Field))
1042 return false;
1043 Field.deref<T>() = Value;
1044 return true;
1045}
1046
1047template <PrimType Name, class T = typename PrimConv<Name>::T>
1048bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1049 const Pointer &Ptr = S.P.getPtrGlobal(I);
1050 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1051 return false;
1052 if (Ptr.isExtern())
1053 return false;
1054
1055 // If a global variable is uninitialized, that means the initializer we've
1056 // compiled for it wasn't a constant expression. Diagnose that.
1057 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1058 return false;
1059
1060 S.Stk.push<T>(Ptr.deref<T>());
1061 return true;
1062}
1063
1064/// Same as GetGlobal, but without the checks.
1065template <PrimType Name, class T = typename PrimConv<Name>::T>
1066bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1067 auto *B = S.P.getGlobal(I);
1068 S.Stk.push<T>(B->deref<T>());
1069 return true;
1070}
1071
1072template <PrimType Name, class T = typename PrimConv<Name>::T>
1073bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1074 // TODO: emit warning.
1075 return false;
1076}
1077
1078template <PrimType Name, class T = typename PrimConv<Name>::T>
1079bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1080 const Pointer &P = S.P.getGlobal(I);
1081 P.deref<T>() = S.Stk.pop<T>();
1082 P.initialize();
1083 return true;
1084}
1085
1086/// 1) Converts the value on top of the stack to an APValue
1087/// 2) Sets that APValue on \Temp
1088/// 3) Initializes global with index \I with that
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1090bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1091 const LifetimeExtendedTemporaryDecl *Temp) {
1092 assert(Temp);
1093 const T Value = S.Stk.peek<T>();
1094 APValue APV = Value.toAPValue();
1095 APValue *Cached = Temp->getOrCreateValue(true);
1096 *Cached = APV;
1097
1098 const Pointer &P = S.P.getGlobal(I);
1099 P.deref<T>() = S.Stk.pop<T>();
1100 P.initialize();
1101
1102 return true;
1103}
1104
1105/// 1) Converts the value on top of the stack to an APValue
1106/// 2) Sets that APValue on \Temp
1107/// 3) Initialized global with index \I with that
1109 const LifetimeExtendedTemporaryDecl *Temp) {
1110 assert(Temp);
1111 const Pointer &P = S.Stk.peek<Pointer>();
1112 APValue *Cached = Temp->getOrCreateValue(true);
1113
1114 if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
1115 *Cached = *APV;
1116 return true;
1117 }
1118
1119 return false;
1120}
1121
1122template <PrimType Name, class T = typename PrimConv<Name>::T>
1123bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1124 if (S.checkingPotentialConstantExpression())
1125 return false;
1126 const Pointer &This = S.Current->getThis();
1127 if (!CheckThis(S, OpPC, This))
1128 return false;
1129 const Pointer &Field = This.atField(I);
1130 Field.deref<T>() = S.Stk.pop<T>();
1131 Field.initialize();
1132 return true;
1133}
1134
1135// FIXME: The Field pointer here is too much IMO and we could instead just
1136// pass an Offset + BitWidth pair.
1137template <PrimType Name, class T = typename PrimConv<Name>::T>
1138bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1139 uint32_t FieldOffset) {
1140 assert(F->isBitField());
1141 if (S.checkingPotentialConstantExpression())
1142 return false;
1143 const Pointer &This = S.Current->getThis();
1144 if (!CheckThis(S, OpPC, This))
1145 return false;
1146 const Pointer &Field = This.atField(FieldOffset);
1147 const auto &Value = S.Stk.pop<T>();
1148 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1149 Field.initialize();
1150 return true;
1151}
1152
1153template <PrimType Name, class T = typename PrimConv<Name>::T>
1154bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1155 if (S.checkingPotentialConstantExpression())
1156 return false;
1157 const Pointer &This = S.Current->getThis();
1158 if (!CheckThis(S, OpPC, This))
1159 return false;
1160 const Pointer &Field = This.atField(I);
1161 Field.deref<T>() = S.Stk.pop<T>();
1162 Field.activate();
1163 Field.initialize();
1164 return true;
1165}
1166
1167/// 1) Pops the value from the stack
1168/// 2) Peeks a pointer from the stack
1169/// 3) Pushes the value to field I of the pointer on the stack
1170template <PrimType Name, class T = typename PrimConv<Name>::T>
1171bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1172 const T &Value = S.Stk.pop<T>();
1173 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1174 Field.deref<T>() = Value;
1175 Field.activate();
1176 Field.initialize();
1177 return true;
1178}
1179
1180template <PrimType Name, class T = typename PrimConv<Name>::T>
1181bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1182 assert(F->isBitField());
1183 const T &Value = S.Stk.pop<T>();
1184 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1185 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1186 Field.activate();
1187 Field.initialize();
1188 return true;
1189}
1190
1191template <PrimType Name, class T = typename PrimConv<Name>::T>
1192bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1193 const T &Value = S.Stk.pop<T>();
1194 const Pointer &Ptr = S.Stk.pop<Pointer>();
1195 const Pointer &Field = Ptr.atField(I);
1196 Field.deref<T>() = Value;
1197 Field.activate();
1198 Field.initialize();
1199 return true;
1200}
1201
1202//===----------------------------------------------------------------------===//
1203// GetPtr Local/Param/Global/Field/This
1204//===----------------------------------------------------------------------===//
1205
1206inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1207 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1208 return true;
1209}
1210
1211inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1212 if (S.checkingPotentialConstantExpression()) {
1213 return false;
1214 }
1215 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1216 return true;
1217}
1218
1219inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1220 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1221 return true;
1222}
1223
1224/// 1) Pops a Pointer from the stack
1225/// 2) Pushes Pointer.atField(Off) on the stack
1226inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1227 const Pointer &Ptr = S.Stk.pop<Pointer>();
1228
1229 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1230 !CheckNull(S, OpPC, Ptr, CSK_Field))
1231 return false;
1232
1233 if (CheckDummy(S, OpPC, Ptr)) {
1234 if (!CheckExtern(S, OpPC, Ptr))
1235 return false;
1236 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1237 return false;
1238 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1239 return false;
1240 }
1241 S.Stk.push<Pointer>(Ptr.atField(Off));
1242 return true;
1243}
1244
1245inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1246 if (S.checkingPotentialConstantExpression())
1247 return false;
1248 const Pointer &This = S.Current->getThis();
1249 if (!CheckThis(S, OpPC, This))
1250 return false;
1251 S.Stk.push<Pointer>(This.atField(Off));
1252 return true;
1253}
1254
1255inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1256 const Pointer &Ptr = S.Stk.pop<Pointer>();
1257 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1258 return false;
1259 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1260 return false;
1261 Pointer Field = Ptr.atField(Off);
1262 Ptr.deactivate();
1263 Field.activate();
1264 S.Stk.push<Pointer>(std::move(Field));
1265 return true;
1266}
1267
1268inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1269 if (S.checkingPotentialConstantExpression())
1270 return false;
1271 const Pointer &This = S.Current->getThis();
1272 if (!CheckThis(S, OpPC, This))
1273 return false;
1274 Pointer Field = This.atField(Off);
1275 This.deactivate();
1276 Field.activate();
1277 S.Stk.push<Pointer>(std::move(Field));
1278 return true;
1279}
1280
1281inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1282 const Pointer &Ptr = S.Stk.pop<Pointer>();
1283 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1284 return false;
1285 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1286 return false;
1287 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1288 return true;
1289}
1290
1291inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1292 const Pointer &Ptr = S.Stk.peek<Pointer>();
1293 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1294 return false;
1295 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1296 return false;
1297 S.Stk.push<Pointer>(Ptr.atField(Off));
1298 return true;
1299}
1300
1301inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1302 const Pointer &Ptr = S.Stk.pop<Pointer>();
1303 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1304 return false;
1305 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1306 return false;
1307 S.Stk.push<Pointer>(Ptr.atField(Off));
1308 return true;
1309}
1310
1311inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1312 if (S.checkingPotentialConstantExpression())
1313 return false;
1314 const Pointer &This = S.Current->getThis();
1315 if (!CheckThis(S, OpPC, This))
1316 return false;
1317 S.Stk.push<Pointer>(This.atField(Off));
1318 return true;
1319}
1320
1321inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1322 const Pointer &Ptr = S.Stk.pop<Pointer>();
1323 if (Ptr.canBeInitialized())
1324 Ptr.initialize();
1325 return true;
1326}
1327
1328inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1329 const Pointer &Ptr = S.Stk.peek<Pointer>();
1330
1331 if (Ptr.canBeInitialized())
1332 Ptr.initialize();
1333 return true;
1334}
1335
1336inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1337 const Pointer &Ptr) {
1338 Pointer Base = Ptr;
1339 while (Base.isBaseClass())
1340 Base = Base.getBase();
1341
1342 auto *Field = Base.getRecord()->getVirtualBase(Decl);
1343 S.Stk.push<Pointer>(Base.atField(Field->Offset));
1344 return true;
1345}
1346
1347inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1348 const Pointer &Ptr = S.Stk.pop<Pointer>();
1349 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1350 return false;
1351 return VirtBaseHelper(S, OpPC, D, Ptr);
1352}
1353
1355 const RecordDecl *D) {
1356 if (S.checkingPotentialConstantExpression())
1357 return false;
1358 const Pointer &This = S.Current->getThis();
1359 if (!CheckThis(S, OpPC, This))
1360 return false;
1361 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1362}
1363
1364//===----------------------------------------------------------------------===//
1365// Load, Store, Init
1366//===----------------------------------------------------------------------===//
1367
1368template <PrimType Name, class T = typename PrimConv<Name>::T>
1369bool Load(InterpState &S, CodePtr OpPC) {
1370 const Pointer &Ptr = S.Stk.peek<Pointer>();
1371 if (!CheckLoad(S, OpPC, Ptr))
1372 return false;
1373 S.Stk.push<T>(Ptr.deref<T>());
1374 return true;
1375}
1376
1377template <PrimType Name, class T = typename PrimConv<Name>::T>
1379 const Pointer &Ptr = S.Stk.pop<Pointer>();
1380 if (!CheckLoad(S, OpPC, Ptr))
1381 return false;
1382 S.Stk.push<T>(Ptr.deref<T>());
1383 return true;
1384}
1385
1386template <PrimType Name, class T = typename PrimConv<Name>::T>
1387bool Store(InterpState &S, CodePtr OpPC) {
1388 const T &Value = S.Stk.pop<T>();
1389 const Pointer &Ptr = S.Stk.peek<Pointer>();
1390 if (!CheckStore(S, OpPC, Ptr))
1391 return false;
1392 if (Ptr.canBeInitialized())
1393 Ptr.initialize();
1394 Ptr.deref<T>() = Value;
1395 return true;
1396}
1397
1398template <PrimType Name, class T = typename PrimConv<Name>::T>
1400 const T &Value = S.Stk.pop<T>();
1401 const Pointer &Ptr = S.Stk.pop<Pointer>();
1402 if (!CheckStore(S, OpPC, Ptr))
1403 return false;
1404 if (Ptr.canBeInitialized())
1405 Ptr.initialize();
1406 Ptr.deref<T>() = Value;
1407 return true;
1408}
1409
1410template <PrimType Name, class T = typename PrimConv<Name>::T>
1412 const T &Value = S.Stk.pop<T>();
1413 const Pointer &Ptr = S.Stk.peek<Pointer>();
1414 if (!CheckStore(S, OpPC, Ptr))
1415 return false;
1416 if (Ptr.canBeInitialized())
1417 Ptr.initialize();
1418 if (const auto *FD = Ptr.getField())
1419 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1420 else
1421 Ptr.deref<T>() = Value;
1422 return true;
1423}
1424
1425template <PrimType Name, class T = typename PrimConv<Name>::T>
1427 const T &Value = S.Stk.pop<T>();
1428 const Pointer &Ptr = S.Stk.pop<Pointer>();
1429 if (!CheckStore(S, OpPC, Ptr))
1430 return false;
1431 if (Ptr.canBeInitialized())
1432 Ptr.initialize();
1433 if (const auto *FD = Ptr.getField())
1434 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1435 else
1436 Ptr.deref<T>() = Value;
1437 return true;
1438}
1439
1440template <PrimType Name, class T = typename PrimConv<Name>::T>
1441bool Init(InterpState &S, CodePtr OpPC) {
1442 const T &Value = S.Stk.pop<T>();
1443 const Pointer &Ptr = S.Stk.peek<Pointer>();
1444 if (!CheckInit(S, OpPC, Ptr)) {
1445 assert(false);
1446 return false;
1447 }
1448 Ptr.initialize();
1449 new (&Ptr.deref<T>()) T(Value);
1450 return true;
1451}
1452
1453template <PrimType Name, class T = typename PrimConv<Name>::T>
1455 const T &Value = S.Stk.pop<T>();
1456 const Pointer &Ptr = S.Stk.pop<Pointer>();
1457 if (!CheckInit(S, OpPC, Ptr))
1458 return false;
1459 Ptr.initialize();
1460 new (&Ptr.deref<T>()) T(Value);
1461 return true;
1462}
1463
1464/// 1) Pops the value from the stack
1465/// 2) Peeks a pointer and gets its index \Idx
1466/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1467template <PrimType Name, class T = typename PrimConv<Name>::T>
1468bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1469 const T &Value = S.Stk.pop<T>();
1470 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1471 if (Ptr.isUnknownSizeArray())
1472 return false;
1473 if (!CheckInit(S, OpPC, Ptr))
1474 return false;
1475 Ptr.initialize();
1476 new (&Ptr.deref<T>()) T(Value);
1477 return true;
1478}
1479
1480/// The same as InitElem, but pops the pointer as well.
1481template <PrimType Name, class T = typename PrimConv<Name>::T>
1482bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1483 const T &Value = S.Stk.pop<T>();
1484 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1485 if (Ptr.isUnknownSizeArray())
1486 return false;
1487 if (!CheckInit(S, OpPC, Ptr))
1488 return false;
1489 Ptr.initialize();
1490 new (&Ptr.deref<T>()) T(Value);
1491 return true;
1492}
1493
1494inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1495 const Pointer &Src = S.Stk.pop<Pointer>();
1496 Pointer &Dest = S.Stk.peek<Pointer>();
1497
1498 if (!CheckLoad(S, OpPC, Src))
1499 return false;
1500
1501 return DoMemcpy(S, OpPC, Src, Dest);
1502}
1503
1504//===----------------------------------------------------------------------===//
1505// AddOffset, SubOffset
1506//===----------------------------------------------------------------------===//
1507
1508template <class T, ArithOp Op>
1509bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1510 const Pointer &Ptr) {
1511 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1512 return false;
1513
1514 // A zero offset does not change the pointer.
1515 if (Offset.isZero()) {
1516 S.Stk.push<Pointer>(Ptr);
1517 return true;
1518 }
1519
1520 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1521 return false;
1522
1523 // Arrays of unknown bounds cannot have pointers into them.
1524 if (!CheckArray(S, OpPC, Ptr))
1525 return false;
1526
1527 // Get a version of the index comparable to the type.
1528 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1529 // Compute the largest index into the array.
1530 T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
1531
1532 bool Invalid = false;
1533 // Helper to report an invalid offset, computed as APSInt.
1534 auto DiagInvalidOffset = [&]() -> void {
1535 const unsigned Bits = Offset.bitWidth();
1536 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1537 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1538 APSInt NewIndex =
1539 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1540 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1541 << NewIndex
1542 << /*array*/ static_cast<int>(!Ptr.inArray())
1543 << static_cast<unsigned>(MaxIndex);
1544 Invalid = true;
1545 };
1546
1547 T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
1548 if constexpr (Op == ArithOp::Add) {
1549 // If the new offset would be negative, bail out.
1550 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1551 DiagInvalidOffset();
1552
1553 // If the new offset would be out of bounds, bail out.
1554 if (Offset.isPositive() && Offset > MaxOffset)
1555 DiagInvalidOffset();
1556 } else {
1557 // If the new offset would be negative, bail out.
1558 if (Offset.isPositive() && Index < Offset)
1559 DiagInvalidOffset();
1560
1561 // If the new offset would be out of bounds, bail out.
1562 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1563 DiagInvalidOffset();
1564 }
1565
1566 if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
1567 return false;
1568
1569 // Offset is valid - compute it on unsigned.
1570 int64_t WideIndex = static_cast<int64_t>(Index);
1571 int64_t WideOffset = static_cast<int64_t>(Offset);
1572 int64_t Result;
1573 if constexpr (Op == ArithOp::Add)
1574 Result = WideIndex + WideOffset;
1575 else
1576 Result = WideIndex - WideOffset;
1577
1578 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1579 return true;
1580}
1581
1582template <PrimType Name, class T = typename PrimConv<Name>::T>
1584 const T &Offset = S.Stk.pop<T>();
1585 const Pointer &Ptr = S.Stk.pop<Pointer>();
1586 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1587}
1588
1589template <PrimType Name, class T = typename PrimConv<Name>::T>
1591 const T &Offset = S.Stk.pop<T>();
1592 const Pointer &Ptr = S.Stk.pop<Pointer>();
1593 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1594}
1595
1596template <ArithOp Op>
1597static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1598 const Pointer &Ptr) {
1599 if (Ptr.isDummy())
1600 return false;
1601
1602 using OneT = Integral<8, false>;
1603
1604 const Pointer &P = Ptr.deref<Pointer>();
1605 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1606 return false;
1607
1608 // Get the current value on the stack.
1609 S.Stk.push<Pointer>(P);
1610
1611 // Now the current Ptr again and a constant 1.
1612 OneT One = OneT::from(1);
1613 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1614 return false;
1615
1616 // Store the new value.
1617 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1618 return true;
1619}
1620
1621static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1622 const Pointer &Ptr = S.Stk.pop<Pointer>();
1623
1624 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1625 return false;
1626
1627 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1628}
1629
1630static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1631 const Pointer &Ptr = S.Stk.pop<Pointer>();
1632
1633 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1634 return false;
1635
1636 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1637}
1638
1639/// 1) Pops a Pointer from the stack.
1640/// 2) Pops another Pointer from the stack.
1641/// 3) Pushes the different of the indices of the two pointers on the stack.
1642template <PrimType Name, class T = typename PrimConv<Name>::T>
1643inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1644 const Pointer &LHS = S.Stk.pop<Pointer>();
1645 const Pointer &RHS = S.Stk.pop<Pointer>();
1646
1647 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1648 // TODO: Diagnose.
1649 return false;
1650 }
1651
1652 if (LHS.isZero() && RHS.isZero()) {
1653 S.Stk.push<T>();
1654 return true;
1655 }
1656
1657 T A = T::from(LHS.getIndex());
1658 T B = T::from(RHS.getIndex());
1659 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1660}
1661
1662//===----------------------------------------------------------------------===//
1663// Destroy
1664//===----------------------------------------------------------------------===//
1665
1666inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1667 S.Current->destroy(I);
1668 return true;
1669}
1670
1671//===----------------------------------------------------------------------===//
1672// Cast, CastFP
1673//===----------------------------------------------------------------------===//
1674
1675template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1676 using T = typename PrimConv<TIn>::T;
1677 using U = typename PrimConv<TOut>::T;
1678 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1679 return true;
1680}
1681
1682/// 1) Pops a Floating from the stack.
1683/// 2) Pushes a new floating on the stack that uses the given semantics.
1684inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1685 llvm::RoundingMode RM) {
1686 Floating F = S.Stk.pop<Floating>();
1687 Floating Result = F.toSemantics(Sem, RM);
1688 S.Stk.push<Floating>(Result);
1689 return true;
1690}
1691
1692/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1693/// to know what bitwidth the result should be.
1694template <PrimType Name, class T = typename PrimConv<Name>::T>
1695bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1696 S.Stk.push<IntegralAP<false>>(
1697 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1698 return true;
1699}
1700
1701template <PrimType Name, class T = typename PrimConv<Name>::T>
1702bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1703 S.Stk.push<IntegralAP<true>>(
1704 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1705 return true;
1706}
1707
1708template <PrimType Name, class T = typename PrimConv<Name>::T>
1710 const llvm::fltSemantics *Sem,
1711 llvm::RoundingMode RM) {
1712 const T &From = S.Stk.pop<T>();
1713 APSInt FromAP = From.toAPSInt();
1715
1716 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1717 S.Stk.push<Floating>(Result);
1718
1719 return CheckFloatResult(S, OpPC, Result, Status);
1720}
1721
1722template <PrimType Name, class T = typename PrimConv<Name>::T>
1724 const Floating &F = S.Stk.pop<Floating>();
1725
1726 if constexpr (std::is_same_v<T, Boolean>) {
1727 S.Stk.push<T>(T(F.isNonZero()));
1728 return true;
1729 } else {
1730 APSInt Result(std::max(8u, T::bitWidth()),
1731 /*IsUnsigned=*/!T::isSigned());
1732 auto Status = F.convertToInteger(Result);
1733
1734 // Float-to-Integral overflow check.
1735 if ((Status & APFloat::opStatus::opInvalidOp)) {
1736 const Expr *E = S.Current->getExpr(OpPC);
1737 QualType Type = E->getType();
1738
1739 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1740 if (S.noteUndefinedBehavior()) {
1741 S.Stk.push<T>(T(Result));
1742 return true;
1743 }
1744 return false;
1745 }
1746
1747 S.Stk.push<T>(T(Result));
1748 return CheckFloatResult(S, OpPC, F, Status);
1749 }
1750}
1751
1752static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1753 uint32_t BitWidth) {
1754 const Floating &F = S.Stk.pop<Floating>();
1755
1756 APSInt Result(BitWidth, /*IsUnsigned=*/true);
1757 auto Status = F.convertToInteger(Result);
1758
1759 // Float-to-Integral overflow check.
1760 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1761 const Expr *E = S.Current->getExpr(OpPC);
1762 QualType Type = E->getType();
1763
1764 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1765 return S.noteUndefinedBehavior();
1766 }
1767
1769 return CheckFloatResult(S, OpPC, F, Status);
1770}
1771
1772static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1773 uint32_t BitWidth) {
1774 const Floating &F = S.Stk.pop<Floating>();
1775
1776 APSInt Result(BitWidth, /*IsUnsigned=*/false);
1777 auto Status = F.convertToInteger(Result);
1778
1779 // Float-to-Integral overflow check.
1780 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1781 const Expr *E = S.Current->getExpr(OpPC);
1782 QualType Type = E->getType();
1783
1784 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1785 return S.noteUndefinedBehavior();
1786 }
1787
1789 return CheckFloatResult(S, OpPC, F, Status);
1790}
1791
1792template <PrimType Name, class T = typename PrimConv<Name>::T>
1794 const Pointer &Ptr = S.Stk.pop<Pointer>();
1795
1796 const SourceInfo &E = S.Current->getSource(OpPC);
1797 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1798 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1799
1800 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1801 return true;
1802}
1803
1804//===----------------------------------------------------------------------===//
1805// Zero, Nullptr
1806//===----------------------------------------------------------------------===//
1807
1808template <PrimType Name, class T = typename PrimConv<Name>::T>
1809bool Zero(InterpState &S, CodePtr OpPC) {
1810 S.Stk.push<T>(T::zero());
1811 return true;
1812}
1813
1814static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1815 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
1816 return true;
1817}
1818
1819static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1820 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
1821 return true;
1822}
1823
1824template <PrimType Name, class T = typename PrimConv<Name>::T>
1825inline bool Null(InterpState &S, CodePtr OpPC) {
1826 S.Stk.push<T>();
1827 return true;
1828}
1829
1830//===----------------------------------------------------------------------===//
1831// This, ImplicitThis
1832//===----------------------------------------------------------------------===//
1833
1834inline bool This(InterpState &S, CodePtr OpPC) {
1835 // Cannot read 'this' in this mode.
1836 if (S.checkingPotentialConstantExpression()) {
1837 return false;
1838 }
1839
1840 const Pointer &This = S.Current->getThis();
1841 if (!CheckThis(S, OpPC, This))
1842 return false;
1843
1844 S.Stk.push<Pointer>(This);
1845 return true;
1846}
1847
1848inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1849 assert(S.Current->getFunction()->hasRVO());
1850 if (S.checkingPotentialConstantExpression())
1851 return false;
1852 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1853 return true;
1854}
1855
1856//===----------------------------------------------------------------------===//
1857// Shr, Shl
1858//===----------------------------------------------------------------------===//
1859
1860template <PrimType NameL, PrimType NameR>
1861inline bool Shr(InterpState &S, CodePtr OpPC) {
1862 using LT = typename PrimConv<NameL>::T;
1863 using RT = typename PrimConv<NameR>::T;
1864 const auto &RHS = S.Stk.pop<RT>();
1865 const auto &LHS = S.Stk.pop<LT>();
1866 const unsigned Bits = LHS.bitWidth();
1867
1868 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1869 return false;
1870
1871 // Limit the shift amount to Bits - 1. If this happened,
1872 // it has already been diagnosed by CheckShift() above,
1873 // but we still need to handle it.
1874 typename LT::AsUnsigned R;
1875 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1876 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1877 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1878 else
1879 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1880 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1881 S.Stk.push<LT>(LT::from(R));
1882 return true;
1883}
1884
1885template <PrimType NameL, PrimType NameR>
1886inline bool Shl(InterpState &S, CodePtr OpPC) {
1887 using LT = typename PrimConv<NameL>::T;
1888 using RT = typename PrimConv<NameR>::T;
1889 const auto &RHS = S.Stk.pop<RT>();
1890 const auto &LHS = S.Stk.pop<LT>();
1891 const unsigned Bits = LHS.bitWidth();
1892
1893 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1894 return false;
1895
1896 // Limit the shift amount to Bits - 1. If this happened,
1897 // it has already been diagnosed by CheckShift() above,
1898 // but we still need to handle it.
1899 typename LT::AsUnsigned R;
1900 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1901 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1902 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1903 else
1904 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1905 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1906
1907 S.Stk.push<LT>(LT::from(R));
1908 return true;
1909}
1910
1911//===----------------------------------------------------------------------===//
1912// NoRet
1913//===----------------------------------------------------------------------===//
1914
1915inline bool NoRet(InterpState &S, CodePtr OpPC) {
1916 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1917 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1918 return false;
1919}
1920
1921//===----------------------------------------------------------------------===//
1922// NarrowPtr, ExpandPtr
1923//===----------------------------------------------------------------------===//
1924
1925inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1926 const Pointer &Ptr = S.Stk.pop<Pointer>();
1927 S.Stk.push<Pointer>(Ptr.narrow());
1928 return true;
1929}
1930
1931inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1932 const Pointer &Ptr = S.Stk.pop<Pointer>();
1933 S.Stk.push<Pointer>(Ptr.expand());
1934 return true;
1935}
1936
1937// 1) Pops an integral value from the stack
1938// 2) Peeks a pointer
1939// 3) Pushes a new pointer that's a narrowed array
1940// element of the peeked pointer with the value
1941// from 1) added as offset.
1942//
1943// This leaves the original pointer on the stack and pushes a new one
1944// with the offset applied and narrowed.
1945template <PrimType Name, class T = typename PrimConv<Name>::T>
1946inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1947 const T &Offset = S.Stk.pop<T>();
1948 const Pointer &Ptr = S.Stk.peek<Pointer>();
1949
1950 if (!Ptr.isZero()) {
1951 if (!CheckArray(S, OpPC, Ptr))
1952 return false;
1953
1954 if (Ptr.isDummy()) {
1955 S.Stk.push<Pointer>(Ptr);
1956 return true;
1957 }
1958 }
1959
1960 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1961 return false;
1962
1963 return NarrowPtr(S, OpPC);
1964}
1965
1966template <PrimType Name, class T = typename PrimConv<Name>::T>
1967inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1968 const T &Offset = S.Stk.pop<T>();
1969 const Pointer &Ptr = S.Stk.pop<Pointer>();
1970
1971 if (!Ptr.isZero()) {
1972 if (!CheckArray(S, OpPC, Ptr))
1973 return false;
1974
1975 if (Ptr.isDummy()) {
1976 S.Stk.push<Pointer>(Ptr);
1977 return true;
1978 }
1979 }
1980
1981 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1982 return false;
1983
1984 return NarrowPtr(S, OpPC);
1985}
1986
1987template <PrimType Name, class T = typename PrimConv<Name>::T>
1988inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
1989 const Pointer &Ptr = S.Stk.peek<Pointer>();
1990
1991 if (!CheckLoad(S, OpPC, Ptr))
1992 return false;
1993
1994 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
1995 return true;
1996}
1997
1998template <PrimType Name, class T = typename PrimConv<Name>::T>
1999inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2000 const Pointer &Ptr = S.Stk.pop<Pointer>();
2001
2002 if (!CheckLoad(S, OpPC, Ptr))
2003 return false;
2004
2005 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2006 return true;
2007}
2008
2009/// Just takes a pointer and checks if it's an incomplete
2010/// array type.
2011inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2012 const Pointer &Ptr = S.Stk.pop<Pointer>();
2013
2014 if (Ptr.isZero() || Ptr.isDummy()) {
2015 S.Stk.push<Pointer>(Ptr);
2016 return true;
2017 }
2018
2019 if (!Ptr.isUnknownSizeArray()) {
2020 S.Stk.push<Pointer>(Ptr.atIndex(0));
2021 return true;
2022 }
2023
2024 const SourceInfo &E = S.Current->getSource(OpPC);
2025 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2026
2027 return false;
2028}
2029
2030inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2031 uint32_t VarArgSize) {
2032 if (Func->hasThisPointer()) {
2033 size_t ArgSize = Func->getArgSize() + VarArgSize;
2034 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2035 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2036
2037 // If the current function is a lambda static invoker and
2038 // the function we're about to call is a lambda call operator,
2039 // skip the CheckInvoke, since the ThisPtr is a null pointer
2040 // anyway.
2041 if (!(S.Current->getFunction() &&
2042 S.Current->getFunction()->isLambdaStaticInvoker() &&
2043 Func->isLambdaCallOperator())) {
2044 if (!CheckInvoke(S, OpPC, ThisPtr))
2045 return false;
2046 }
2047
2048 if (S.checkingPotentialConstantExpression())
2049 return false;
2050 }
2051
2052 if (!CheckCallable(S, OpPC, Func))
2053 return false;
2054
2055 if (!CheckCallDepth(S, OpPC))
2056 return false;
2057
2058 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2059 InterpFrame *FrameBefore = S.Current;
2060 S.Current = NewFrame.get();
2061
2062 APValue CallResult;
2063 // Note that we cannot assert(CallResult.hasValue()) here since
2064 // Ret() above only sets the APValue if the curent frame doesn't
2065 // have a caller set.
2066 if (Interpret(S, CallResult)) {
2067 NewFrame.release(); // Frame was delete'd already.
2068 assert(S.Current == FrameBefore);
2069 return true;
2070 }
2071
2072 // Interpreting the function failed somehow. Reset to
2073 // previous state.
2074 S.Current = FrameBefore;
2075 return false;
2076
2077 return false;
2078}
2079
2080inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2081 uint32_t VarArgSize) {
2082 if (Func->hasThisPointer()) {
2083 size_t ArgSize = Func->getArgSize() + VarArgSize;
2084 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2085
2086 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2087
2088 // If the current function is a lambda static invoker and
2089 // the function we're about to call is a lambda call operator,
2090 // skip the CheckInvoke, since the ThisPtr is a null pointer
2091 // anyway.
2092 if (!(S.Current->getFunction() &&
2093 S.Current->getFunction()->isLambdaStaticInvoker() &&
2094 Func->isLambdaCallOperator())) {
2095 if (!CheckInvoke(S, OpPC, ThisPtr))
2096 return false;
2097 }
2098
2099 if (S.checkingPotentialConstantExpression())
2100 return false;
2101 }
2102
2103 if (!CheckCallable(S, OpPC, Func))
2104 return false;
2105
2106 if (!CheckCallDepth(S, OpPC))
2107 return false;
2108
2109 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2110 InterpFrame *FrameBefore = S.Current;
2111 S.Current = NewFrame.get();
2112
2113 APValue CallResult;
2114 // Note that we cannot assert(CallResult.hasValue()) here since
2115 // Ret() above only sets the APValue if the curent frame doesn't
2116 // have a caller set.
2117 if (Interpret(S, CallResult)) {
2118 NewFrame.release(); // Frame was delete'd already.
2119 assert(S.Current == FrameBefore);
2120 return true;
2121 }
2122
2123 // Interpreting the function failed somehow. Reset to
2124 // previous state.
2125 S.Current = FrameBefore;
2126 return false;
2127}
2128
2129inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2130 uint32_t VarArgSize) {
2131 assert(Func->hasThisPointer());
2132 assert(Func->isVirtual());
2133 size_t ArgSize = Func->getArgSize() + VarArgSize;
2134 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2135 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2136
2137 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2138 const CXXRecordDecl *DynamicDecl;
2139 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2140 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2141 else
2142 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2143 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2144 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2145 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2146 DynamicDecl, StaticDecl, InitialFunction);
2147
2148 if (Overrider != InitialFunction) {
2149 // DR1872: An instantiated virtual constexpr function can't be called in a
2150 // constant expression (prior to C++20). We can still constant-fold such a
2151 // call.
2152 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2153 const Expr *E = S.Current->getExpr(OpPC);
2154 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2155 }
2156
2157 Func = S.getContext().getOrCreateFunction(Overrider);
2158
2159 const CXXRecordDecl *ThisFieldDecl =
2160 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2161 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2162 // If the function we call is further DOWN the hierarchy than the
2163 // FieldDesc of our pointer, just get the DeclDesc instead, which
2164 // is the furthest we might go up in the hierarchy.
2165 ThisPtr = ThisPtr.getDeclPtr();
2166 }
2167 }
2168
2169 return Call(S, OpPC, Func, VarArgSize);
2170}
2171
2172inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2173 const CallExpr *CE) {
2174 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2175
2176 InterpFrame *FrameBefore = S.Current;
2177 S.Current = NewFrame.get();
2178
2179 if (InterpretBuiltin(S, PC, Func, CE)) {
2180 NewFrame.release();
2181 return true;
2182 }
2183 S.Current = FrameBefore;
2184 return false;
2185}
2186
2187inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2188 const CallExpr *CE) {
2189 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2190
2191 const Function *F = FuncPtr.getFunction();
2192 if (!F) {
2193 const Expr *E = S.Current->getExpr(OpPC);
2194 S.FFDiag(E, diag::note_constexpr_null_callee)
2195 << const_cast<Expr *>(E) << E->getSourceRange();
2196 return false;
2197 }
2198 assert(F);
2199
2200 // Check argument nullability state.
2201 if (F->hasNonNullAttr()) {
2202 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2203 return false;
2204 }
2205
2206 assert(ArgSize >= F->getWrittenArgSize());
2207 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2208
2209 if (F->isVirtual())
2210 return CallVirt(S, OpPC, F, VarArgSize);
2211
2212 return Call(S, OpPC, F, VarArgSize);
2213}
2214
2215inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2216 assert(Func);
2217 S.Stk.push<FunctionPointer>(Func);
2218 return true;
2219}
2220
2221/// Just emit a diagnostic. The expression that caused emission of this
2222/// op is not valid in a constant context.
2223inline bool Invalid(InterpState &S, CodePtr OpPC) {
2224 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2225 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2226 << S.Current->getRange(OpPC);
2227 return false;
2228}
2229
2230/// Do nothing and just abort execution.
2231inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2232
2233/// Same here, but only for casts.
2234inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2235 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2236
2237 // FIXME: Support diagnosing other invalid cast kinds.
2238 if (Kind == CastKind::Reinterpret)
2239 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
2240 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2241 return false;
2242}
2243
2245 const DeclRefExpr *DR) {
2246 assert(DR);
2247 return CheckDeclRef(S, OpPC, DR);
2248}
2249
2250template <PrimType Name, class T = typename PrimConv<Name>::T>
2251inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2252 llvm::SmallVector<int64_t> ArrayIndices;
2253 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2254 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2255
2256 int64_t Result;
2257 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2258 return false;
2259
2260 S.Stk.push<T>(T::from(Result));
2261
2262 return true;
2263}
2264
2265template <PrimType Name, class T = typename PrimConv<Name>::T>
2266inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2267 const T &Arg = S.Stk.peek<T>();
2268 if (!Arg.isZero())
2269 return true;
2270
2271 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2272 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2273
2274 return false;
2275}
2276
2277//===----------------------------------------------------------------------===//
2278// Read opcode arguments
2279//===----------------------------------------------------------------------===//
2280
2281template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2282 if constexpr (std::is_pointer<T>::value) {
2283 uint32_t ID = OpPC.read<uint32_t>();
2284 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2285 } else {
2286 return OpPC.read<T>();
2287 }
2288}
2289
2290template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2292 OpPC += align(F.bytesToSerialize());
2293 return F;
2294}
2295
2296template <>
2297inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2298 CodePtr &OpPC) {
2299 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
2300 OpPC += align(I.bytesToSerialize());
2301 return I;
2302}
2303
2304template <>
2305inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2306 CodePtr &OpPC) {
2307 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
2308 OpPC += align(I.bytesToSerialize());
2309 return I;
2310}
2311
2312} // namespace interp
2313} // namespace clang
2314
2315#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3259
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:2053
bool isVirtual() const
Definition: DeclCXX.h:2108
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:2819
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:3222
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:2464
unsigned getNumExpressions() const
Definition: Expr.h:2540
A (possibly-)qualified type.
Definition: Type.h:737
Represents a struct/union/class.
Definition: Decl.h:4133
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:1606
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:65
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:213
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:130
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:209
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:347
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:123
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:318
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:377
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:104
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:116
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:401
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:372
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:287
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:280
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:283
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:140
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:196
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:427
unsigned getIntegerRepresentation() const
Definition: Pointer.h:96
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:167
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:232
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:302
void initialize() const
Initializes a field.
Definition: Pointer.cpp:170
unsigned getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:367
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:1454
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:473
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1861
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:1090
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:1999
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1301
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:1988
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:879
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:443
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:1019
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1925
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1123
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:664
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2290
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1819
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:956
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1482
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1411
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1378
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:1772
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1621
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:625
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:912
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:511
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:522
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:987
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2266
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:1597
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1206
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1752
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:250
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:1226
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:344
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2215
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1066
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1268
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1643
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:315
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:1219
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1946
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:857
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1915
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1814
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:319
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1886
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1848
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:357
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1793
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1590
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:95
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:297
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:217
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1702
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1931
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1154
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:540
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1387
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:973
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1967
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1834
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:1171
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:2281
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:220
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2011
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:1108
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:531
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1723
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:938
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2251
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:1709
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:871
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1809
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1138
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:417
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:288
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:1684
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:1033
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1426
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2030
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1630
bool Null(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1825
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1192
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:1336
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:394
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:672
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1245
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1255
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:212
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:377
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1281
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:642
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1291
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:965
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 StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1399
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:151
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
Definition: Interp.h:2172
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:950
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1328
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:1468
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1666
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:918
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind)
Same here, but only for casts.
Definition: Interp.h:2234
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:1181
bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1347
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:2244
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1321
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:898
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:201
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:1369
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1073
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1675
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:826
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:1005
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:451
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:630
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1583
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:928
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:1494
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:886
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.h:2187
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:794
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:66
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2129
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:325
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1211
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1048
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1354
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1079
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:251
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:833
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:1695
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:433
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1311
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:549
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1509
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
#define bool
Definition: stdbool.h:20
Mapping from primitive types to their representation.
Definition: PrimType.h:69