1//===------- Interp.cpp - 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#include "Interp.h"
10#include <limits>
11#include <vector>
12#include "Function.h"
13#include "InterpFrame.h"
14#include "InterpStack.h"
15#include "Opcode.h"
16#include "PrimType.h"
17#include "Program.h"
18#include "State.h"
19#include "clang/AST/ASTContext.h"
20#include "clang/AST/ASTDiagnostic.h"
21#include "clang/AST/CXXInheritance.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/ExprCXX.h"
24#include "llvm/ADT/APSInt.h"
25
26using namespace clang;
27using namespace clang::interp;
28
29//===----------------------------------------------------------------------===//
30// Ret
31//===----------------------------------------------------------------------===//
32
33template <PrimType Name, class T = typename PrimConv<Name>::T>
34static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
35  S.CallStackDepth--;
36  const T &Ret = S.Stk.pop<T>();
37
38  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
39  if (!S.checkingPotentialConstantExpression())
40    S.Current->popArgs();
41
42  if (InterpFrame *Caller = S.Current->Caller) {
43    PC = S.Current->getRetPC();
44    delete S.Current;
45    S.Current = Caller;
46    S.Stk.push<T>(Ret);
47  } else {
48    delete S.Current;
49    S.Current = nullptr;
50    if (!ReturnValue<T>(Ret, Result))
51      return false;
52  }
53  return true;
54}
55
56static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
57  S.CallStackDepth--;
58
59  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
60  if (!S.checkingPotentialConstantExpression())
61    S.Current->popArgs();
62
63  if (InterpFrame *Caller = S.Current->Caller) {
64    PC = S.Current->getRetPC();
65    delete S.Current;
66    S.Current = Caller;
67  } else {
68    delete S.Current;
69    S.Current = nullptr;
70  }
71  return true;
72}
73
74static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
75  llvm::report_fatal_error("Interpreter cannot return values");
76}
77
78//===----------------------------------------------------------------------===//
79// Jmp, Jt, Jf
80//===----------------------------------------------------------------------===//
81
82static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
83  PC += Offset;
84  return true;
85}
86
87static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
88  if (S.Stk.pop<bool>()) {
89    PC += Offset;
90  }
91  return true;
92}
93
94static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
95  if (!S.Stk.pop<bool>()) {
96    PC += Offset;
97  }
98  return true;
99}
100
101static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
102                             AccessKinds AK) {
103  if (Ptr.isInitialized())
104    return true;
105  if (!S.checkingPotentialConstantExpression()) {
106    const SourceInfo &Loc = S.Current->getSource(OpPC);
107    S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
108  }
109  return false;
110}
111
112static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
113                        AccessKinds AK) {
114  if (Ptr.isActive())
115    return true;
116
117  // Get the inactive field descriptor.
118  const FieldDecl *InactiveField = Ptr.getField();
119
120  // Walk up the pointer chain to find the union which is not active.
121  Pointer U = Ptr.getBase();
122  while (!U.isActive()) {
123    U = U.getBase();
124  }
125
126  // Find the active field of the union.
127  Record *R = U.getRecord();
128  assert(R && R->isUnion() && "Not a union");
129  const FieldDecl *ActiveField = nullptr;
130  for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
131    const Pointer &Field = U.atField(R->getField(I)->Offset);
132    if (Field.isActive()) {
133      ActiveField = Field.getField();
134      break;
135    }
136  }
137
138  const SourceInfo &Loc = S.Current->getSource(OpPC);
139  S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
140      << AK << InactiveField << !ActiveField << ActiveField;
141  return false;
142}
143
144static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
145                           AccessKinds AK) {
146  if (auto ID = Ptr.getDeclID()) {
147    if (!Ptr.isStaticTemporary())
148      return true;
149
150    if (Ptr.getDeclDesc()->getType().isConstQualified())
151      return true;
152
153    if (S.P.getCurrentDecl() == ID)
154      return true;
155
156    const SourceInfo &E = S.Current->getSource(OpPC);
157    S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
158    S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
159    return false;
160  }
161  return true;
162}
163
164static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
165  if (auto ID = Ptr.getDeclID()) {
166    if (!Ptr.isStatic())
167      return true;
168
169    if (S.P.getCurrentDecl() == ID)
170      return true;
171
172    S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
173    return false;
174  }
175  return true;
176}
177
178namespace clang {
179namespace interp {
180
181bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
182  if (!Ptr.isExtern())
183    return true;
184
185  if (!S.checkingPotentialConstantExpression()) {
186    auto *VD = Ptr.getDeclDesc()->asValueDecl();
187    const SourceInfo &Loc = S.Current->getSource(OpPC);
188    S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
189    S.Note(VD->getLocation(), diag::note_declared_at);
190  }
191  return false;
192}
193
194bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
195  if (!Ptr.isUnknownSizeArray())
196    return true;
197  const SourceInfo &E = S.Current->getSource(OpPC);
198  S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
199  return false;
200}
201
202bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
203               AccessKinds AK) {
204  if (Ptr.isZero()) {
205    const auto &Src = S.Current->getSource(OpPC);
206
207    if (Ptr.isField())
208      S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
209    else
210      S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
211
212    return false;
213  }
214
215  if (!Ptr.isLive()) {
216    const auto &Src = S.Current->getSource(OpPC);
217    bool IsTemp = Ptr.isTemporary();
218
219    S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
220
221    if (IsTemp)
222      S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
223    else
224      S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
225
226    return false;
227  }
228
229  return true;
230}
231
232bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
233               CheckSubobjectKind CSK) {
234  if (!Ptr.isZero())
235    return true;
236  const SourceInfo &Loc = S.Current->getSource(OpPC);
237  S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
238  return false;
239}
240
241bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
242                AccessKinds AK) {
243  if (!Ptr.isOnePastEnd())
244    return true;
245  const SourceInfo &Loc = S.Current->getSource(OpPC);
246  S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
247  return false;
248}
249
250bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
251                CheckSubobjectKind CSK) {
252  if (!Ptr.isElementPastEnd())
253    return true;
254  const SourceInfo &Loc = S.Current->getSource(OpPC);
255  S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
256  return false;
257}
258
259bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
260  assert(Ptr.isLive() && "Pointer is not live");
261  if (!Ptr.isConst()) {
262    return true;
263  }
264
265  const QualType Ty = Ptr.getType();
266  const SourceInfo &Loc = S.Current->getSource(OpPC);
267  S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
268  return false;
269}
270
271bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
272  assert(Ptr.isLive() && "Pointer is not live");
273  if (!Ptr.isMutable()) {
274    return true;
275  }
276
277  const SourceInfo &Loc = S.Current->getSource(OpPC);
278  const FieldDecl *Field = Ptr.getField();
279  S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
280  S.Note(Field->getLocation(), diag::note_declared_at);
281  return false;
282}
283
284bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
285  if (!CheckLive(S, OpPC, Ptr, AK_Read))
286    return false;
287  if (!CheckExtern(S, OpPC, Ptr))
288    return false;
289  if (!CheckRange(S, OpPC, Ptr, AK_Read))
290    return false;
291  if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
292    return false;
293  if (!CheckActive(S, OpPC, Ptr, AK_Read))
294    return false;
295  if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
296    return false;
297  if (!CheckMutable(S, OpPC, Ptr))
298    return false;
299  return true;
300}
301
302bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
303  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
304    return false;
305  if (!CheckExtern(S, OpPC, Ptr))
306    return false;
307  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
308    return false;
309  if (!CheckGlobal(S, OpPC, Ptr))
310    return false;
311  if (!CheckConst(S, OpPC, Ptr))
312    return false;
313  return true;
314}
315
316bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
317  if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
318    return false;
319  if (!CheckExtern(S, OpPC, Ptr))
320    return false;
321  if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
322    return false;
323  return true;
324}
325
326bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
327  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
328    return false;
329  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
330    return false;
331  return true;
332}
333
334bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
335
336  if (F->isVirtual()) {
337    if (!S.getLangOpts().CPlusPlus20) {
338      const SourceLocation &Loc = S.Current->getLocation(OpPC);
339      S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
340      return false;
341    }
342  }
343
344  if (!F->isConstexpr()) {
345    const SourceLocation &Loc = S.Current->getLocation(OpPC);
346    if (S.getLangOpts().CPlusPlus11) {
347      const FunctionDecl *DiagDecl = F->getDecl();
348
349      // If this function is not constexpr because it is an inherited
350      // non-constexpr constructor, diagnose that directly.
351      auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
352      if (CD && CD->isInheritingConstructor()) {
353        auto *Inherited = CD->getInheritedConstructor().getConstructor();
354        if (!Inherited->isConstexpr())
355          DiagDecl = CD = Inherited;
356      }
357
358      // FIXME: If DiagDecl is an implicitly-declared special member function
359      // or an inheriting constructor, we should be much more explicit about why
360      // it's not constexpr.
361      if (CD && CD->isInheritingConstructor())
362        S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
363          << CD->getInheritedConstructor().getConstructor()->getParent();
364      else
365        S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
366          << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
367      S.Note(DiagDecl->getLocation(), diag::note_declared_at);
368    } else {
369      S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
370    }
371    return false;
372  }
373
374  return true;
375}
376
377bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
378  if (!This.isZero())
379    return true;
380
381  const SourceInfo &Loc = S.Current->getSource(OpPC);
382
383  bool IsImplicit = false;
384  if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
385    IsImplicit = E->isImplicit();
386
387  if (S.getLangOpts().CPlusPlus11)
388    S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
389  else
390    S.FFDiag(Loc);
391
392  return false;
393}
394
395bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
396  if (!MD->isPure())
397    return true;
398  const SourceInfo &E = S.Current->getSource(OpPC);
399  S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
400  S.Note(MD->getLocation(), diag::note_declared_at);
401  return false;
402}
403
404static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
405                                           QualType SubObjType,
406                                           SourceLocation SubObjLoc) {
407  S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType;
408  if (SubObjLoc.isValid())
409    S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here);
410}
411
412static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
413                                   const Pointer &BasePtr, const Record *R);
414
415static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
416                                  const Pointer &BasePtr,
417                                  const ConstantArrayType *CAT) {
418  bool Result = true;
419  size_t NumElems = CAT->getSize().getZExtValue();
420  QualType ElemType = CAT->getElementType();
421
422  if (isa<RecordType>(ElemType.getTypePtr())) {
423    const Record *R = BasePtr.getElemRecord();
424    for (size_t I = 0; I != NumElems; ++I) {
425      Pointer ElemPtr = BasePtr.atIndex(I).narrow();
426      Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
427    }
428  } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
429    for (size_t I = 0; I != NumElems; ++I) {
430      Pointer ElemPtr = BasePtr.atIndex(I).narrow();
431      Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
432    }
433  } else {
434    for (size_t I = 0; I != NumElems; ++I) {
435      if (!BasePtr.atIndex(I).isInitialized()) {
436        DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType,
437                                       BasePtr.getFieldDesc()->getLocation());
438        Result = false;
439      }
440    }
441  }
442
443  return Result;
444}
445
446static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
447                                   const Pointer &BasePtr, const Record *R) {
448  assert(R);
449  bool Result = true;
450  // Check all fields of this record are initialized.
451  for (const Record::Field &F : R->fields()) {
452    Pointer FieldPtr = BasePtr.atField(F.Offset);
453    QualType FieldType = F.Decl->getType();
454
455    if (FieldType->isRecordType()) {
456      Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
457    } else if (FieldType->isArrayType()) {
458      const auto *CAT =
459          cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
460      Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
461    } else if (!FieldPtr.isInitialized()) {
462      DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
463                                     F.Decl->getType(), F.Decl->getLocation());
464      Result = false;
465    }
466  }
467  return Result;
468}
469
470bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
471  assert(!This.isZero());
472  const Record *R = This.getRecord();
473  return CheckFieldsInitialized(S, OpPC, This, R);
474}
475
476bool Interpret(InterpState &S, APValue &Result) {
477  // The current stack frame when we started Interpret().
478  // This is being used by the ops to determine wheter
479  // to return from this function and thus terminate
480  // interpretation.
481  const InterpFrame *StartFrame = S.Current;
482  assert(!S.Current->isRoot());
483  CodePtr PC = S.Current->getPC();
484
485  // Empty program.
486  if (!PC)
487    return true;
488
489  for (;;) {
490    auto Op = PC.read<Opcode>();
491    CodePtr OpPC = PC;
492
493    switch (Op) {
494#define GET_INTERP
495#include "Opcodes.inc"
496#undef GET_INTERP
497    }
498  }
499}
500
501} // namespace interp
502} // namespace clang
503