1 //===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
13 #include "InterpFrame.h"
14 #include "InterpStack.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"
26 using namespace clang;
27 using namespace clang::interp;
29 static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
30 llvm::report_fatal_error("Interpreter cannot return values");
33 //===----------------------------------------------------------------------===//
35 //===----------------------------------------------------------------------===//
37 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
42 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
43 if (S.Stk.pop<bool>()) {
49 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
50 if (!S.Stk.pop<bool>()) {
56 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
61 // Get the inactive field descriptor.
62 const FieldDecl *InactiveField = Ptr.getField();
64 // Walk up the pointer chain to find the union which is not active.
65 Pointer U = Ptr.getBase();
66 while (!U.isActive()) {
70 // Find the active field of the union.
71 const Record *R = U.getRecord();
72 assert(R && R->isUnion() && "Not a union");
73 const FieldDecl *ActiveField = nullptr;
74 for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
75 const Pointer &Field = U.atField(R->getField(I)->Offset);
76 if (Field.isActive()) {
77 ActiveField = Field.getField();
82 const SourceInfo &Loc = S.Current->getSource(OpPC);
83 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
84 << AK << InactiveField << !ActiveField << ActiveField;
88 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
90 if (auto ID = Ptr.getDeclID()) {
91 if (!Ptr.isStaticTemporary())
94 if (Ptr.getDeclDesc()->getType().isConstQualified())
97 if (S.P.getCurrentDecl() == ID)
100 const SourceInfo &E = S.Current->getSource(OpPC);
101 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
102 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
108 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
109 if (auto ID = Ptr.getDeclID()) {
113 if (S.P.getCurrentDecl() == ID)
116 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
125 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
129 if (!S.checkingPotentialConstantExpression()) {
130 const auto *VD = Ptr.getDeclDesc()->asValueDecl();
131 const SourceInfo &Loc = S.Current->getSource(OpPC);
132 S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
133 S.Note(VD->getLocation(), diag::note_declared_at);
138 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
139 if (!Ptr.isUnknownSizeArray())
141 const SourceInfo &E = S.Current->getSource(OpPC);
142 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
146 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
149 const auto &Src = S.Current->getSource(OpPC);
152 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
154 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
160 const auto &Src = S.Current->getSource(OpPC);
161 bool IsTemp = Ptr.isTemporary();
163 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
166 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
168 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
176 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
177 CheckSubobjectKind CSK) {
180 const SourceInfo &Loc = S.Current->getSource(OpPC);
181 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
185 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
187 if (!Ptr.isOnePastEnd())
189 const SourceInfo &Loc = S.Current->getSource(OpPC);
190 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
194 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
195 CheckSubobjectKind CSK) {
196 if (!Ptr.isElementPastEnd())
198 const SourceInfo &Loc = S.Current->getSource(OpPC);
199 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
203 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
204 assert(Ptr.isLive() && "Pointer is not live");
208 // The This pointer is writable in constructors and destructors,
209 // even if isConst() returns true.
210 if (const Function *Func = S.Current->getFunction();
211 Func && (Func->isConstructor() || Func->isDestructor()) &&
212 Ptr.block() == S.Current->getThis().block()) {
216 const QualType Ty = Ptr.getType();
217 const SourceInfo &Loc = S.Current->getSource(OpPC);
218 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
222 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
223 assert(Ptr.isLive() && "Pointer is not live");
224 if (!Ptr.isMutable()) {
228 const SourceInfo &Loc = S.Current->getSource(OpPC);
229 const FieldDecl *Field = Ptr.getField();
230 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
231 S.Note(Field->getLocation(), diag::note_declared_at);
235 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
237 if (Ptr.isInitialized())
240 if (!S.checkingPotentialConstantExpression()) {
241 const SourceInfo &Loc = S.Current->getSource(OpPC);
242 S.FFDiag(Loc, diag::note_constexpr_access_uninit)
243 << AK << /*uninitialized=*/true;
248 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
249 if (!CheckLive(S, OpPC, Ptr, AK_Read))
251 if (!CheckExtern(S, OpPC, Ptr))
253 if (!CheckRange(S, OpPC, Ptr, AK_Read))
255 if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
257 if (!CheckActive(S, OpPC, Ptr, AK_Read))
259 if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
261 if (!CheckMutable(S, OpPC, Ptr))
266 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
267 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
269 if (!CheckExtern(S, OpPC, Ptr))
271 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
273 if (!CheckGlobal(S, OpPC, Ptr))
275 if (!CheckConst(S, OpPC, Ptr))
280 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
281 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
283 if (!CheckExtern(S, OpPC, Ptr))
285 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
290 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
291 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
293 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
298 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
300 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
301 const SourceLocation &Loc = S.Current->getLocation(OpPC);
302 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
306 if (!F->isConstexpr()) {
307 // Don't emit anything if we're checking for a potential constant
308 // expression. That will happen later when actually executing.
309 if (S.checkingPotentialConstantExpression())
312 const SourceLocation &Loc = S.Current->getLocation(OpPC);
313 if (S.getLangOpts().CPlusPlus11) {
314 const FunctionDecl *DiagDecl = F->getDecl();
316 // If this function is not constexpr because it is an inherited
317 // non-constexpr constructor, diagnose that directly.
318 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
319 if (CD && CD->isInheritingConstructor()) {
320 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
321 if (!Inherited->isConstexpr())
322 DiagDecl = CD = Inherited;
325 // FIXME: If DiagDecl is an implicitly-declared special member function
326 // or an inheriting constructor, we should be much more explicit about why
327 // it's not constexpr.
328 if (CD && CD->isInheritingConstructor())
329 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
330 << CD->getInheritedConstructor().getConstructor()->getParent();
332 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
333 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
334 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
336 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
344 bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
345 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
346 S.FFDiag(S.Current->getSource(OpPC),
347 diag::note_constexpr_depth_limit_exceeded)
348 << S.getLangOpts().ConstexprCallDepth;
355 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
359 const SourceInfo &Loc = S.Current->getSource(OpPC);
361 bool IsImplicit = false;
362 if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))
363 IsImplicit = E->isImplicit();
365 if (S.getLangOpts().CPlusPlus11)
366 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
373 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
376 const SourceInfo &E = S.Current->getSource(OpPC);
377 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
378 S.Note(MD->getLocation(), diag::note_declared_at);
382 static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
383 const FieldDecl *SubObjDecl) {
384 assert(SubObjDecl && "Subobject declaration does not exist");
385 S.FFDiag(SI, diag::note_constexpr_uninitialized)
386 << /*(name)*/ 1 << SubObjDecl;
387 S.Note(SubObjDecl->getLocation(),
388 diag::note_constexpr_subobject_declared_here);
391 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
392 const Pointer &BasePtr, const Record *R);
394 static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
395 const Pointer &BasePtr,
396 const ConstantArrayType *CAT) {
398 size_t NumElems = CAT->getSize().getZExtValue();
399 QualType ElemType = CAT->getElementType();
401 if (ElemType->isRecordType()) {
402 const Record *R = BasePtr.getElemRecord();
403 for (size_t I = 0; I != NumElems; ++I) {
404 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
405 Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
407 } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
408 for (size_t I = 0; I != NumElems; ++I) {
409 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
410 Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
413 for (size_t I = 0; I != NumElems; ++I) {
414 if (!BasePtr.atIndex(I).isInitialized()) {
415 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
425 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
426 const Pointer &BasePtr, const Record *R) {
429 // Check all fields of this record are initialized.
430 for (const Record::Field &F : R->fields()) {
431 Pointer FieldPtr = BasePtr.atField(F.Offset);
432 QualType FieldType = F.Decl->getType();
434 if (FieldType->isRecordType()) {
435 Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
436 } else if (FieldType->isArrayType()) {
438 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
439 Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
440 } else if (!FieldPtr.isInitialized()) {
441 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), F.Decl);
446 // Check Fields in all bases
447 for (const Record::Base &B : R->bases()) {
448 Pointer P = BasePtr.atField(B.Offset);
449 Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
452 // TODO: Virtual bases
457 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
458 assert(!This.isZero());
459 if (const Record *R = This.getRecord())
460 return CheckFieldsInitialized(S, OpPC, This, R);
462 cast<ConstantArrayType>(This.getType()->getAsArrayTypeUnsafe());
463 return CheckArrayInitialized(S, OpPC, This, CAT);
466 bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
467 // In a constant context, assume that any dynamic rounding mode or FP
468 // exception state matches the default floating-point environment.
469 if (S.inConstantContext())
472 const SourceInfo &E = S.Current->getSource(OpPC);
473 FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
475 if ((Status & APFloat::opInexact) &&
476 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
477 // Inexact result means that it depends on rounding mode. If the requested
478 // mode is dynamic, the evaluation cannot be made in compile time.
479 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
483 if ((Status != APFloat::opOK) &&
484 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
485 FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
486 FPO.getAllowFEnvAccess())) {
487 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
491 if ((Status & APFloat::opStatus::opInvalidOp) &&
492 FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
493 // There is no usefully definable result.
501 bool Interpret(InterpState &S, APValue &Result) {
502 // The current stack frame when we started Interpret().
503 // This is being used by the ops to determine wheter
504 // to return from this function and thus terminate
506 const InterpFrame *StartFrame = S.Current;
507 assert(!S.Current->isRoot());
508 CodePtr PC = S.Current->getPC();
515 auto Op = PC.read<Opcode>();
520 #include "Opcodes.inc"
526 } // namespace interp