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