diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/AST/Interp/Interp.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'clang/lib/AST/Interp/Interp.cpp')
-rw-r--r-- | clang/lib/AST/Interp/Interp.cpp | 93 |
1 files changed, 89 insertions, 4 deletions
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index cec3f6d6160e..6a600b306bad 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -1,4 +1,4 @@ -//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===// +//===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -201,8 +201,8 @@ bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { - const auto &Src = S.Current->getSource(OpPC); if (Ptr.isZero()) { + const auto &Src = S.Current->getSource(OpPC); if (Ptr.isField()) S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; @@ -213,6 +213,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, } if (!Ptr.isLive()) { + const auto &Src = S.Current->getSource(OpPC); bool IsTemp = Ptr.isTemporary(); S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp; @@ -330,17 +331,18 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } -bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) { - const SourceLocation &Loc = S.Current->getLocation(OpPC); +bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { if (F->isVirtual()) { if (!S.getLangOpts().CPlusPlus20) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); S.CCEDiag(Loc, diag::note_constexpr_virtual_call); return false; } } if (!F->isConstexpr()) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); if (S.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = F->getDecl(); @@ -398,9 +400,92 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) { S.Note(MD->getLocation(), diag::note_declared_at); return false; } + +static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI, + QualType SubObjType, + SourceLocation SubObjLoc) { + S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType; + if (SubObjLoc.isValid()) + S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here); +} + +static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, + const Pointer &BasePtr, const Record *R); + +static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, + const Pointer &BasePtr, + const ConstantArrayType *CAT) { + bool Result = true; + size_t NumElems = CAT->getSize().getZExtValue(); + QualType ElemType = CAT->getElementType(); + + if (isa<RecordType>(ElemType.getTypePtr())) { + const Record *R = BasePtr.getElemRecord(); + for (size_t I = 0; I != NumElems; ++I) { + Pointer ElemPtr = BasePtr.atIndex(I).narrow(); + Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R); + } + } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) { + for (size_t I = 0; I != NumElems; ++I) { + Pointer ElemPtr = BasePtr.atIndex(I).narrow(); + Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT); + } + } else { + for (size_t I = 0; I != NumElems; ++I) { + if (!BasePtr.atIndex(I).isInitialized()) { + DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType, + BasePtr.getFieldDesc()->getLocation()); + Result = false; + } + } + } + + return Result; +} + +static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, + const Pointer &BasePtr, const Record *R) { + assert(R); + bool Result = true; + // Check all fields of this record are initialized. + for (const Record::Field &F : R->fields()) { + Pointer FieldPtr = BasePtr.atField(F.Offset); + QualType FieldType = F.Decl->getType(); + + if (FieldType->isRecordType()) { + Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord()); + } else if (FieldType->isArrayType()) { + const auto *CAT = + cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe()); + Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT); + } else if (!FieldPtr.isInitialized()) { + DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), + F.Decl->getType(), F.Decl->getLocation()); + Result = false; + } + } + return Result; +} + +bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) { + assert(!This.isZero()); + const Record *R = This.getRecord(); + return CheckFieldsInitialized(S, OpPC, This, R); +} + bool Interpret(InterpState &S, APValue &Result) { + // The current stack frame when we started Interpret(). + // This is being used by the ops to determine wheter + // to return from this function and thus terminate + // interpretation. + const InterpFrame *StartFrame = S.Current; + assert(!S.Current->isRoot()); CodePtr PC = S.Current->getPC(); + // Empty program. + if (!PC) + return true; + for (;;) { auto Op = PC.read<Opcode>(); CodePtr OpPC = PC; |