blob: c9ace131bbd5af1383e14dde24c2c84dbc7741d7 [file] [log] [blame]
Nandor Licker950b70d2019-09-13 09:46:16 +00001//===--- InterpState.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 const auto &Src = S.Current->getSource(OpPC);
205 if (Ptr.isZero()) {
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 bool IsTemp = Ptr.isTemporary();
217
218 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
219
220 if (IsTemp)
221 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
222 else
223 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
224
225 return false;
226 }
227
228 return true;
229}
230
231bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
232 CheckSubobjectKind CSK) {
233 if (!Ptr.isZero())
234 return true;
235 const SourceInfo &Loc = S.Current->getSource(OpPC);
236 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
237 return false;
238}
239
240bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
241 AccessKinds AK) {
242 if (!Ptr.isOnePastEnd())
243 return true;
244 const SourceInfo &Loc = S.Current->getSource(OpPC);
245 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
246 return false;
247}
248
249bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
250 CheckSubobjectKind CSK) {
251 if (!Ptr.isElementPastEnd())
252 return true;
253 const SourceInfo &Loc = S.Current->getSource(OpPC);
254 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
255 return false;
256}
257
258bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
259 assert(Ptr.isLive() && "Pointer is not live");
260 if (!Ptr.isConst()) {
261 return true;
262 }
263
264 const QualType Ty = Ptr.getType();
265 const SourceInfo &Loc = S.Current->getSource(OpPC);
266 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
267 return false;
268}
269
270bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
271 assert(Ptr.isLive() && "Pointer is not live");
272 if (!Ptr.isMutable()) {
273 return true;
274 }
275
276 const SourceInfo &Loc = S.Current->getSource(OpPC);
277 const FieldDecl *Field = Ptr.getField();
278 S.FFDiag(Loc, diag::note_constexpr_ltor_mutable, 1) << Field;
279 S.Note(Field->getLocation(), diag::note_declared_at);
280 return false;
281}
282
283bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
284 if (!CheckLive(S, OpPC, Ptr, AK_Read))
285 return false;
286 if (!CheckExtern(S, OpPC, Ptr))
287 return false;
288 if (!CheckRange(S, OpPC, Ptr, AK_Read))
289 return false;
290 if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
291 return false;
292 if (!CheckActive(S, OpPC, Ptr, AK_Read))
293 return false;
294 if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
295 return false;
296 if (!CheckMutable(S, OpPC, Ptr))
297 return false;
298 return true;
299}
300
301bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
302 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
303 return false;
304 if (!CheckExtern(S, OpPC, Ptr))
305 return false;
306 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
307 return false;
308 if (!CheckGlobal(S, OpPC, Ptr))
309 return false;
310 if (!CheckConst(S, OpPC, Ptr))
311 return false;
312 return true;
313}
314
315bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
316 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
317 return false;
318 if (!CheckExtern(S, OpPC, Ptr))
319 return false;
320 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
321 return false;
322 return true;
323}
324
325bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
326 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
327 return false;
328 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
329 return false;
330 return true;
331}
332
333bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
334 const SourceLocation &Loc = S.Current->getLocation(OpPC);
335
336 if (F->isVirtual()) {
337 if (!S.getLangOpts().CPlusPlus2a) {
338 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
339 return false;
340 }
341 }
342
343 if (!F->isConstexpr()) {
344 if (S.getLangOpts().CPlusPlus11) {
345 const FunctionDecl *DiagDecl = F->getDecl();
346
347 // If this function is not constexpr because it is an inherited
348 // non-constexpr constructor, diagnose that directly.
349 auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
350 if (CD && CD->isInheritingConstructor()) {
351 auto *Inherited = CD->getInheritedConstructor().getConstructor();
352 if (!Inherited->isConstexpr())
353 DiagDecl = CD = Inherited;
354 }
355
356 // FIXME: If DiagDecl is an implicitly-declared special member function
357 // or an inheriting constructor, we should be much more explicit about why
358 // it's not constexpr.
359 if (CD && CD->isInheritingConstructor())
360 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
361 << CD->getInheritedConstructor().getConstructor()->getParent();
362 else
363 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
364 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
365 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
366 } else {
367 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
368 }
369 return false;
370 }
371
372 return true;
373}
374
375bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
376 if (!This.isZero())
377 return true;
378
379 const SourceInfo &Loc = S.Current->getSource(OpPC);
380
381 bool IsImplicit = false;
382 if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
383 IsImplicit = E->isImplicit();
384
385 if (S.getLangOpts().CPlusPlus11)
386 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
387 else
388 S.FFDiag(Loc);
389
390 return false;
391}
392
393bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
394 if (!MD->isPure())
395 return true;
396 const SourceInfo &E = S.Current->getSource(OpPC);
397 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
398 S.Note(MD->getLocation(), diag::note_declared_at);
399 return false;
400}
401bool Interpret(InterpState &S, APValue &Result) {
402 CodePtr PC = S.Current->getPC();
403
404 for (;;) {
405 auto Op = PC.read<Opcode>();
406 CodePtr OpPC = PC;
407
408 switch (Op) {
409#define GET_INTERP
410#include "Opcodes.inc"
411#undef GET_INTERP
412 }
413 }
414}
415
416} // namespace interp
417} // namespace clang