clang 17.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 "InterpFrame.h"
20#include "InterpStack.h"
21#include "InterpState.h"
22#include "Opcode.h"
23#include "PrimType.h"
24#include "Program.h"
25#include "State.h"
29#include "clang/AST/Expr.h"
30#include "llvm/ADT/APFloat.h"
31#include "llvm/ADT/APSInt.h"
32#include "llvm/Support/Endian.h"
33#include <limits>
34#include <type_traits>
35
36namespace clang {
37namespace interp {
38
39using APInt = llvm::APInt;
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/// Checks if a pointer is null.
58bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60
61/// Checks if a pointer is in range.
62bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
63 AccessKinds AK);
64
65/// Checks if a field from which a pointer is going to be derived is valid.
66bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68
69/// Checks if a pointer points to const storage.
70bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
71
72/// Checks if a pointer points to a mutable field.
73bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
74
75/// Checks if a value can be loaded from a block.
76bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
77
78/// Checks if a value can be stored in a block.
79bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
80
81/// Checks if a method can be invoked on an object.
82bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
83
84/// Checks if a value can be initialized.
85bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
86
87/// Checks if a method can be called.
88bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
89
90/// Checks the 'this' pointer.
91bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
92
93/// Checks if a method is pure virtual.
94bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
95
96/// Checks that all fields are initialized after a constructor call.
97bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
98
99/// Checks if the shift operation is legal.
100template <typename RT>
101bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
102 if (RHS.isNegative()) {
103 const SourceInfo &Loc = S.Current->getSource(OpPC);
104 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
105 return false;
106 }
107
108 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
109 // the shifted type.
110 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
111 const Expr *E = S.Current->getExpr(OpPC);
112 const APSInt Val = RHS.toAPSInt();
113 QualType Ty = E->getType();
114 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
115 return false;
116 }
117 return true;
118}
119
120/// Checks if Div/Rem operation on LHS and RHS is valid.
121template <typename T>
122bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
123 if (RHS.isZero()) {
124 const SourceInfo &Loc = S.Current->getSource(OpPC);
125 S.FFDiag(Loc, diag::note_expr_divide_by_zero);
126 return false;
127 }
128
129 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
130 APSInt LHSInt = LHS.toAPSInt();
131 SmallString<32> Trunc;
132 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
133 const SourceInfo &Loc = S.Current->getSource(OpPC);
134 const Expr *E = S.Current->getExpr(OpPC);
135 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
136 return false;
137 }
138 return true;
139}
140
141/// Checks if the result is a floating-point operation is valid
142/// in the current context.
143bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
144
145/// Interpreter entry point.
146bool Interpret(InterpState &S, APValue &Result);
147
148/// Interpret a builtin function.
149bool InterpretBuiltin(InterpState &S, CodePtr &PC, unsigned BuiltinID);
150
151enum class ArithOp { Add, Sub };
152
153//===----------------------------------------------------------------------===//
154// Returning values
155//===----------------------------------------------------------------------===//
156
157template <PrimType Name, bool Builtin = false,
158 class T = typename PrimConv<Name>::T>
160 S.CallStackDepth--;
161 const T &Ret = S.Stk.pop<T>();
162
163 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
164 if (Builtin || !S.checkingPotentialConstantExpression())
165 S.Current->popArgs();
166
167 if (InterpFrame *Caller = S.Current->Caller) {
168 PC = S.Current->getRetPC();
169 delete S.Current;
170 S.Current = Caller;
171 S.Stk.push<T>(Ret);
172 } else {
173 delete S.Current;
174 S.Current = nullptr;
175 if (!ReturnValue<T>(Ret, Result))
176 return false;
177 }
178 return true;
179}
180
181template <bool Builtin = false>
182inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
183 S.CallStackDepth--;
184
185 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
186 if (Builtin || !S.checkingPotentialConstantExpression())
187 S.Current->popArgs();
188
189 if (InterpFrame *Caller = S.Current->Caller) {
190 PC = S.Current->getRetPC();
191 delete S.Current;
192 S.Current = Caller;
193 } else {
194 delete S.Current;
195 S.Current = nullptr;
196 }
197 return true;
198}
199
200//===----------------------------------------------------------------------===//
201// Add, Sub, Mul
202//===----------------------------------------------------------------------===//
203
204template <typename T, bool (*OpFW)(T, T, unsigned, T *),
205 template <typename U> class OpAP>
206bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
207 const T &RHS) {
208 // Fast path - add the numbers with fixed width.
209 T Result;
210 if (!OpFW(LHS, RHS, Bits, &Result)) {
211 S.Stk.push<T>(Result);
212 return true;
213 }
214
215 // If for some reason evaluation continues, use the truncated results.
216 S.Stk.push<T>(Result);
217
218 // Slow path - compute the result using another bit of precision.
219 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
220
221 // Report undefined behaviour, stopping if required.
222 const Expr *E = S.Current->getExpr(OpPC);
223 QualType Type = E->getType();
224 if (S.checkingForUndefinedBehavior()) {
225 SmallString<32> Trunc;
226 Value.trunc(Result.bitWidth()).toString(Trunc, 10);
227 auto Loc = E->getExprLoc();
228 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
229 return true;
230 } else {
231 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
232 return S.noteUndefinedBehavior();
233 }
234}
235
236template <PrimType Name, class T = typename PrimConv<Name>::T>
237bool Add(InterpState &S, CodePtr OpPC) {
238 const T &RHS = S.Stk.pop<T>();
239 const T &LHS = S.Stk.pop<T>();
240 const unsigned Bits = RHS.bitWidth() + 1;
241 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
242}
243
244inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
245 const Floating &RHS = S.Stk.pop<Floating>();
246 const Floating &LHS = S.Stk.pop<Floating>();
247
249 auto Status = Floating::add(LHS, RHS, RM, &Result);
250 S.Stk.push<Floating>(Result);
251 return CheckFloatResult(S, OpPC, Status);
252}
253
254template <PrimType Name, class T = typename PrimConv<Name>::T>
255bool Sub(InterpState &S, CodePtr OpPC) {
256 const T &RHS = S.Stk.pop<T>();
257 const T &LHS = S.Stk.pop<T>();
258 const unsigned Bits = RHS.bitWidth() + 1;
259 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
260}
261
262inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
263 const Floating &RHS = S.Stk.pop<Floating>();
264 const Floating &LHS = S.Stk.pop<Floating>();
265
267 auto Status = Floating::sub(LHS, RHS, RM, &Result);
268 S.Stk.push<Floating>(Result);
269 return CheckFloatResult(S, OpPC, Status);
270}
271
272template <PrimType Name, class T = typename PrimConv<Name>::T>
273bool Mul(InterpState &S, CodePtr OpPC) {
274 const T &RHS = S.Stk.pop<T>();
275 const T &LHS = S.Stk.pop<T>();
276 const unsigned Bits = RHS.bitWidth() * 2;
277 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
278}
279
280inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
281 const Floating &RHS = S.Stk.pop<Floating>();
282 const Floating &LHS = S.Stk.pop<Floating>();
283
285 auto Status = Floating::mul(LHS, RHS, RM, &Result);
286 S.Stk.push<Floating>(Result);
287 return CheckFloatResult(S, OpPC, Status);
288}
289/// 1) Pops the RHS from the stack.
290/// 2) Pops the LHS from the stack.
291/// 3) Pushes 'LHS & RHS' on the stack
292template <PrimType Name, class T = typename PrimConv<Name>::T>
293bool BitAnd(InterpState &S, CodePtr OpPC) {
294 const T &RHS = S.Stk.pop<T>();
295 const T &LHS = S.Stk.pop<T>();
296
297 unsigned Bits = RHS.bitWidth();
298 T Result;
299 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
300 S.Stk.push<T>(Result);
301 return true;
302 }
303 return false;
304}
305
306/// 1) Pops the RHS from the stack.
307/// 2) Pops the LHS from the stack.
308/// 3) Pushes 'LHS | RHS' on the stack
309template <PrimType Name, class T = typename PrimConv<Name>::T>
310bool BitOr(InterpState &S, CodePtr OpPC) {
311 const T &RHS = S.Stk.pop<T>();
312 const T &LHS = S.Stk.pop<T>();
313
314 unsigned Bits = RHS.bitWidth();
315 T Result;
316 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
317 S.Stk.push<T>(Result);
318 return true;
319 }
320 return false;
321}
322
323/// 1) Pops the RHS from the stack.
324/// 2) Pops the LHS from the stack.
325/// 3) Pushes 'LHS ^ RHS' on the stack
326template <PrimType Name, class T = typename PrimConv<Name>::T>
327bool BitXor(InterpState &S, CodePtr OpPC) {
328 const T &RHS = S.Stk.pop<T>();
329 const T &LHS = S.Stk.pop<T>();
330
331 unsigned Bits = RHS.bitWidth();
332 T Result;
333 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
334 S.Stk.push<T>(Result);
335 return true;
336 }
337 return false;
338}
339
340/// 1) Pops the RHS from the stack.
341/// 2) Pops the LHS from the stack.
342/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
343template <PrimType Name, class T = typename PrimConv<Name>::T>
344bool Rem(InterpState &S, CodePtr OpPC) {
345 const T &RHS = S.Stk.pop<T>();
346 const T &LHS = S.Stk.pop<T>();
347
348 if (!CheckDivRem(S, OpPC, LHS, RHS))
349 return false;
350
351 const unsigned Bits = RHS.bitWidth() * 2;
352 T Result;
353 if (!T::rem(LHS, RHS, Bits, &Result)) {
354 S.Stk.push<T>(Result);
355 return true;
356 }
357 return false;
358}
359
360/// 1) Pops the RHS from the stack.
361/// 2) Pops the LHS from the stack.
362/// 3) Pushes 'LHS / RHS' on the stack
363template <PrimType Name, class T = typename PrimConv<Name>::T>
364bool Div(InterpState &S, CodePtr OpPC) {
365 const T &RHS = S.Stk.pop<T>();
366 const T &LHS = S.Stk.pop<T>();
367
368 if (!CheckDivRem(S, OpPC, LHS, RHS))
369 return false;
370
371 const unsigned Bits = RHS.bitWidth() * 2;
372 T Result;
373 if (!T::div(LHS, RHS, Bits, &Result)) {
374 S.Stk.push<T>(Result);
375 return true;
376 }
377 return false;
378}
379
380inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
381 const Floating &RHS = S.Stk.pop<Floating>();
382 const Floating &LHS = S.Stk.pop<Floating>();
383
384 if (!CheckDivRem(S, OpPC, LHS, RHS))
385 return false;
386
388 auto Status = Floating::div(LHS, RHS, RM, &Result);
389 S.Stk.push<Floating>(Result);
390 return CheckFloatResult(S, OpPC, Status);
391}
392
393//===----------------------------------------------------------------------===//
394// Inv
395//===----------------------------------------------------------------------===//
396
397template <PrimType Name, class T = typename PrimConv<Name>::T>
398bool Inv(InterpState &S, CodePtr OpPC) {
399 using BoolT = PrimConv<PT_Bool>::T;
400 const T &Val = S.Stk.pop<T>();
401 const unsigned Bits = Val.bitWidth();
402 Boolean R;
403 Boolean::inv(BoolT::from(Val, Bits), &R);
404
405 S.Stk.push<BoolT>(R);
406 return true;
407}
408
409//===----------------------------------------------------------------------===//
410// Neg
411//===----------------------------------------------------------------------===//
412
413template <PrimType Name, class T = typename PrimConv<Name>::T>
414bool Neg(InterpState &S, CodePtr OpPC) {
415 const T &Val = S.Stk.pop<T>();
416 T Result;
417 T::neg(Val, &Result);
418
419 S.Stk.push<T>(Result);
420 return true;
421}
422
423enum class PushVal : bool {
424 No,
425 Yes,
426};
427enum class IncDecOp {
428 Inc,
429 Dec,
430};
431
432template <typename T, IncDecOp Op, PushVal DoPush>
433bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
434 T Value = Ptr.deref<T>();
435 T Result;
436
437 if constexpr (DoPush == PushVal::Yes)
438 S.Stk.push<T>(Result);
439
440 if constexpr (Op == IncDecOp::Inc) {
441 if (!T::increment(Value, &Result)) {
442 Ptr.deref<T>() = Result;
443 return true;
444 }
445 } else {
446 if (!T::decrement(Value, &Result)) {
447 Ptr.deref<T>() = Result;
448 return true;
449 }
450 }
451
452 // Something went wrong with the previous operation. Compute the
453 // result with another bit of precision.
454 unsigned Bits = Value.bitWidth() + 1;
455 APSInt APResult;
456 if constexpr (Op == IncDecOp::Inc)
457 APResult = ++Value.toAPSInt(Bits);
458 else
459 APResult = --Value.toAPSInt(Bits);
460
461 // Report undefined behaviour, stopping if required.
462 const Expr *E = S.Current->getExpr(OpPC);
463 QualType Type = E->getType();
464 if (S.checkingForUndefinedBehavior()) {
465 SmallString<32> Trunc;
466 APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
467 auto Loc = E->getExprLoc();
468 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
469 return true;
470 }
471
472 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
473 return S.noteUndefinedBehavior();
474}
475
476/// 1) Pops a pointer from the stack
477/// 2) Load the value from the pointer
478/// 3) Writes the value increased by one back to the pointer
479/// 4) Pushes the original (pre-inc) value on the stack.
480template <PrimType Name, class T = typename PrimConv<Name>::T>
481bool Inc(InterpState &S, CodePtr OpPC) {
482 // FIXME: Check initialization of Ptr
483 const Pointer &Ptr = S.Stk.pop<Pointer>();
484
485 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
486}
487
488/// 1) Pops a pointer from the stack
489/// 2) Load the value from the pointer
490/// 3) Writes the value increased by one back to the pointer
491template <PrimType Name, class T = typename PrimConv<Name>::T>
492bool IncPop(InterpState &S, CodePtr OpPC) {
493 // FIXME: Check initialization of Ptr
494 const Pointer &Ptr = S.Stk.pop<Pointer>();
495
496 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
497}
498
499/// 1) Pops a pointer from the stack
500/// 2) Load the value from the pointer
501/// 3) Writes the value decreased by one back to the pointer
502/// 4) Pushes the original (pre-dec) value on the stack.
503template <PrimType Name, class T = typename PrimConv<Name>::T>
504bool Dec(InterpState &S, CodePtr OpPC) {
505 // FIXME: Check initialization of Ptr
506 const Pointer &Ptr = S.Stk.pop<Pointer>();
507
508 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
509}
510
511/// 1) Pops a pointer from the stack
512/// 2) Load the value from the pointer
513/// 3) Writes the value decreased by one back to the pointer
514template <PrimType Name, class T = typename PrimConv<Name>::T>
515bool DecPop(InterpState &S, CodePtr OpPC) {
516 // FIXME: Check initialization of Ptr
517 const Pointer &Ptr = S.Stk.pop<Pointer>();
518
519 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
520}
521
522/// 1) Pops the value from the stack.
523/// 2) Pushes the bitwise complemented value on the stack (~V).
524template <PrimType Name, class T = typename PrimConv<Name>::T>
525bool Comp(InterpState &S, CodePtr OpPC) {
526 const T &Val = S.Stk.pop<T>();
527 T Result;
528 if (!T::comp(Val, &Result)) {
529 S.Stk.push<T>(Result);
530 return true;
531 }
532
533 return false;
534}
535
536//===----------------------------------------------------------------------===//
537// EQ, NE, GT, GE, LT, LE
538//===----------------------------------------------------------------------===//
539
540using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
541
542template <typename T>
544 using BoolT = PrimConv<PT_Bool>::T;
545 const T &RHS = S.Stk.pop<T>();
546 const T &LHS = S.Stk.pop<T>();
547 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
548 return true;
549}
550
551template <typename T>
553 return CmpHelper<T>(S, OpPC, Fn);
554}
555
556template <>
558 using BoolT = PrimConv<PT_Bool>::T;
559 const Pointer &RHS = S.Stk.pop<Pointer>();
560 const Pointer &LHS = S.Stk.pop<Pointer>();
561
562 if (!Pointer::hasSameBase(LHS, RHS)) {
563 const SourceInfo &Loc = S.Current->getSource(OpPC);
564 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
565 return false;
566 } else {
567 unsigned VL = LHS.getByteOffset();
568 unsigned VR = RHS.getByteOffset();
569 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
570 return true;
571 }
572}
573
574template <>
576 using BoolT = PrimConv<PT_Bool>::T;
577 const Pointer &RHS = S.Stk.pop<Pointer>();
578 const Pointer &LHS = S.Stk.pop<Pointer>();
579
580 if (LHS.isZero() && RHS.isZero()) {
581 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
582 return true;
583 }
584
585 if (!Pointer::hasSameBase(LHS, RHS)) {
586 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
587 return true;
588 } else {
589 unsigned VL = LHS.getByteOffset();
590 unsigned VR = RHS.getByteOffset();
591
592 // In our Pointer class, a pointer to an array and a pointer to the first
593 // element in the same array are NOT equal. They have the same Base value,
594 // but a different Offset. This is a pretty rare case, so we fix this here
595 // by comparing pointers to the first elements.
596 if (LHS.inArray() && LHS.isRoot())
597 VL = LHS.atIndex(0).getByteOffset();
598 if (RHS.inArray() && RHS.isRoot())
599 VR = RHS.atIndex(0).getByteOffset();
600
601 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
602 return true;
603 }
604}
605
606template <PrimType Name, class T = typename PrimConv<Name>::T>
607bool EQ(InterpState &S, CodePtr OpPC) {
608 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
610 });
611}
612
613template <PrimType Name, class T = typename PrimConv<Name>::T>
614bool NE(InterpState &S, CodePtr OpPC) {
615 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
617 });
618}
619
620template <PrimType Name, class T = typename PrimConv<Name>::T>
621bool LT(InterpState &S, CodePtr OpPC) {
622 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
624 });
625}
626
627template <PrimType Name, class T = typename PrimConv<Name>::T>
628bool LE(InterpState &S, CodePtr OpPC) {
629 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
630 return R == ComparisonCategoryResult::Less ||
632 });
633}
634
635template <PrimType Name, class T = typename PrimConv<Name>::T>
636bool GT(InterpState &S, CodePtr OpPC) {
637 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
639 });
640}
641
642template <PrimType Name, class T = typename PrimConv<Name>::T>
643bool GE(InterpState &S, CodePtr OpPC) {
644 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
647 });
648}
649
650//===----------------------------------------------------------------------===//
651// InRange
652//===----------------------------------------------------------------------===//
653
654template <PrimType Name, class T = typename PrimConv<Name>::T>
656 const T RHS = S.Stk.pop<T>();
657 const T LHS = S.Stk.pop<T>();
658 const T Value = S.Stk.pop<T>();
659
660 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
661 return true;
662}
663
664//===----------------------------------------------------------------------===//
665// Dup, Pop, Test
666//===----------------------------------------------------------------------===//
667
668template <PrimType Name, class T = typename PrimConv<Name>::T>
669bool Dup(InterpState &S, CodePtr OpPC) {
670 S.Stk.push<T>(S.Stk.peek<T>());
671 return true;
672}
673
674template <PrimType Name, class T = typename PrimConv<Name>::T>
675bool Pop(InterpState &S, CodePtr OpPC) {
676 S.Stk.pop<T>();
677 return true;
678}
679
680//===----------------------------------------------------------------------===//
681// Const
682//===----------------------------------------------------------------------===//
683
684template <PrimType Name, class T = typename PrimConv<Name>::T>
685bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
686 S.Stk.push<T>(Arg);
687 return true;
688}
689
690//===----------------------------------------------------------------------===//
691// Get/Set Local/Param/Global/This
692//===----------------------------------------------------------------------===//
693
694template <PrimType Name, class T = typename PrimConv<Name>::T>
695bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
696 const Pointer &Ptr = S.Current->getLocalPointer(I);
697 if (!CheckLoad(S, OpPC, Ptr))
698 return false;
699 S.Stk.push<T>(Ptr.deref<T>());
700 return true;
701}
702
703template <PrimType Name, class T = typename PrimConv<Name>::T>
704bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
705 S.Current->setLocal<T>(I, S.Stk.pop<T>());
706 return true;
707}
708
709template <PrimType Name, class T = typename PrimConv<Name>::T>
710bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
711 if (S.checkingPotentialConstantExpression()) {
712 return false;
713 }
714 S.Stk.push<T>(S.Current->getParam<T>(I));
715 return true;
716}
717
718template <PrimType Name, class T = typename PrimConv<Name>::T>
719bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
720 S.Current->setParam<T>(I, S.Stk.pop<T>());
721 return true;
722}
723
724/// 1) Peeks a pointer on the stack
725/// 2) Pushes the value of the pointer's field on the stack
726template <PrimType Name, class T = typename PrimConv<Name>::T>
727bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
728 const Pointer &Obj = S.Stk.peek<Pointer>();
729 if (!CheckNull(S, OpPC, Obj, CSK_Field))
730 return false;
731 if (!CheckRange(S, OpPC, Obj, CSK_Field))
732 return false;
733 const Pointer &Field = Obj.atField(I);
734 if (!CheckLoad(S, OpPC, Field))
735 return false;
736 S.Stk.push<T>(Field.deref<T>());
737 return true;
738}
739
740template <PrimType Name, class T = typename PrimConv<Name>::T>
741bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
742 const T &Value = S.Stk.pop<T>();
743 const Pointer &Obj = S.Stk.peek<Pointer>();
744 if (!CheckNull(S, OpPC, Obj, CSK_Field))
745 return false;
746 if (!CheckRange(S, OpPC, Obj, CSK_Field))
747 return false;
748 const Pointer &Field = Obj.atField(I);
749 if (!CheckStore(S, OpPC, Field))
750 return false;
751 Field.deref<T>() = Value;
752 return true;
753}
754
755/// 1) Pops a pointer from the stack
756/// 2) Pushes the value of the pointer's field on the stack
757template <PrimType Name, class T = typename PrimConv<Name>::T>
758bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
759 const Pointer &Obj = S.Stk.pop<Pointer>();
760 if (!CheckNull(S, OpPC, Obj, CSK_Field))
761 return false;
762 if (!CheckRange(S, OpPC, Obj, CSK_Field))
763 return false;
764 const Pointer &Field = Obj.atField(I);
765 if (!CheckLoad(S, OpPC, Field))
766 return false;
767 S.Stk.push<T>(Field.deref<T>());
768 return true;
769}
770
771template <PrimType Name, class T = typename PrimConv<Name>::T>
772bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
773 if (S.checkingPotentialConstantExpression())
774 return false;
775 const Pointer &This = S.Current->getThis();
776 if (!CheckThis(S, OpPC, This))
777 return false;
778 const Pointer &Field = This.atField(I);
779 if (!CheckLoad(S, OpPC, Field))
780 return false;
781 S.Stk.push<T>(Field.deref<T>());
782 return true;
783}
784
785template <PrimType Name, class T = typename PrimConv<Name>::T>
786bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
787 if (S.checkingPotentialConstantExpression())
788 return false;
789 const T &Value = S.Stk.pop<T>();
790 const Pointer &This = S.Current->getThis();
791 if (!CheckThis(S, OpPC, This))
792 return false;
793 const Pointer &Field = This.atField(I);
794 if (!CheckStore(S, OpPC, Field))
795 return false;
796 Field.deref<T>() = Value;
797 return true;
798}
799
800template <PrimType Name, class T = typename PrimConv<Name>::T>
801bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
802 auto *B = S.P.getGlobal(I);
803 if (B->isExtern())
804 return false;
805 S.Stk.push<T>(B->deref<T>());
806 return true;
807}
808
809template <PrimType Name, class T = typename PrimConv<Name>::T>
810bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
811 // TODO: emit warning.
812 return false;
813}
814
815template <PrimType Name, class T = typename PrimConv<Name>::T>
816bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
817 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
818 return true;
819}
820
821/// 1) Converts the value on top of the stack to an APValue
822/// 2) Sets that APValue on \Temp
823/// 3) Initialized global with index \I with that
824template <PrimType Name, class T = typename PrimConv<Name>::T>
825bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
826 const LifetimeExtendedTemporaryDecl *Temp) {
827 assert(Temp);
828 const T Value = S.Stk.peek<T>();
829 APValue APV = Value.toAPValue();
830 APValue *Cached = Temp->getOrCreateValue(true);
831 *Cached = APV;
832
833 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
834 return true;
835}
836
837template <PrimType Name, class T = typename PrimConv<Name>::T>
838bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
839 if (S.checkingPotentialConstantExpression())
840 return false;
841 const Pointer &This = S.Current->getThis();
842 if (!CheckThis(S, OpPC, This))
843 return false;
844 const Pointer &Field = This.atField(I);
845 Field.deref<T>() = S.Stk.pop<T>();
846 Field.initialize();
847 return true;
848}
849
850template <PrimType Name, class T = typename PrimConv<Name>::T>
852 if (S.checkingPotentialConstantExpression())
853 return false;
854 const Pointer &This = S.Current->getThis();
855 if (!CheckThis(S, OpPC, This))
856 return false;
857 const Pointer &Field = This.atField(F->Offset);
858 const auto &Value = S.Stk.pop<T>();
859 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
860 Field.initialize();
861 return true;
862}
863
864template <PrimType Name, class T = typename PrimConv<Name>::T>
865bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
866 if (S.checkingPotentialConstantExpression())
867 return false;
868 const Pointer &This = S.Current->getThis();
869 if (!CheckThis(S, OpPC, This))
870 return false;
871 const Pointer &Field = This.atField(I);
872 Field.deref<T>() = S.Stk.pop<T>();
873 Field.activate();
874 Field.initialize();
875 return true;
876}
877
878/// 1) Pops the value from the stack
879/// 2) Peeks a pointer from the stack
880/// 3) Pushes the value to field I of the pointer on the stack
881template <PrimType Name, class T = typename PrimConv<Name>::T>
882bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
883 const T &Value = S.Stk.pop<T>();
884 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
885 Field.deref<T>() = Value;
886 Field.activate();
887 Field.initialize();
888 return true;
889}
890
891template <PrimType Name, class T = typename PrimConv<Name>::T>
893 const T &Value = S.Stk.pop<T>();
894 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
895 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
896 Field.activate();
897 Field.initialize();
898 return true;
899}
900
901template <PrimType Name, class T = typename PrimConv<Name>::T>
902bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
903 const T &Value = S.Stk.pop<T>();
904 const Pointer &Ptr = S.Stk.pop<Pointer>();
905 const Pointer &Field = Ptr.atField(I);
906 Field.deref<T>() = Value;
907 Field.activate();
908 Field.initialize();
909 return true;
910}
911
912//===----------------------------------------------------------------------===//
913// GetPtr Local/Param/Global/Field/This
914//===----------------------------------------------------------------------===//
915
916inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
917 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
918 return true;
919}
920
921inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
922 if (S.checkingPotentialConstantExpression()) {
923 return false;
924 }
925 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
926 return true;
927}
928
929inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
930 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
931 return true;
932}
933
934/// 1) Pops a Pointer from the stack
935/// 2) Pushes Pointer.atField(Off) on the stack
936inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
937 const Pointer &Ptr = S.Stk.pop<Pointer>();
938 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
939 return false;
940 if (!CheckExtern(S, OpPC, Ptr))
941 return false;
942 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
943 return false;
944 S.Stk.push<Pointer>(Ptr.atField(Off));
945 return true;
946}
947
948inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
949 if (S.checkingPotentialConstantExpression())
950 return false;
951 const Pointer &This = S.Current->getThis();
952 if (!CheckThis(S, OpPC, This))
953 return false;
954 S.Stk.push<Pointer>(This.atField(Off));
955 return true;
956}
957
958inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
959 const Pointer &Ptr = S.Stk.pop<Pointer>();
960 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
961 return false;
962 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
963 return false;
964 Pointer Field = Ptr.atField(Off);
965 Ptr.deactivate();
966 Field.activate();
967 S.Stk.push<Pointer>(std::move(Field));
968 return true;
969}
970
971inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
972 if (S.checkingPotentialConstantExpression())
973 return false;
974 const Pointer &This = S.Current->getThis();
975 if (!CheckThis(S, OpPC, This))
976 return false;
977 Pointer Field = This.atField(Off);
978 This.deactivate();
979 Field.activate();
980 S.Stk.push<Pointer>(std::move(Field));
981 return true;
982}
983
984inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
985 const Pointer &Ptr = S.Stk.peek<Pointer>();
986 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
987 return false;
988 S.Stk.push<Pointer>(Ptr.atField(Off));
989 return true;
990}
991
992inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
993 const Pointer &Ptr = S.Stk.pop<Pointer>();
994 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
995 return false;
996 S.Stk.push<Pointer>(Ptr.atField(Off));
997 return true;
998}
999
1000inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1001 if (S.checkingPotentialConstantExpression())
1002 return false;
1003 const Pointer &This = S.Current->getThis();
1004 if (!CheckThis(S, OpPC, This))
1005 return false;
1006 S.Stk.push<Pointer>(This.atField(Off));
1007 return true;
1008}
1009
1010inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1011 const Pointer &Ptr) {
1012 Pointer Base = Ptr;
1013 while (Base.isBaseClass())
1014 Base = Base.getBase();
1015
1016 auto *Field = Base.getRecord()->getVirtualBase(Decl);
1017 S.Stk.push<Pointer>(Base.atField(Field->Offset));
1018 return true;
1019}
1020
1021inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1022 const Pointer &Ptr = S.Stk.pop<Pointer>();
1023 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1024 return false;
1025 return VirtBaseHelper(S, OpPC, D, Ptr);
1026}
1027
1029 const RecordDecl *D) {
1030 if (S.checkingPotentialConstantExpression())
1031 return false;
1032 const Pointer &This = S.Current->getThis();
1033 if (!CheckThis(S, OpPC, This))
1034 return false;
1035 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1036}
1037
1038//===----------------------------------------------------------------------===//
1039// Load, Store, Init
1040//===----------------------------------------------------------------------===//
1041
1042template <PrimType Name, class T = typename PrimConv<Name>::T>
1043bool Load(InterpState &S, CodePtr OpPC) {
1044 const Pointer &Ptr = S.Stk.peek<Pointer>();
1045 if (!CheckLoad(S, OpPC, Ptr))
1046 return false;
1047 S.Stk.push<T>(Ptr.deref<T>());
1048 return true;
1049}
1050
1051template <PrimType Name, class T = typename PrimConv<Name>::T>
1053 const Pointer &Ptr = S.Stk.pop<Pointer>();
1054 if (!CheckLoad(S, OpPC, Ptr))
1055 return false;
1056 S.Stk.push<T>(Ptr.deref<T>());
1057 return true;
1058}
1059
1060template <PrimType Name, class T = typename PrimConv<Name>::T>
1061bool Store(InterpState &S, CodePtr OpPC) {
1062 const T &Value = S.Stk.pop<T>();
1063 const Pointer &Ptr = S.Stk.peek<Pointer>();
1064 if (!CheckStore(S, OpPC, Ptr))
1065 return false;
1066 if (!Ptr.isRoot())
1067 Ptr.initialize();
1068 Ptr.deref<T>() = Value;
1069 return true;
1070}
1071
1072template <PrimType Name, class T = typename PrimConv<Name>::T>
1074 const T &Value = S.Stk.pop<T>();
1075 const Pointer &Ptr = S.Stk.pop<Pointer>();
1076 if (!CheckStore(S, OpPC, Ptr))
1077 return false;
1078 if (!Ptr.isRoot())
1079 Ptr.initialize();
1080 Ptr.deref<T>() = Value;
1081 return true;
1082}
1083
1084template <PrimType Name, class T = typename PrimConv<Name>::T>
1086 const T &Value = S.Stk.pop<T>();
1087 const Pointer &Ptr = S.Stk.peek<Pointer>();
1088 if (!CheckStore(S, OpPC, Ptr))
1089 return false;
1090 if (!Ptr.isRoot())
1091 Ptr.initialize();
1092 if (auto *FD = Ptr.getField()) {
1093 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1094 } else {
1095 Ptr.deref<T>() = Value;
1096 }
1097 return true;
1098}
1099
1100template <PrimType Name, class T = typename PrimConv<Name>::T>
1102 const T &Value = S.Stk.pop<T>();
1103 const Pointer &Ptr = S.Stk.pop<Pointer>();
1104 if (!CheckStore(S, OpPC, Ptr))
1105 return false;
1106 if (!Ptr.isRoot())
1107 Ptr.initialize();
1108 if (auto *FD = Ptr.getField()) {
1109 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1110 } else {
1111 Ptr.deref<T>() = Value;
1112 }
1113 return true;
1114}
1115
1116template <PrimType Name, class T = typename PrimConv<Name>::T>
1118 const T &Value = S.Stk.pop<T>();
1119 const Pointer &Ptr = S.Stk.pop<Pointer>();
1120 if (!CheckInit(S, OpPC, Ptr))
1121 return false;
1122 Ptr.initialize();
1123 new (&Ptr.deref<T>()) T(Value);
1124 return true;
1125}
1126
1127/// 1) Pops the value from the stack
1128/// 2) Peeks a pointer and gets its index \Idx
1129/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1130template <PrimType Name, class T = typename PrimConv<Name>::T>
1131bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1132 const T &Value = S.Stk.pop<T>();
1133 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1134 if (!CheckInit(S, OpPC, Ptr))
1135 return false;
1136 Ptr.initialize();
1137 new (&Ptr.deref<T>()) T(Value);
1138 return true;
1139}
1140
1141/// The same as InitElem, but pops the pointer as well.
1142template <PrimType Name, class T = typename PrimConv<Name>::T>
1143bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1144 const T &Value = S.Stk.pop<T>();
1145 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1146 if (!CheckInit(S, OpPC, Ptr))
1147 return false;
1148 Ptr.initialize();
1149 new (&Ptr.deref<T>()) T(Value);
1150 return true;
1151}
1152
1153//===----------------------------------------------------------------------===//
1154// AddOffset, SubOffset
1155//===----------------------------------------------------------------------===//
1156
1157template <class T, ArithOp Op>
1158bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1159 const Pointer &Ptr) {
1160 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1161 return false;
1162
1163 // A zero offset does not change the pointer.
1164 if (Offset.isZero()) {
1165 S.Stk.push<Pointer>(Ptr);
1166 return true;
1167 }
1168
1169 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1170 return false;
1171
1172 // Arrays of unknown bounds cannot have pointers into them.
1173 if (!CheckArray(S, OpPC, Ptr))
1174 return false;
1175
1176 // Get a version of the index comparable to the type.
1177 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1178 // Compute the largest index into the array.
1179 unsigned MaxIndex = Ptr.getNumElems();
1180
1181 // Helper to report an invalid offset, computed as APSInt.
1182 auto InvalidOffset = [&]() {
1183 const unsigned Bits = Offset.bitWidth();
1184 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1185 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1186 APSInt NewIndex =
1187 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1188 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1189 << NewIndex
1190 << /*array*/ static_cast<int>(!Ptr.inArray())
1191 << static_cast<unsigned>(MaxIndex);
1192 return false;
1193 };
1194
1195 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1196 if constexpr (Op == ArithOp::Add) {
1197 // If the new offset would be negative, bail out.
1198 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1199 return InvalidOffset();
1200
1201 // If the new offset would be out of bounds, bail out.
1202 if (Offset.isPositive() && Offset > MaxOffset)
1203 return InvalidOffset();
1204 } else {
1205 // If the new offset would be negative, bail out.
1206 if (Offset.isPositive() && Index < Offset)
1207 return InvalidOffset();
1208
1209 // If the new offset would be out of bounds, bail out.
1210 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1211 return InvalidOffset();
1212 }
1213
1214 // Offset is valid - compute it on unsigned.
1215 int64_t WideIndex = static_cast<int64_t>(Index);
1216 int64_t WideOffset = static_cast<int64_t>(Offset);
1217 int64_t Result;
1218 if constexpr (Op == ArithOp::Add)
1219 Result = WideIndex + WideOffset;
1220 else
1221 Result = WideIndex - WideOffset;
1222
1223 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1224 return true;
1225}
1226
1227template <PrimType Name, class T = typename PrimConv<Name>::T>
1229 const T &Offset = S.Stk.pop<T>();
1230 const Pointer &Ptr = S.Stk.pop<Pointer>();
1231 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1232}
1233
1234template <PrimType Name, class T = typename PrimConv<Name>::T>
1236 const T &Offset = S.Stk.pop<T>();
1237 const Pointer &Ptr = S.Stk.pop<Pointer>();
1238 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1239}
1240
1241template <ArithOp Op>
1242static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC) {
1243 using OneT = Integral<8, false>;
1244 const Pointer &Ptr = S.Stk.pop<Pointer>();
1245
1246 // Get the current value on the stack.
1247 S.Stk.push<Pointer>(Ptr.deref<Pointer>());
1248
1249 // Now the current Ptr again and a constant 1.
1250 Pointer P = Ptr.deref<Pointer>();
1251 OneT One = OneT::from(1);
1252 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1253 return false;
1254
1255 // Store the new value.
1256 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1257 return true;
1258}
1259
1260static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1261 return IncDecPtrHelper<ArithOp::Add>(S, OpPC);
1262}
1263
1264static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1265 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC);
1266}
1267
1268/// 1) Pops a Pointer from the stack.
1269/// 2) Pops another Pointer from the stack.
1270/// 3) Pushes the different of the indices of the two pointers on the stack.
1271template <PrimType Name, class T = typename PrimConv<Name>::T>
1272inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1273 const Pointer &LHS = S.Stk.pop<Pointer>();
1274 const Pointer &RHS = S.Stk.pop<Pointer>();
1275
1276 if (!Pointer::hasSameArray(LHS, RHS)) {
1277 // TODO: Diagnose.
1278 return false;
1279 }
1280
1281 T A = T::from(LHS.getIndex());
1282 T B = T::from(RHS.getIndex());
1283 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1284}
1285
1286//===----------------------------------------------------------------------===//
1287// Destroy
1288//===----------------------------------------------------------------------===//
1289
1290inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1291 S.Current->destroy(I);
1292 return true;
1293}
1294
1295//===----------------------------------------------------------------------===//
1296// Cast, CastFP
1297//===----------------------------------------------------------------------===//
1298
1299template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1300 using T = typename PrimConv<TIn>::T;
1301 using U = typename PrimConv<TOut>::T;
1302 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1303 return true;
1304}
1305
1306/// 1) Pops a Floating from the stack.
1307/// 2) Pushes a new floating on the stack that uses the given semantics.
1308/// Not templated, so implemented in Interp.cpp.
1309bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1310 llvm::RoundingMode RM);
1311
1312template <PrimType Name, class T = typename PrimConv<Name>::T>
1314 const llvm::fltSemantics *Sem,
1315 llvm::RoundingMode RM) {
1316 const T &From = S.Stk.pop<T>();
1317 APSInt FromAP = From.toAPSInt();
1319
1320 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1321 S.Stk.push<Floating>(Result);
1322
1323 return CheckFloatResult(S, OpPC, Status);
1324}
1325
1326template <PrimType Name, class T = typename PrimConv<Name>::T>
1328 const Floating &F = S.Stk.pop<Floating>();
1329
1330 if constexpr (std::is_same_v<T, Boolean>) {
1331 S.Stk.push<T>(T(F.isNonZero()));
1332 return true;
1333 } else {
1334 APSInt Result(std::max(8u, T::bitWidth() + 1),
1335 /*IsUnsigned=*/!T::isSigned());
1336 auto Status = F.convertToInteger(Result);
1337
1338 // Float-to-Integral overflow check.
1339 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1340 const Expr *E = S.Current->getExpr(OpPC);
1341 QualType Type = E->getType();
1342
1343 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1344 return S.noteUndefinedBehavior();
1345 }
1346
1347 S.Stk.push<T>(T(Result));
1348 return CheckFloatResult(S, OpPC, Status);
1349 }
1350}
1351
1352//===----------------------------------------------------------------------===//
1353// Zero, Nullptr
1354//===----------------------------------------------------------------------===//
1355
1356template <PrimType Name, class T = typename PrimConv<Name>::T>
1357bool Zero(InterpState &S, CodePtr OpPC) {
1358 S.Stk.push<T>(T::zero());
1359 return true;
1360}
1361
1362template <PrimType Name, class T = typename PrimConv<Name>::T>
1363inline bool Null(InterpState &S, CodePtr OpPC) {
1364 S.Stk.push<T>();
1365 return true;
1366}
1367
1368//===----------------------------------------------------------------------===//
1369// This, ImplicitThis
1370//===----------------------------------------------------------------------===//
1371
1372inline bool This(InterpState &S, CodePtr OpPC) {
1373 // Cannot read 'this' in this mode.
1374 if (S.checkingPotentialConstantExpression()) {
1375 return false;
1376 }
1377
1378 const Pointer &This = S.Current->getThis();
1379 if (!CheckThis(S, OpPC, This))
1380 return false;
1381
1382 S.Stk.push<Pointer>(This);
1383 return true;
1384}
1385
1386inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1387 assert(S.Current->getFunction()->hasRVO());
1388 if (S.checkingPotentialConstantExpression())
1389 return false;
1390 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1391 return true;
1392}
1393
1394//===----------------------------------------------------------------------===//
1395// Shr, Shl
1396//===----------------------------------------------------------------------===//
1397
1398template <PrimType NameL, PrimType NameR>
1399inline bool Shr(InterpState &S, CodePtr OpPC) {
1400 using LT = typename PrimConv<NameL>::T;
1401 using RT = typename PrimConv<NameR>::T;
1402 const auto &RHS = S.Stk.pop<RT>();
1403 const auto &LHS = S.Stk.pop<LT>();
1404 const unsigned Bits = LHS.bitWidth();
1405
1406 if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1407 return false;
1408
1409 Integral<LT::bitWidth(), false> R;
1410 Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
1411 S.Stk.push<LT>(R);
1412 return true;
1413}
1414
1415template <PrimType NameL, PrimType NameR>
1416inline bool Shl(InterpState &S, CodePtr OpPC) {
1417 using LT = typename PrimConv<NameL>::T;
1418 using RT = typename PrimConv<NameR>::T;
1419 const auto &RHS = S.Stk.pop<RT>();
1420 const auto &LHS = S.Stk.pop<LT>();
1421 const unsigned Bits = LHS.bitWidth();
1422
1423 if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1424 return false;
1425
1426 Integral<LT::bitWidth(), false> R;
1427 Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
1428 S.Stk.push<LT>(R);
1429 return true;
1430}
1431
1432//===----------------------------------------------------------------------===//
1433// NoRet
1434//===----------------------------------------------------------------------===//
1435
1436inline bool NoRet(InterpState &S, CodePtr OpPC) {
1437 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1438 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1439 return false;
1440}
1441
1442//===----------------------------------------------------------------------===//
1443// NarrowPtr, ExpandPtr
1444//===----------------------------------------------------------------------===//
1445
1446inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1447 const Pointer &Ptr = S.Stk.pop<Pointer>();
1448 S.Stk.push<Pointer>(Ptr.narrow());
1449 return true;
1450}
1451
1452inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1453 const Pointer &Ptr = S.Stk.pop<Pointer>();
1454 S.Stk.push<Pointer>(Ptr.expand());
1455 return true;
1456}
1457
1458// 1) Pops an integral value from the stack
1459// 2) Peeks a pointer
1460// 3) Pushes a new pointer that's a narrowed array
1461// element of the peeked pointer with the value
1462// from 1) added as offset.
1463//
1464// This leaves the original pointer on the stack and pushes a new one
1465// with the offset applied and narrowed.
1466template <PrimType Name, class T = typename PrimConv<Name>::T>
1467inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1468 const T &Offset = S.Stk.pop<T>();
1469 const Pointer &Ptr = S.Stk.peek<Pointer>();
1470
1471 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1472 return false;
1473
1474 return NarrowPtr(S, OpPC);
1475}
1476
1477template <PrimType Name, class T = typename PrimConv<Name>::T>
1478inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1479 const T &Offset = S.Stk.pop<T>();
1480 const Pointer &Ptr = S.Stk.pop<Pointer>();
1481
1482 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1483 return false;
1484
1485 return NarrowPtr(S, OpPC);
1486}
1487
1489 const Pointer &Obj = S.Stk.peek<Pointer>();
1490 return CheckCtorCall(S, PC, Obj);
1491}
1492
1493inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
1494 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1495 Pointer ThisPtr;
1496 if (Func->hasThisPointer()) {
1497 ThisPtr = NewFrame->getThis();
1498 if (!CheckInvoke(S, PC, ThisPtr))
1499 return false;
1500
1501 if (S.checkingPotentialConstantExpression())
1502 return false;
1503 }
1504
1505 if (!CheckCallable(S, PC, Func))
1506 return false;
1507
1508 InterpFrame *FrameBefore = S.Current;
1509 S.Current = NewFrame.get();
1510
1511 APValue CallResult;
1512 // Note that we cannot assert(CallResult.hasValue()) here since
1513 // Ret() above only sets the APValue if the curent frame doesn't
1514 // have a caller set.
1515 if (Interpret(S, CallResult)) {
1516 NewFrame.release(); // Frame was delete'd already.
1517 assert(S.Current == FrameBefore);
1518 return true;
1519 }
1520
1521 // Interpreting the function failed somehow. Reset to
1522 // previous state.
1523 S.Current = FrameBefore;
1524 return false;
1525}
1526
1527inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func) {
1528 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1529
1530 InterpFrame *FrameBefore = S.Current;
1531 S.Current = NewFrame.get();
1532
1533 if (InterpretBuiltin(S, PC, Func->getBuiltinID())) {
1534 NewFrame.release();
1535 return true;
1536 }
1537 S.Current = FrameBefore;
1538 return false;
1539}
1540
1541//===----------------------------------------------------------------------===//
1542// Read opcode arguments
1543//===----------------------------------------------------------------------===//
1544
1545template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1546 if constexpr (std::is_pointer<T>::value) {
1547 uint32_t ID = OpPC.read<uint32_t>();
1548 return reinterpret_cast<T>(S.P.getNativePointer(ID));
1549 } else {
1550 return OpPC.read<T>();
1551 }
1552}
1553
1554} // namespace interp
1555} // namespace clang
1556
1557#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3217
ASTImporterLookupTable & LT
StringRef P
llvm::APSInt APSInt
unsigned Offset
Definition: Format.cpp:2776
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:2018
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
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:330
QualType getType() const
Definition: Expr.h:142
unsigned getBitWidthValue(const ASTContext &Ctx) const
Definition: Decl.cpp:4323
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3166
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3009
A (possibly-)qualified type.
Definition: Type.h:736
Represents a struct/union/class.
Definition: Decl.h:3998
Encodes a location in the source.
The base class of the type hierarchy.
Definition: Type.h:1566
Wrapper around boolean types.
Definition: Boolean.h:25
static bool inv(Boolean A, Boolean *R)
Definition: Boolean.h:143
Pointer into the code segment.
Definition: Source.h:26
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:50
static APFloat::opStatus div(Floating A, Floating B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:126
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus sub(Floating A, Floating B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:114
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:96
bool isNonZero() const
Definition: Floating.h:86
bool isFinite() const
Definition: Floating.h:90
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition: Floating.h:50
static APFloat::opStatus add(Floating A, Floating B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:108
static APFloat::opStatus mul(Floating A, Floating B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:120
Bytecode function.
Definition: Function.h:74
bool hasThisPointer() const
Definition: Function.h:143
unsigned getBuiltinID() const
Definition: Function.h:148
Wrapper around numeric types.
Definition: Integral.h:48
Frame storing local variables.
Definition: InterpFrame.h:29
Interpreter context.
Definition: InterpState.h:34
A pointer to a memory block, live or dead.
Definition: Pointer.h:61
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:205
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:99
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:201
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:296
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:81
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:93
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:313
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:291
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:233
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:163
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:243
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:209
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:135
void initialize() const
Initializes a field.
Definition: Pointer.cpp:168
unsigned getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:286
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:70
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1117
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:398
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1399
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) Initialized ...
Definition: Interp.h:825
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:492
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:992
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:262
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:636
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:288
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:515
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:772
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1446
llvm::APInt APInt
Definition: Integral.h:29
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:838
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:495
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:710
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1143
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1085
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1052
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1260
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:669
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:344
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:741
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks that all fields are initialized after a constructor call.
Definition: Interp.cpp:446
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:916
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:122
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:206
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:936
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:364
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:233
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:971
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1272
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:929
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1467
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:614
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1436
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:244
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1416
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1386
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1235
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:327
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:196
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1452
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:865
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:362
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1061
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:727
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1478
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1372
bool InterpretBuiltin(InterpState &S, CodePtr &PC, unsigned BuiltinID)
Interpret a builtin function.
bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:280
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:882
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status)
Checks if the result is a floating-point operation is valid in the current context.
Definition: Interp.cpp:452
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:552
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:540
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:1545
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:159
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:157
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:433
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1327
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:695
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:293
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func)
Definition: Interp.h:1527
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:1313
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:628
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:29
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1357
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:264
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:187
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.cpp:487
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1242
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:786
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1101
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1264
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:182
bool CheckGlobalCtor(InterpState &S, CodePtr &PC)
Definition: Interp.h:1488
bool Null(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1363
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:902
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:344
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1010
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:246
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:948
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:958
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:149
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:984
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:719
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:525
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1073
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:851
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:704
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:273
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:1131
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1290
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:675
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:892
bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1021
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
Definition: Interp.h:1493
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:655
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:414
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:136
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:380
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:310
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1043
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:810
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1299
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:607
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:758
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:296
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1228
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:685
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:643
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:575
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:543
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:214
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:921
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:801
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1028
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:816
bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:101
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:557
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:278
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1000
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1158
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
CheckSubobjectKind
Definition: State.h:40
@ CSK_ArrayToPointer
Definition: State.h:44
@ 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
#define bool
Definition: stdbool.h:20
Mapping from primitive types to their representation.
Definition: PrimType.h:44
Describes a record field.
Definition: Record.h:28
const FieldDecl * Decl
Definition: Record.h:29