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