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