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
34namespace clang {
35namespace interp {
36
37using APInt = llvm::APInt;
38using APSInt = llvm::APSInt;
39
40/// Convers a value to an APValue.
41template <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.
47bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
48
49/// Checks if the array is offsetable.
50bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
51
52/// Checks if a pointer is live and accesible.
53bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
54               AccessKinds AK);
55/// Checks if a pointer is null.
56bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57               CheckSubobjectKind CSK);
58
59/// Checks if a pointer is in range.
60bool 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.
64bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
65                CheckSubobjectKind CSK);
66
67/// Checks if a pointer points to const storage.
68bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
69
70/// Checks if a pointer points to a mutable field.
71bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
72
73/// Checks if a value can be loaded from a block.
74bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
75
76/// Checks if a value can be stored in a block.
77bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
78
79/// Checks if a method can be invoked on an object.
80bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
81
82/// Checks if a value can be initialized.
83bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
84
85/// Checks if a method can be called.
86bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
87
88/// Checks the 'this' pointer.
89bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
90
91/// Checks if a method is pure virtual.
92bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
93
94template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
95
96//===----------------------------------------------------------------------===//
97// Add, Sub, Mul
98//===----------------------------------------------------------------------===//
99
100template <typename T, bool (*OpFW)(T, T, unsigned, T *),
101          template <typename U> class OpAP>
102bool 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
131template <PrimType Name, class T = typename PrimConv<Name>::T>
132bool 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
139template <PrimType Name, class T = typename PrimConv<Name>::T>
140bool 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
147template <PrimType Name, class T = typename PrimConv<Name>::T>
148bool 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
159using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
160
161template <typename T>
162bool 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
170template <typename T>
171bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
172  return CmpHelper<T>(S, OpPC, Fn);
173}
174
175template <>
176inline 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
193template <>
194inline 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
215template <PrimType Name, class T = typename PrimConv<Name>::T>
216bool EQ(InterpState &S, CodePtr OpPC) {
217  return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
218    return R == ComparisonCategoryResult::Equal;
219  });
220}
221
222template <PrimType Name, class T = typename PrimConv<Name>::T>
223bool NE(InterpState &S, CodePtr OpPC) {
224  return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
225    return R != ComparisonCategoryResult::Equal;
226  });
227}
228
229template <PrimType Name, class T = typename PrimConv<Name>::T>
230bool LT(InterpState &S, CodePtr OpPC) {
231  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
232    return R == ComparisonCategoryResult::Less;
233  });
234}
235
236template <PrimType Name, class T = typename PrimConv<Name>::T>
237bool 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
244template <PrimType Name, class T = typename PrimConv<Name>::T>
245bool GT(InterpState &S, CodePtr OpPC) {
246  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
247    return R == ComparisonCategoryResult::Greater;
248  });
249}
250
251template <PrimType Name, class T = typename PrimConv<Name>::T>
252bool 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
263template <PrimType Name, class T = typename PrimConv<Name>::T>
264bool 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
277template <PrimType Name, class T = typename PrimConv<Name>::T>
278bool Dup(InterpState &S, CodePtr OpPC) {
279  S.Stk.push<T>(S.Stk.peek<T>());
280  return true;
281}
282
283template <PrimType Name, class T = typename PrimConv<Name>::T>
284bool Pop(InterpState &S, CodePtr OpPC) {
285  S.Stk.pop<T>();
286  return true;
287}
288
289//===----------------------------------------------------------------------===//
290// Const
291//===----------------------------------------------------------------------===//
292
293template <PrimType Name, class T = typename PrimConv<Name>::T>
294bool 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
303template <PrimType Name, class T = typename PrimConv<Name>::T>
304bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
305  S.Stk.push<T>(S.Current->getLocal<T>(I));
306  return true;
307}
308
309template <PrimType Name, class T = typename PrimConv<Name>::T>
310bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
311  S.Current->setLocal<T>(I, S.Stk.pop<T>());
312  return true;
313}
314
315template <PrimType Name, class T = typename PrimConv<Name>::T>
316bool 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
324template <PrimType Name, class T = typename PrimConv<Name>::T>
325bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
326  S.Current->setParam<T>(I, S.Stk.pop<T>());
327  return true;
328}
329
330template <PrimType Name, class T = typename PrimConv<Name>::T>
331bool 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
344template <PrimType Name, class T = typename PrimConv<Name>::T>
345bool 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
359template <PrimType Name, class T = typename PrimConv<Name>::T>
360bool 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
373template <PrimType Name, class T = typename PrimConv<Name>::T>
374bool 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
387template <PrimType Name, class T = typename PrimConv<Name>::T>
388bool 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
402template <PrimType Name, class T = typename PrimConv<Name>::T>
403bool 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
411template <PrimType Name, class T = typename PrimConv<Name>::T>
412bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
413  // TODO: emit warning.
414  return false;
415}
416
417template <PrimType Name, class T = typename PrimConv<Name>::T>
418bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
419  S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
420  return true;
421}
422
423template <PrimType Name, class T = typename PrimConv<Name>::T>
424bool 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
436template <PrimType Name, class T = typename PrimConv<Name>::T>
437bool 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
450template <PrimType Name, class T = typename PrimConv<Name>::T>
451bool 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
464template <PrimType Name, class T = typename PrimConv<Name>::T>
465bool 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
474template <PrimType Name, class T = typename PrimConv<Name>::T>
475bool 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
484template <PrimType Name, class T = typename PrimConv<Name>::T>
485bool 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
499inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
500  S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
501  return true;
502}
503
504inline 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
512inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
513  S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
514  return true;
515}
516
517inline 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
529inline 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
539inline 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
552inline 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
565inline 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
573inline 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
583inline 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
594inline 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
601inline 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
615template <PrimType Name, class T = typename PrimConv<Name>::T>
616bool 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
624template <PrimType Name, class T = typename PrimConv<Name>::T>
625bool 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
633template <PrimType Name, class T = typename PrimConv<Name>::T>
634bool 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
643template <PrimType Name, class T = typename PrimConv<Name>::T>
644bool 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
653template <PrimType Name, class T = typename PrimConv<Name>::T>
654bool 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
667template <PrimType Name, class T = typename PrimConv<Name>::T>
668bool 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
681template <PrimType Name, class T = typename PrimConv<Name>::T>
682bool 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
692template <PrimType Name, class T = typename PrimConv<Name>::T>
693bool 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
703template <PrimType Name, class T = typename PrimConv<Name>::T>
704bool 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
718template <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
776template <PrimType Name, class T = typename PrimConv<Name>::T>
777bool AddOffset(InterpState &S, CodePtr OpPC) {
778  return OffsetHelper<T, true>(S, OpPC);
779}
780
781template <PrimType Name, class T = typename PrimConv<Name>::T>
782bool SubOffset(InterpState &S, CodePtr OpPC) {
783  return OffsetHelper<T, false>(S, OpPC);
784}
785
786
787//===----------------------------------------------------------------------===//
788// Destroy
789//===----------------------------------------------------------------------===//
790
791inline 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
800template <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
811template <PrimType Name, class T = typename PrimConv<Name>::T>
812bool Zero(InterpState &S, CodePtr OpPC) {
813  S.Stk.push<T>(T::zero());
814  return true;
815}
816
817template <PrimType Name, class T = typename PrimConv<Name>::T>
818inline bool Null(InterpState &S, CodePtr OpPC) {
819  S.Stk.push<T>();
820  return true;
821}
822
823//===----------------------------------------------------------------------===//
824// This, ImplicitThis
825//===----------------------------------------------------------------------===//
826
827inline 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
845template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
846unsigned 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
860template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
861inline 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
870template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
871inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
872  if (V.isSigned() && !S.getLangOpts().CPlusPlus2a) {
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
895template <PrimType TL, PrimType TR>
896inline 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
910template <PrimType TL, PrimType TR>
911inline 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
929inline 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
939inline 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
945inline 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.
952bool Interpret(InterpState &S, APValue &Result);
953
954} // namespace interp
955} // namespace clang
956
957#endif
958