1 //===--- 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
26 using namespace clang;
27 using namespace clang::interp;
28
29 //===----------------------------------------------------------------------===//
30 // Ret
31 //===----------------------------------------------------------------------===//
32
33 template <PrimType Name, class T = typename PrimConv<Name>::T>
Ret(InterpState & S,CodePtr & PC,APValue & Result)34 static 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
RetVoid(InterpState & S,CodePtr & PC,APValue & Result)56 static 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
RetValue(InterpState & S,CodePtr & Pt,APValue & Result)74 static 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
Jmp(InterpState & S,CodePtr & PC,int32_t Offset)82 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
83 PC += Offset;
84 return true;
85 }
86
Jt(InterpState & S,CodePtr & PC,int32_t Offset)87 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
88 if (S.Stk.pop<bool>()) {
89 PC += Offset;
90 }
91 return true;
92 }
93
Jf(InterpState & S,CodePtr & PC,int32_t Offset)94 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
95 if (!S.Stk.pop<bool>()) {
96 PC += Offset;
97 }
98 return true;
99 }
100
CheckInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)101 static 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
CheckActive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)112 static 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
CheckTemporary(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)144 static 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
CheckGlobal(InterpState & S,CodePtr OpPC,const Pointer & Ptr)164 static 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
178 namespace clang {
179 namespace interp {
180
CheckExtern(InterpState & S,CodePtr OpPC,const Pointer & Ptr)181 bool 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
CheckArray(InterpState & S,CodePtr OpPC,const Pointer & Ptr)194 bool 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
CheckLive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)202 bool 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
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)231 bool 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
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)240 bool 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
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)249 bool 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
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)258 bool 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
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)270 bool 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_access_mutable, 1) << AK_Read << Field;
279 S.Note(Field->getLocation(), diag::note_declared_at);
280 return false;
281 }
282
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr)283 bool 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
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)301 bool 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
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)315 bool 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
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)325 bool 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
CheckCallable(InterpState & S,CodePtr OpPC,Function * F)333 bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
334 const SourceLocation &Loc = S.Current->getLocation(OpPC);
335
336 if (F->isVirtual()) {
337 if (!S.getLangOpts().CPlusPlus20) {
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
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)375 bool 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
CheckPure(InterpState & S,CodePtr OpPC,const CXXMethodDecl * MD)393 bool 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 }
Interpret(InterpState & S,APValue & Result)401 bool 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
418