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
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 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
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)232 bool 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
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)241 bool 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
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)250 bool 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
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)259 bool 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
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)271 bool 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
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr)284 bool 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
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)302 bool 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
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)316 bool 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
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)326 bool 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
CheckCallable(InterpState & S,CodePtr OpPC,const Function * F)334 bool 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
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)377 bool 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
CheckPure(InterpState & S,CodePtr OpPC,const CXXMethodDecl * MD)395 bool 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
DiagnoseUninitializedSubobject(InterpState & S,const SourceInfo & SI,QualType SubObjType,SourceLocation SubObjLoc)404 static 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
412 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
413 const Pointer &BasePtr, const Record *R);
414
CheckArrayInitialized(InterpState & S,CodePtr OpPC,const Pointer & BasePtr,const ConstantArrayType * CAT)415 static 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
CheckFieldsInitialized(InterpState & S,CodePtr OpPC,const Pointer & BasePtr,const Record * R)446 static 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
CheckCtorCall(InterpState & S,CodePtr OpPC,const Pointer & This)470 bool 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
Interpret(InterpState & S,APValue & Result)476 bool 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