xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Interp.h (revision 4731124cace5e7a0224e29784617d2856e5c59ab)
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 <limits>
17 #include <vector>
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"
26 #include "clang/AST/ASTContext.h"
27 #include "clang/AST/ASTDiagnostic.h"
28 #include "clang/AST/CXXInheritance.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 
34 namespace clang {
35 namespace interp {
36 
37 using APInt = llvm::APInt;
38 using APSInt = llvm::APSInt;
39 
40 /// Convers 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 accesible.
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, 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 template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
95 
96 //===----------------------------------------------------------------------===//
97 // Add, Sub, Mul
98 //===----------------------------------------------------------------------===//
99 
100 template <typename T, bool (*OpFW)(T, T, unsigned, T *),
101           template <typename U> class OpAP>
102 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
103                      const T &RHS) {
104   // Fast path - add the numbers with fixed width.
105   T Result;
106   if (!OpFW(LHS, RHS, Bits, &Result)) {
107     S.Stk.push<T>(Result);
108     return true;
109   }
110 
111   // If for some reason evaluation continues, use the truncated results.
112   S.Stk.push<T>(Result);
113 
114   // Slow path - compute the result using another bit of precision.
115   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
116 
117   // Report undefined behaviour, stopping if required.
118   const Expr *E = S.Current->getExpr(OpPC);
119   QualType Type = E->getType();
120   if (S.checkingForUndefinedBehavior()) {
121     SmallString<32> Trunc;
122     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
123     auto Loc = E->getExprLoc();
124     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
125     return true;
126   } else {
127     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
128     return S.noteUndefinedBehavior();
129   }
130 }
131 
132 template <PrimType Name, class T = typename PrimConv<Name>::T>
133 bool Add(InterpState &S, CodePtr OpPC) {
134   const T &RHS = S.Stk.pop<T>();
135   const T &LHS = S.Stk.pop<T>();
136   const unsigned Bits = RHS.bitWidth() + 1;
137   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
138 }
139 
140 template <PrimType Name, class T = typename PrimConv<Name>::T>
141 bool Sub(InterpState &S, CodePtr OpPC) {
142   const T &RHS = S.Stk.pop<T>();
143   const T &LHS = S.Stk.pop<T>();
144   const unsigned Bits = RHS.bitWidth() + 1;
145   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
146 }
147 
148 template <PrimType Name, class T = typename PrimConv<Name>::T>
149 bool Mul(InterpState &S, CodePtr OpPC) {
150   const T &RHS = S.Stk.pop<T>();
151   const T &LHS = S.Stk.pop<T>();
152   const unsigned Bits = RHS.bitWidth() * 2;
153   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
154 }
155 
156 //===----------------------------------------------------------------------===//
157 // EQ, NE, GT, GE, LT, LE
158 //===----------------------------------------------------------------------===//
159 
160 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
161 
162 template <typename T>
163 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
164   using BoolT = PrimConv<PT_Bool>::T;
165   const T &RHS = S.Stk.pop<T>();
166   const T &LHS = S.Stk.pop<T>();
167   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
168   return true;
169 }
170 
171 template <typename T>
172 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
173   return CmpHelper<T>(S, OpPC, Fn);
174 }
175 
176 template <>
177 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
178   using BoolT = PrimConv<PT_Bool>::T;
179   const Pointer &RHS = S.Stk.pop<Pointer>();
180   const Pointer &LHS = S.Stk.pop<Pointer>();
181 
182   if (!Pointer::hasSameBase(LHS, RHS)) {
183     const SourceInfo &Loc = S.Current->getSource(OpPC);
184     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
185     return false;
186   } else {
187     unsigned VL = LHS.getByteOffset();
188     unsigned VR = RHS.getByteOffset();
189     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
190     return true;
191   }
192 }
193 
194 template <>
195 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
196   using BoolT = PrimConv<PT_Bool>::T;
197   const Pointer &RHS = S.Stk.pop<Pointer>();
198   const Pointer &LHS = S.Stk.pop<Pointer>();
199 
200   if (LHS.isZero() && RHS.isZero()) {
201     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
202     return true;
203   }
204 
205   if (!Pointer::hasSameBase(LHS, RHS)) {
206     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
207     return true;
208   } else {
209     unsigned VL = LHS.getByteOffset();
210     unsigned VR = RHS.getByteOffset();
211     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
212     return true;
213   }
214 }
215 
216 template <PrimType Name, class T = typename PrimConv<Name>::T>
217 bool EQ(InterpState &S, CodePtr OpPC) {
218   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
219     return R == ComparisonCategoryResult::Equal;
220   });
221 }
222 
223 template <PrimType Name, class T = typename PrimConv<Name>::T>
224 bool NE(InterpState &S, CodePtr OpPC) {
225   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
226     return R != ComparisonCategoryResult::Equal;
227   });
228 }
229 
230 template <PrimType Name, class T = typename PrimConv<Name>::T>
231 bool LT(InterpState &S, CodePtr OpPC) {
232   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
233     return R == ComparisonCategoryResult::Less;
234   });
235 }
236 
237 template <PrimType Name, class T = typename PrimConv<Name>::T>
238 bool LE(InterpState &S, CodePtr OpPC) {
239   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
240     return R == ComparisonCategoryResult::Less ||
241            R == ComparisonCategoryResult::Equal;
242   });
243 }
244 
245 template <PrimType Name, class T = typename PrimConv<Name>::T>
246 bool GT(InterpState &S, CodePtr OpPC) {
247   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
248     return R == ComparisonCategoryResult::Greater;
249   });
250 }
251 
252 template <PrimType Name, class T = typename PrimConv<Name>::T>
253 bool GE(InterpState &S, CodePtr OpPC) {
254   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
255     return R == ComparisonCategoryResult::Greater ||
256            R == ComparisonCategoryResult::Equal;
257   });
258 }
259 
260 //===----------------------------------------------------------------------===//
261 // InRange
262 //===----------------------------------------------------------------------===//
263 
264 template <PrimType Name, class T = typename PrimConv<Name>::T>
265 bool InRange(InterpState &S, CodePtr OpPC) {
266   const T RHS = S.Stk.pop<T>();
267   const T LHS = S.Stk.pop<T>();
268   const T Value = S.Stk.pop<T>();
269 
270   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
271   return true;
272 }
273 
274 //===----------------------------------------------------------------------===//
275 // Dup, Pop, Test
276 //===----------------------------------------------------------------------===//
277 
278 template <PrimType Name, class T = typename PrimConv<Name>::T>
279 bool Dup(InterpState &S, CodePtr OpPC) {
280   S.Stk.push<T>(S.Stk.peek<T>());
281   return true;
282 }
283 
284 template <PrimType Name, class T = typename PrimConv<Name>::T>
285 bool Pop(InterpState &S, CodePtr OpPC) {
286   S.Stk.pop<T>();
287   return true;
288 }
289 
290 //===----------------------------------------------------------------------===//
291 // Const
292 //===----------------------------------------------------------------------===//
293 
294 template <PrimType Name, class T = typename PrimConv<Name>::T>
295 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
296   S.Stk.push<T>(Arg);
297   return true;
298 }
299 
300 //===----------------------------------------------------------------------===//
301 // Get/Set Local/Param/Global/This
302 //===----------------------------------------------------------------------===//
303 
304 template <PrimType Name, class T = typename PrimConv<Name>::T>
305 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
306   S.Stk.push<T>(S.Current->getLocal<T>(I));
307   return true;
308 }
309 
310 template <PrimType Name, class T = typename PrimConv<Name>::T>
311 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
312   S.Current->setLocal<T>(I, S.Stk.pop<T>());
313   return true;
314 }
315 
316 template <PrimType Name, class T = typename PrimConv<Name>::T>
317 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
318   if (S.checkingPotentialConstantExpression()) {
319     return false;
320   }
321   S.Stk.push<T>(S.Current->getParam<T>(I));
322   return true;
323 }
324 
325 template <PrimType Name, class T = typename PrimConv<Name>::T>
326 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
327   S.Current->setParam<T>(I, S.Stk.pop<T>());
328   return true;
329 }
330 
331 template <PrimType Name, class T = typename PrimConv<Name>::T>
332 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
333   const Pointer &Obj = S.Stk.peek<Pointer>();
334   if (!CheckNull(S, OpPC, Obj, CSK_Field))
335       return false;
336   if (!CheckRange(S, OpPC, Obj, CSK_Field))
337     return false;
338   const Pointer &Field = Obj.atField(I);
339   if (!CheckLoad(S, OpPC, Field))
340     return false;
341   S.Stk.push<T>(Field.deref<T>());
342   return true;
343 }
344 
345 template <PrimType Name, class T = typename PrimConv<Name>::T>
346 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
347   const T &Value = S.Stk.pop<T>();
348   const Pointer &Obj = S.Stk.peek<Pointer>();
349   if (!CheckNull(S, OpPC, Obj, CSK_Field))
350     return false;
351   if (!CheckRange(S, OpPC, Obj, CSK_Field))
352     return false;
353   const Pointer &Field = Obj.atField(I);
354   if (!CheckStore(S, OpPC, Field))
355     return false;
356   Field.deref<T>() = Value;
357   return true;
358 }
359 
360 template <PrimType Name, class T = typename PrimConv<Name>::T>
361 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
362   const Pointer &Obj = S.Stk.pop<Pointer>();
363   if (!CheckNull(S, OpPC, Obj, CSK_Field))
364     return false;
365   if (!CheckRange(S, OpPC, Obj, CSK_Field))
366     return false;
367   const Pointer &Field = Obj.atField(I);
368   if (!CheckLoad(S, OpPC, Field))
369     return false;
370   S.Stk.push<T>(Field.deref<T>());
371   return true;
372 }
373 
374 template <PrimType Name, class T = typename PrimConv<Name>::T>
375 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
376   if (S.checkingPotentialConstantExpression())
377     return false;
378   const Pointer &This = S.Current->getThis();
379   if (!CheckThis(S, OpPC, This))
380     return false;
381   const Pointer &Field = This.atField(I);
382   if (!CheckLoad(S, OpPC, Field))
383     return false;
384   S.Stk.push<T>(Field.deref<T>());
385   return true;
386 }
387 
388 template <PrimType Name, class T = typename PrimConv<Name>::T>
389 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
390   if (S.checkingPotentialConstantExpression())
391     return false;
392   const T &Value = S.Stk.pop<T>();
393   const Pointer &This = S.Current->getThis();
394   if (!CheckThis(S, OpPC, This))
395     return false;
396   const Pointer &Field = This.atField(I);
397   if (!CheckStore(S, OpPC, Field))
398     return false;
399   Field.deref<T>() = Value;
400   return true;
401 }
402 
403 template <PrimType Name, class T = typename PrimConv<Name>::T>
404 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
405   auto *B = S.P.getGlobal(I);
406   if (B->isExtern())
407     return false;
408   S.Stk.push<T>(B->deref<T>());
409   return true;
410 }
411 
412 template <PrimType Name, class T = typename PrimConv<Name>::T>
413 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
414   // TODO: emit warning.
415   return false;
416 }
417 
418 template <PrimType Name, class T = typename PrimConv<Name>::T>
419 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
420   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
421   return true;
422 }
423 
424 template <PrimType Name, class T = typename PrimConv<Name>::T>
425 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
426   if (S.checkingPotentialConstantExpression())
427     return false;
428   const Pointer &This = S.Current->getThis();
429   if (!CheckThis(S, OpPC, This))
430     return false;
431   const Pointer &Field = This.atField(I);
432   Field.deref<T>() = S.Stk.pop<T>();
433   Field.initialize();
434   return true;
435 }
436 
437 template <PrimType Name, class T = typename PrimConv<Name>::T>
438 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
439   if (S.checkingPotentialConstantExpression())
440     return false;
441   const Pointer &This = S.Current->getThis();
442   if (!CheckThis(S, OpPC, This))
443     return false;
444   const Pointer &Field = This.atField(F->Offset);
445   const auto &Value = S.Stk.pop<T>();
446   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
447   Field.initialize();
448   return true;
449 }
450 
451 template <PrimType Name, class T = typename PrimConv<Name>::T>
452 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
453   if (S.checkingPotentialConstantExpression())
454     return false;
455   const Pointer &This = S.Current->getThis();
456   if (!CheckThis(S, OpPC, This))
457     return false;
458   const Pointer &Field = This.atField(I);
459   Field.deref<T>() = S.Stk.pop<T>();
460   Field.activate();
461   Field.initialize();
462   return true;
463 }
464 
465 template <PrimType Name, class T = typename PrimConv<Name>::T>
466 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
467   const T &Value = S.Stk.pop<T>();
468   const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
469   Field.deref<T>() = Value;
470   Field.activate();
471   Field.initialize();
472   return true;
473 }
474 
475 template <PrimType Name, class T = typename PrimConv<Name>::T>
476 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
477   const T &Value = S.Stk.pop<T>();
478   const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
479   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
480   Field.activate();
481   Field.initialize();
482   return true;
483 }
484 
485 template <PrimType Name, class T = typename PrimConv<Name>::T>
486 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
487   const T &Value = S.Stk.pop<T>();
488   const Pointer &Ptr = S.Stk.pop<Pointer>();
489   const Pointer &Field = Ptr.atField(I);
490   Field.deref<T>() = Value;
491   Field.activate();
492   Field.initialize();
493   return true;
494 }
495 
496 //===----------------------------------------------------------------------===//
497 // GetPtr Local/Param/Global/Field/This
498 //===----------------------------------------------------------------------===//
499 
500 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
501   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
502   return true;
503 }
504 
505 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
506   if (S.checkingPotentialConstantExpression()) {
507     return false;
508   }
509   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
510   return true;
511 }
512 
513 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
514   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
515   return true;
516 }
517 
518 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
519   const Pointer &Ptr = S.Stk.pop<Pointer>();
520   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
521     return false;
522   if (!CheckExtern(S, OpPC, Ptr))
523     return false;
524   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
525     return false;
526   S.Stk.push<Pointer>(Ptr.atField(Off));
527   return true;
528 }
529 
530 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
531   if (S.checkingPotentialConstantExpression())
532     return false;
533   const Pointer &This = S.Current->getThis();
534   if (!CheckThis(S, OpPC, This))
535     return false;
536   S.Stk.push<Pointer>(This.atField(Off));
537   return true;
538 }
539 
540 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
541   const Pointer &Ptr = S.Stk.pop<Pointer>();
542   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
543     return false;
544   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
545     return false;
546   Pointer Field = Ptr.atField(Off);
547   Ptr.deactivate();
548   Field.activate();
549   S.Stk.push<Pointer>(std::move(Field));
550   return true;
551 }
552 
553 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
554  if (S.checkingPotentialConstantExpression())
555     return false;
556   const Pointer &This = S.Current->getThis();
557   if (!CheckThis(S, OpPC, This))
558     return false;
559   Pointer Field = This.atField(Off);
560   This.deactivate();
561   Field.activate();
562   S.Stk.push<Pointer>(std::move(Field));
563   return true;
564 }
565 
566 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
567   const Pointer &Ptr = S.Stk.pop<Pointer>();
568   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
569     return false;
570   S.Stk.push<Pointer>(Ptr.atField(Off));
571   return true;
572 }
573 
574 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
575   if (S.checkingPotentialConstantExpression())
576     return false;
577   const Pointer &This = S.Current->getThis();
578   if (!CheckThis(S, OpPC, This))
579     return false;
580   S.Stk.push<Pointer>(This.atField(Off));
581   return true;
582 }
583 
584 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
585                            const Pointer &Ptr) {
586   Pointer Base = Ptr;
587   while (Base.isBaseClass())
588     Base = Base.getBase();
589 
590   auto *Field = Base.getRecord()->getVirtualBase(Decl);
591   S.Stk.push<Pointer>(Base.atField(Field->Offset));
592   return true;
593 }
594 
595 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
596   const Pointer &Ptr = S.Stk.pop<Pointer>();
597   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
598     return false;
599   return VirtBaseHelper(S, OpPC, D, Ptr);
600 }
601 
602 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
603                                const RecordDecl *D) {
604   if (S.checkingPotentialConstantExpression())
605     return false;
606   const Pointer &This = S.Current->getThis();
607   if (!CheckThis(S, OpPC, This))
608     return false;
609   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
610 }
611 
612 //===----------------------------------------------------------------------===//
613 // Load, Store, Init
614 //===----------------------------------------------------------------------===//
615 
616 template <PrimType Name, class T = typename PrimConv<Name>::T>
617 bool Load(InterpState &S, CodePtr OpPC) {
618   const Pointer &Ptr = S.Stk.peek<Pointer>();
619   if (!CheckLoad(S, OpPC, Ptr))
620     return false;
621   S.Stk.push<T>(Ptr.deref<T>());
622   return true;
623 }
624 
625 template <PrimType Name, class T = typename PrimConv<Name>::T>
626 bool LoadPop(InterpState &S, CodePtr OpPC) {
627   const Pointer &Ptr = S.Stk.pop<Pointer>();
628   if (!CheckLoad(S, OpPC, Ptr))
629     return false;
630   S.Stk.push<T>(Ptr.deref<T>());
631   return true;
632 }
633 
634 template <PrimType Name, class T = typename PrimConv<Name>::T>
635 bool Store(InterpState &S, CodePtr OpPC) {
636   const T &Value = S.Stk.pop<T>();
637   const Pointer &Ptr = S.Stk.peek<Pointer>();
638   if (!CheckStore(S, OpPC, Ptr))
639     return false;
640   Ptr.deref<T>() = Value;
641   return true;
642 }
643 
644 template <PrimType Name, class T = typename PrimConv<Name>::T>
645 bool StorePop(InterpState &S, CodePtr OpPC) {
646   const T &Value = S.Stk.pop<T>();
647   const Pointer &Ptr = S.Stk.pop<Pointer>();
648   if (!CheckStore(S, OpPC, Ptr))
649     return false;
650   Ptr.deref<T>() = Value;
651   return true;
652 }
653 
654 template <PrimType Name, class T = typename PrimConv<Name>::T>
655 bool StoreBitField(InterpState &S, CodePtr OpPC) {
656   const T &Value = S.Stk.pop<T>();
657   const Pointer &Ptr = S.Stk.peek<Pointer>();
658   if (!CheckStore(S, OpPC, Ptr))
659     return false;
660   if (auto *FD = Ptr.getField()) {
661     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
662   } else {
663     Ptr.deref<T>() = Value;
664   }
665   return true;
666 }
667 
668 template <PrimType Name, class T = typename PrimConv<Name>::T>
669 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
670   const T &Value = S.Stk.pop<T>();
671   const Pointer &Ptr = S.Stk.pop<Pointer>();
672   if (!CheckStore(S, OpPC, Ptr))
673     return false;
674   if (auto *FD = Ptr.getField()) {
675     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
676   } else {
677     Ptr.deref<T>() = Value;
678   }
679   return true;
680 }
681 
682 template <PrimType Name, class T = typename PrimConv<Name>::T>
683 bool InitPop(InterpState &S, CodePtr OpPC) {
684   const T &Value = S.Stk.pop<T>();
685   const Pointer &Ptr = S.Stk.pop<Pointer>();
686   if (!CheckInit(S, OpPC, Ptr))
687     return false;
688   Ptr.initialize();
689   new (&Ptr.deref<T>()) T(Value);
690   return true;
691 }
692 
693 template <PrimType Name, class T = typename PrimConv<Name>::T>
694 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
695   const T &Value = S.Stk.pop<T>();
696   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
697   if (!CheckInit(S, OpPC, Ptr))
698     return false;
699   Ptr.initialize();
700   new (&Ptr.deref<T>()) T(Value);
701   return true;
702 }
703 
704 template <PrimType Name, class T = typename PrimConv<Name>::T>
705 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
706   const T &Value = S.Stk.pop<T>();
707   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
708   if (!CheckInit(S, OpPC, Ptr))
709     return false;
710   Ptr.initialize();
711   new (&Ptr.deref<T>()) T(Value);
712   return true;
713 }
714 
715 //===----------------------------------------------------------------------===//
716 // AddOffset, SubOffset
717 //===----------------------------------------------------------------------===//
718 
719 template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
720   // Fetch the pointer and the offset.
721   const T &Offset = S.Stk.pop<T>();
722   const Pointer &Ptr = S.Stk.pop<Pointer>();
723   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
724     return false;
725   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
726     return false;
727 
728   // Get a version of the index comparable to the type.
729   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
730   // A zero offset does not change the pointer, but in the case of an array
731   // it has to be adjusted to point to the first element instead of the array.
732   if (Offset.isZero()) {
733     S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
734     return true;
735   }
736   // Arrays of unknown bounds cannot have pointers into them.
737   if (!CheckArray(S, OpPC, Ptr))
738     return false;
739 
740   // Compute the largest index into the array.
741   unsigned MaxIndex = Ptr.getNumElems();
742 
743   // Helper to report an invalid offset, computed as APSInt.
744   auto InvalidOffset = [&]() {
745     const unsigned Bits = Offset.bitWidth();
746     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
747     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
748     APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
749     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
750         << NewIndex
751         << /*array*/ static_cast<int>(!Ptr.inArray())
752         << static_cast<unsigned>(MaxIndex);
753     return false;
754   };
755 
756   // If the new offset would be negative, bail out.
757   if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
758     return InvalidOffset();
759   if (!Add && Offset.isPositive() && Index < Offset)
760     return InvalidOffset();
761 
762   // If the new offset would be out of bounds, bail out.
763   unsigned MaxOffset = MaxIndex - Ptr.getIndex();
764   if (Add && Offset.isPositive() && Offset > MaxOffset)
765     return InvalidOffset();
766   if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
767     return InvalidOffset();
768 
769   // Offset is valid - compute it on unsigned.
770   int64_t WideIndex = static_cast<int64_t>(Index);
771   int64_t WideOffset = static_cast<int64_t>(Offset);
772   int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
773   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
774   return true;
775 }
776 
777 template <PrimType Name, class T = typename PrimConv<Name>::T>
778 bool AddOffset(InterpState &S, CodePtr OpPC) {
779   return OffsetHelper<T, true>(S, OpPC);
780 }
781 
782 template <PrimType Name, class T = typename PrimConv<Name>::T>
783 bool SubOffset(InterpState &S, CodePtr OpPC) {
784   return OffsetHelper<T, false>(S, OpPC);
785 }
786 
787 
788 //===----------------------------------------------------------------------===//
789 // Destroy
790 //===----------------------------------------------------------------------===//
791 
792 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
793   S.Current->destroy(I);
794   return true;
795 }
796 
797 //===----------------------------------------------------------------------===//
798 // Cast, CastFP
799 //===----------------------------------------------------------------------===//
800 
801 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
802   using T = typename PrimConv<TIn>::T;
803   using U = typename PrimConv<TOut>::T;
804   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
805   return true;
806 }
807 
808 //===----------------------------------------------------------------------===//
809 // Zero, Nullptr
810 //===----------------------------------------------------------------------===//
811 
812 template <PrimType Name, class T = typename PrimConv<Name>::T>
813 bool Zero(InterpState &S, CodePtr OpPC) {
814   S.Stk.push<T>(T::zero());
815   return true;
816 }
817 
818 template <PrimType Name, class T = typename PrimConv<Name>::T>
819 inline bool Null(InterpState &S, CodePtr OpPC) {
820   S.Stk.push<T>();
821   return true;
822 }
823 
824 //===----------------------------------------------------------------------===//
825 // This, ImplicitThis
826 //===----------------------------------------------------------------------===//
827 
828 inline bool This(InterpState &S, CodePtr OpPC) {
829   // Cannot read 'this' in this mode.
830   if (S.checkingPotentialConstantExpression()) {
831     return false;
832   }
833 
834   const Pointer &This = S.Current->getThis();
835   if (!CheckThis(S, OpPC, This))
836     return false;
837 
838   S.Stk.push<Pointer>(This);
839   return true;
840 }
841 
842 //===----------------------------------------------------------------------===//
843 // Shr, Shl
844 //===----------------------------------------------------------------------===//
845 
846 template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
847 unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
848   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
849   // the shifted type.
850   if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
851     const Expr *E = S.Current->getExpr(OpPC);
852     const APSInt Val = V.toAPSInt();
853     QualType Ty = E->getType();
854     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
855     return Bits;
856   } else {
857     return static_cast<unsigned>(V);
858   }
859 }
860 
861 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
862 inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
863   if (RHS >= V.bitWidth()) {
864     S.Stk.push<T>(T::from(0, V.bitWidth()));
865   } else {
866     S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
867   }
868   return true;
869 }
870 
871 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
872 inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
873   if (V.isSigned() && !S.getLangOpts().CPlusPlus20) {
874     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
875     // operand, and must not overflow the corresponding unsigned type.
876     // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
877     // E1 x 2^E2 module 2^N.
878     if (V.isNegative()) {
879       const Expr *E = S.Current->getExpr(OpPC);
880       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
881     } else if (V.countLeadingZeros() < RHS) {
882       S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
883     }
884   }
885 
886   if (V.bitWidth() == 1) {
887     S.Stk.push<T>(V);
888   } else if (RHS >= V.bitWidth()) {
889     S.Stk.push<T>(T::from(0, V.bitWidth()));
890   } else {
891     S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
892   }
893   return true;
894 }
895 
896 template <PrimType TL, PrimType TR>
897 inline bool Shr(InterpState &S, CodePtr OpPC) {
898   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
899   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
900   const unsigned Bits = LHS.bitWidth();
901 
902   if (RHS.isSigned() && RHS.isNegative()) {
903     const SourceInfo &Loc = S.Current->getSource(OpPC);
904     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
905     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
906   } else {
907     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
908   }
909 }
910 
911 template <PrimType TL, PrimType TR>
912 inline bool Shl(InterpState &S, CodePtr OpPC) {
913   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
914   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
915   const unsigned Bits = LHS.bitWidth();
916 
917   if (RHS.isSigned() && RHS.isNegative()) {
918     const SourceInfo &Loc = S.Current->getSource(OpPC);
919     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
920     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
921   } else {
922     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
923   }
924 }
925 
926 //===----------------------------------------------------------------------===//
927 // NoRet
928 //===----------------------------------------------------------------------===//
929 
930 inline bool NoRet(InterpState &S, CodePtr OpPC) {
931   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
932   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
933   return false;
934 }
935 
936 //===----------------------------------------------------------------------===//
937 // NarrowPtr, ExpandPtr
938 //===----------------------------------------------------------------------===//
939 
940 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
941   const Pointer &Ptr = S.Stk.pop<Pointer>();
942   S.Stk.push<Pointer>(Ptr.narrow());
943   return true;
944 }
945 
946 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
947   const Pointer &Ptr = S.Stk.pop<Pointer>();
948   S.Stk.push<Pointer>(Ptr.expand());
949   return true;
950 }
951 
952 /// Interpreter entry point.
953 bool Interpret(InterpState &S, APValue &Result);
954 
955 } // namespace interp
956 } // namespace clang
957 
958 #endif
959