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