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