https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/184129
>From 440a290eb59a9a382b77600243b8c964035eafca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Mon, 2 Mar 2026 11:33:57 +0100 Subject: [PATCH] Ptrview --- clang/lib/AST/ByteCode/EvaluationResult.cpp | 40 +- clang/lib/AST/ByteCode/Interp.cpp | 7 +- clang/lib/AST/ByteCode/Interp.h | 2 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 44 +- clang/lib/AST/ByteCode/InterpHelpers.h | 12 +- clang/lib/AST/ByteCode/Pointer.cpp | 107 ++--- clang/lib/AST/ByteCode/Pointer.h | 507 +++++++++++++------- clang/test/AST/ByteCode/cxx20.cpp | 1 - 8 files changed, 427 insertions(+), 293 deletions(-) diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp index 039848f00764e..9d12accf02232 100644 --- a/clang/lib/AST/ByteCode/EvaluationResult.cpp +++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp @@ -27,10 +27,10 @@ static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, } static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, - const Pointer &BasePtr, const Record *R); + PtrView BasePtr, const Record *R); static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, - const Pointer &BasePtr, + PtrView BasePtr, const ConstantArrayType *CAT) { size_t NumElems = CAT->getZExtSize(); @@ -43,12 +43,12 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, if (ElemType->isRecordType()) { const Record *R = BasePtr.getElemRecord(); for (size_t I = 0; I != NumElems; ++I) { - Pointer ElemPtr = BasePtr.atIndex(I).narrow(); + PtrView ElemPtr = BasePtr.atIndex(I).narrow(); Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R); } } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) { for (size_t I = 0; I != NumElems; ++I) { - Pointer ElemPtr = BasePtr.atIndex(I).narrow(); + PtrView ElemPtr = BasePtr.atIndex(I).narrow(); Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT); } } else { @@ -74,12 +74,12 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, } static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, - const Pointer &BasePtr, const Record *R) { + PtrView 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); + PtrView FieldPtr = BasePtr.atField(F.Offset); QualType FieldType = F.Decl->getType(); // Don't check inactive union members. @@ -104,7 +104,7 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, // Check Fields in all bases for (auto [I, B] : llvm::enumerate(R->bases())) { - Pointer P = BasePtr.atField(B.Offset); + PtrView P = BasePtr.atField(B.Offset); if (!P.isInitialized()) { const Descriptor *Desc = BasePtr.getDeclDesc(); if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) { @@ -122,7 +122,6 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, } // TODO: Virtual bases - return Result; } @@ -148,11 +147,11 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S, InitLoc = E->getExprLoc(); if (const Record *R = Ptr.getRecord()) - return CheckFieldsInitialized(S, InitLoc, Ptr, R); + return CheckFieldsInitialized(S, InitLoc, Ptr.view(), R); if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>( Ptr.getType()->getAsArrayTypeUnsafe())) - return CheckArrayInitialized(S, InitLoc, Ptr, CAT); + return CheckArrayInitialized(S, InitLoc, Ptr.view(), CAT); return true; } @@ -166,17 +165,16 @@ static bool isOrHasPtr(const Descriptor *D) { return false; } -static void collectBlocks(const Pointer &Ptr, - llvm::SetVector<const Block *> &Blocks) { +static void collectBlocks(PtrView Ptr, llvm::SetVector<const Block *> &Blocks) { auto isUsefulPtr = [](const Pointer &P) -> bool { return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() && P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd(); }; - if (!isUsefulPtr(Ptr)) + if (!isUsefulPtr(Pointer(Ptr))) return; - Blocks.insert(Ptr.block()); + Blocks.insert(Ptr.Pointee); const Descriptor *Desc = Ptr.getFieldDesc(); if (!Desc) @@ -187,24 +185,24 @@ static void collectBlocks(const Pointer &Ptr, for (const Record::Field &F : R->fields()) { if (!isOrHasPtr(F.Desc)) continue; - Pointer FieldPtr = Ptr.atField(F.Offset); - assert(FieldPtr.block() == Ptr.block()); + PtrView FieldPtr = Ptr.atField(F.Offset); + // assert(FieldPtr.block() == Ptr.block()); collectBlocks(FieldPtr, Blocks); } } else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) { Pointer Pointee = Ptr.deref<Pointer>(); if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block())) - collectBlocks(Pointee, Blocks); + collectBlocks(Pointee.view(), Blocks); } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) { for (unsigned I = 0; I != Desc->getNumElems(); ++I) { Pointer ElemPointee = Ptr.elem<Pointer>(I); if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block())) - collectBlocks(ElemPointee, Blocks); + collectBlocks(ElemPointee.view(), Blocks); } } else if (Desc->isCompositeArray() && isOrHasPtr(Desc->ElemDesc)) { for (unsigned I = 0; I != Desc->getNumElems(); ++I) { - Pointer ElemPtr = Ptr.atIndex(I).narrow(); + PtrView ElemPtr = Ptr.atIndex(I).narrow(); collectBlocks(ElemPtr, Blocks); } } @@ -213,11 +211,13 @@ static void collectBlocks(const Pointer &Ptr, bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr, const SourceInfo &Info) { + if (!Ptr.isBlockPointer()) + return true; // Collect all blocks that this pointer (transitively) points to and // return false if any of them is a dynamic block. llvm::SetVector<const Block *> Blocks; - collectBlocks(Ptr, Blocks); + collectBlocks(Ptr.view(), Blocks); for (const Block *B : Blocks) { if (B->isDynamic()) { diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 3b92c1858126a..de05e9e23f7c4 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -544,8 +544,7 @@ bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK) { +bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK) { if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) return true; if (S.getLangOpts().CPlusPlus) { @@ -619,14 +618,14 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; } -bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { +bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr) { assert(Ptr.isLive() && "Pointer is not live"); if (!Ptr.isMutable()) return true; // In C++14 onwards, it is permitted to read a mutable member whose // lifetime began within the evaluation. - if (S.getLangOpts().CPlusPlus14 && Ptr.block()->getEvalID() == S.EvalID) + if (S.getLangOpts().CPlusPlus14 && Ptr.getEvalID() == S.EvalID) return true; const SourceInfo &Loc = S.Current->getSource(OpPC); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 01ea334f65cd3..0585a9cdcfbad 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1095,7 +1095,7 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { } // Diagnose comparisons between fields with different access specifiers. - if (std::optional<std::pair<Pointer, Pointer>> Split = + if (std::optional<std::pair<PtrView, PtrView>> Split = Pointer::computeSplitPoint(LHS, RHS)) { const FieldDecl *LF = Split->first.getField(); const FieldDecl *RF = Split->second.getField(); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index abc746af81306..7a80a456b63c8 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -308,8 +308,8 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, if (Steps >= Limit) break; - const Pointer &PA = A.atIndex(IndexA); - const Pointer &PB = B.atIndex(IndexB); + PtrView PA = A.view().atIndex(IndexA); + PtrView PB = B.view().atIndex(IndexB); if (!CheckRange(S, OpPC, PA, AK_Read) || !CheckRange(S, OpPC, PB, AK_Read)) { return false; @@ -377,7 +377,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, size_t Len = 0; for (size_t I = StrPtr.getIndex();; ++I, ++Len) { - const Pointer &ElemPtr = StrPtr.atIndex(I); + PtrView ElemPtr = StrPtr.view().atIndex(I); if (!CheckRange(S, OpPC, ElemPtr, AK_Read)) return false; @@ -6042,8 +6042,8 @@ bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, assert(R->getNumFields() == 1); unsigned FieldOffset = R->getField(0u)->Offset; - const Pointer &FieldPtr = Ptr.atField(FieldOffset); - PrimType FieldT = *S.getContext().classify(FieldPtr.getType()); + PtrView FieldPtr = Ptr.view().atField(FieldOffset); + PrimType FieldT = FieldPtr.getFieldDesc()->getPrimType(); INT_TYPE_SWITCH(FieldT, FieldPtr.deref<T>() = T::from(IntValue.getSExtValue())); @@ -6051,7 +6051,7 @@ bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, return true; } -static void zeroAll(Pointer &Dest) { +static void zeroAll(PtrView Dest) { const Descriptor *Desc = Dest.getFieldDesc(); if (Desc->isPrimitive()) { @@ -6065,7 +6065,7 @@ static void zeroAll(Pointer &Dest) { if (Desc->isRecord()) { const Record *R = Desc->ElemRecord; for (const Record::Field &F : R->fields()) { - Pointer FieldPtr = Dest.atField(F.Offset); + PtrView FieldPtr = Dest.atField(F.Offset); zeroAll(FieldPtr); } return; @@ -6083,22 +6083,22 @@ static void zeroAll(Pointer &Dest) { if (Desc->isCompositeArray()) { for (unsigned I = 0, N = Desc->getNumElems(); I != N; ++I) { - Pointer ElemPtr = Dest.atIndex(I).narrow(); + PtrView ElemPtr = Dest.atIndex(I).narrow(); zeroAll(ElemPtr); } return; } } -static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, - Pointer &Dest, bool Activate); -static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, - Pointer &Dest, bool Activate = false) { +static bool copyComposite(InterpState &S, CodePtr OpPC, PtrView Src, + PtrView Dest, bool Activate); +static bool copyRecord(InterpState &S, CodePtr OpPC, PtrView Src, PtrView Dest, + bool Activate = false) { [[maybe_unused]] const Descriptor *SrcDesc = Src.getFieldDesc(); const Descriptor *DestDesc = Dest.getFieldDesc(); auto copyField = [&](const Record::Field &F, bool Activate) -> bool { - Pointer DestField = Dest.atField(F.Offset); + PtrView DestField = Dest.atField(F.Offset); if (OptPrimType FT = S.Ctx.classify(F.Decl->getType())) { TYPE_SWITCH(*FT, { DestField.deref<T>() = Src.atField(F.Offset).deref<T>(); @@ -6119,14 +6119,14 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, for (const Record::Field &F : R->fields()) { if (R->isUnion()) { // For unions, only copy the active field. Zero all others. - const Pointer &SrcField = Src.atField(F.Offset); + PtrView SrcField = Src.atField(F.Offset); if (SrcField.isActive()) { if (!copyField(F, /*Activate=*/true)) return false; } else { if (!CheckMutable(S, OpPC, Src.atField(F.Offset))) return false; - Pointer DestField = Dest.atField(F.Offset); + PtrView DestField = Dest.atField(F.Offset); zeroAll(DestField); } } else { @@ -6136,7 +6136,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, } for (const Record::Base &B : R->bases()) { - Pointer DestBase = Dest.atField(B.Offset); + PtrView DestBase = Dest.atField(B.Offset); if (!copyRecord(S, OpPC, Src.atField(B.Offset), DestBase, Activate)) return false; } @@ -6145,8 +6145,8 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, return true; } -static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, - Pointer &Dest, bool Activate = false) { +static bool copyComposite(InterpState &S, CodePtr OpPC, PtrView Src, + PtrView Dest, bool Activate = false) { assert(Src.isLive() && Dest.isLive()); [[maybe_unused]] const Descriptor *SrcDesc = Src.getFieldDesc(); @@ -6159,7 +6159,7 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, assert(SrcDesc->getNumElems() == DestDesc->getNumElems()); PrimType ET = DestDesc->getPrimType(); for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) { - Pointer DestElem = Dest.atIndex(I); + PtrView DestElem = Dest.atIndex(I); TYPE_SWITCH(ET, { DestElem.deref<T>() = Src.elem<T>(I); DestElem.initialize(); @@ -6172,8 +6172,8 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, assert(SrcDesc->isCompositeArray()); assert(SrcDesc->getNumElems() == DestDesc->getNumElems()); for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) { - const Pointer &SrcElem = Src.atIndex(I).narrow(); - Pointer DestElem = Dest.atIndex(I).narrow(); + PtrView SrcElem = Src.atIndex(I).narrow(); + PtrView DestElem = Dest.atIndex(I).narrow(); if (!copyComposite(S, OpPC, SrcElem, DestElem, Activate)) return false; } @@ -6191,7 +6191,7 @@ bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest) { if (!Dest.isBlockPointer() || Dest.getFieldDesc()->isPrimitive()) return false; - return copyComposite(S, OpPC, Src, Dest); + return copyComposite(S, OpPC, Src.view(), Dest.view()); } } // namespace interp diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h index 905bf1b43bfab..2e32a0e97a828 100644 --- a/clang/lib/AST/ByteCode/InterpHelpers.h +++ b/clang/lib/AST/ByteCode/InterpHelpers.h @@ -43,15 +43,21 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); /// Checks if a pointer is in range. -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); +bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK); +inline bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK) { + return CheckRange(S, OpPC, Ptr.view(), AK); +} /// Checks if a field from which a pointer is going to be derived is valid. bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); /// Checks if a pointer points to a mutable field. -bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr); +inline bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + return CheckMutable(S, OpPC, Ptr.view()); +} /// Checks if a value can be loaded from a block. bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 689407e60c542..b97fbd6f01113 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -34,7 +34,7 @@ Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset) Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset) : Offset(Offset), StorageKind(Storage::Block) { assert(Pointee); - assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + assert(Base % alignof(void *) == 0 && "wrong base"); assert(Base >= Pointee->getDescriptor()->getMetadataSize()); BS = {Pointee, Base, nullptr, nullptr}; @@ -236,7 +236,8 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { // Build the path into the object. bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray(); - Pointer Ptr = *this; + + PtrView Ptr = view(); while (Ptr.isField() || Ptr.isArrayElement()) { if (Ptr.isArrayRoot()) { @@ -380,7 +381,7 @@ size_t Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const { } size_t Result = 0; - Pointer P = *this; + PtrView P = view(); while (true) { if (P.isVirtualBaseClass()) { Result += getInlineDesc()->Offset; @@ -461,19 +462,15 @@ bool Pointer::isInitialized() const { return getInlineDesc()->IsInitialized; } -bool Pointer::isElementInitialized(unsigned Index) const { - if (!isBlockPointer()) - return true; - +bool PtrView::isElementInitialized(unsigned Index) const { const Descriptor *Desc = getFieldDesc(); assert(Desc); - if (isStatic() && BS.Base == 0) + if (Pointee->isStatic() && Base == 0) return true; - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && - Offset == BS.Base) { - const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>(); + if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) { + const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>(); return GD.InitState == GlobalInitState::Initialized; } @@ -543,15 +540,9 @@ void Pointer::endLifetime() const { getInlineDesc()->LifeState = Lifetime::Ended; } -void Pointer::initialize() const { - if (!isBlockPointer()) - return; - - assert(BS.Pointee && "Cannot initialize null pointer"); - - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && - Offset == BS.Base) { - auto &GD = BS.Pointee->getBlockDesc<GlobalInlineDescriptor>(); +void PtrView::initialize() const { + if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) { + auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>(); GD.InitState = GlobalInitState::Initialized; return; } @@ -565,13 +556,13 @@ void Pointer::initialize() const { } // Field has its bit in an inline descriptor. - assert(BS.Base != 0 && "Only composite fields can be initialised"); + assert(Base != 0 && "Only composite fields can be initialised"); getInlineDesc()->IsInitialized = true; } -void Pointer::initializeElement(unsigned Index) const { +void PtrView::initializeElement(unsigned Index) const { // Primitive global arrays don't have an initmap. - if (isStatic() && BS.Base == 0) + if (Pointee->isStatic() && Base == 0) return; assert(Index < getFieldDesc()->getNumElems()); @@ -597,16 +588,15 @@ void Pointer::initializeAllElements() const { getInitMap().noteAllInitialized(); } -bool Pointer::allElementsInitialized() const { +bool PtrView::allElementsInitialized() const { assert(getFieldDesc()->isPrimitiveArray()); assert(isArrayRoot()); - if (isStatic() && BS.Base == 0) + if (Pointee->isStatic() && Base == 0) return true; - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && - Offset == BS.Base) { - const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>(); + if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) { + const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>(); return GD.InitState == GlobalInitState::Initialized; } @@ -631,21 +621,21 @@ bool Pointer::allElementsAlive() const { return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive()); } -void Pointer::activate() const { +void PtrView::activate() const { // Field has its bit in an inline descriptor. - assert(BS.Base != 0 && "Only composite fields can be activated"); + assert(Base != 0 && "Only composite fields can be activated"); - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) + if (isRoot() && Base == sizeof(GlobalInlineDescriptor)) return; if (!getInlineDesc()->InUnion) return; - std::function<void(Pointer &)> activate; - activate = [&activate](Pointer &P) -> void { + std::function<void(PtrView P)> activate; + activate = [&activate](PtrView P) -> void { P.getInlineDesc()->IsActive = true; if (const Record *R = P.getRecord(); R && !R->isUnion()) { for (const Record::Field &F : R->fields()) { - Pointer FieldPtr = P.atField(F.Offset); + PtrView FieldPtr = P.atField(F.Offset); if (!FieldPtr.getInlineDesc()->IsActive) activate(FieldPtr); } @@ -653,13 +643,13 @@ void Pointer::activate() const { } }; - std::function<void(Pointer &)> deactivate; - deactivate = [&deactivate](Pointer &P) -> void { + std::function<void(PtrView &)> deactivate; + deactivate = [&deactivate](PtrView &P) -> void { P.getInlineDesc()->IsActive = false; if (const Record *R = P.getRecord()) { for (const Record::Field &F : R->fields()) { - Pointer FieldPtr = P.atField(F.Offset); + PtrView FieldPtr = P.atField(F.Offset); if (FieldPtr.getInlineDesc()->IsActive) deactivate(FieldPtr); } @@ -667,17 +657,17 @@ void Pointer::activate() const { } }; - Pointer B = *this; + PtrView B = *this; while (!B.isRoot() && B.inUnion()) { activate(B); // When walking up the pointer chain, deactivate // all union child pointers that aren't on our path. - Pointer Cur = B; + PtrView Cur = B; B = B.getBase(); if (const Record *BR = B.getRecord(); BR && BR->isUnion()) { for (const Record::Field &F : BR->fields()) { - Pointer FieldPtr = B.atField(F.Offset); + PtrView FieldPtr = B.atField(F.Offset); if (FieldPtr != Cur) deactivate(FieldPtr); } @@ -685,10 +675,6 @@ void Pointer::activate() const { } } -void Pointer::deactivate() const { - // TODO: this only appears in constructors, so nothing to deactivate. -} - bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { // Two null pointers always have the same base. if (A.isZero() && B.isZero()) @@ -740,7 +726,7 @@ bool Pointer::pointsToStringLiteral() const { return isa_and_nonnull<StringLiteral>(E); } -std::optional<std::pair<Pointer, Pointer>> +std::optional<std::pair<PtrView, PtrView>> Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) { if (!A.isBlockPointer() || !B.isBlockPointer()) return std::nullopt; @@ -751,20 +737,20 @@ Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) { return std::nullopt; if (A == B) - return std::make_pair(A, B); + return std::make_pair(A.view(), B.view()); - auto getBase = [](const Pointer &P) -> Pointer { + auto getBase = [](PtrView P) -> PtrView { if (P.isArrayElement()) return P.expand().getArray(); return P.getBase(); }; - Pointer IterA = A; - Pointer IterB = B; - Pointer CurA = IterA; - Pointer CurB = IterB; + PtrView IterA = A.view(); + PtrView IterB = B.view(); + PtrView CurA = IterA; + PtrView CurB = IterB; for (;;) { - if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) { + if (IterA.Base > IterB.Base) { CurA = IterA; IterA = getBase(IterA); } else { @@ -787,15 +773,14 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const ASTContext &ASTCtx = Ctx.getASTContext(); assert(!ResultType.isNull()); // Method to recursively traverse composites. - std::function<bool(QualType, const Pointer &, APValue &)> Composite; - Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr, + std::function<bool(QualType, PtrView, APValue &)> Composite; + Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, PtrView Ptr, APValue &R) { if (const auto *AT = Ty->getAs<AtomicType>()) Ty = AT->getValueType(); // Invalid pointers. - if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || - Ptr.isPastEnd()) + if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd()) return false; // Primitives should never end up here. @@ -810,7 +795,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const FieldDecl *ActiveField = nullptr; APValue Value; for (const auto &F : Record->fields()) { - const Pointer &FP = Ptr.atField(F.Offset); + PtrView FP = Ptr.atField(F.Offset); if (FP.isActive()) { const Descriptor *Desc = F.Desc; if (Desc->isPrimitive()) { @@ -835,7 +820,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I != NF; ++I) { const Record::Field *FD = Record->getField(I); const Descriptor *Desc = FD->Desc; - const Pointer &FP = Ptr.atField(FD->Offset); + PtrView FP = Ptr.atField(FD->Offset); APValue &Value = R.getStructField(I); if (Desc->isPrimitive()) { TYPE_SWITCH(Desc->getPrimType(), @@ -849,7 +834,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I != NB; ++I) { const Record::Base *BD = Record->getBase(I); QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl); - const Pointer &BP = Ptr.atField(BD->Offset); + PtrView BP = Ptr.atField(BD->Offset); Ok &= Composite(BaseTy, BP, R.getStructBase(I)); } @@ -857,7 +842,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const Record::Base *VD = Record->getVirtualBase(I); QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(VD->Decl); - const Pointer &VP = Ptr.atField(VD->Offset); + PtrView VP = Ptr.atField(VD->Offset); Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); } } @@ -971,7 +956,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, // Return the composite type. APValue Result; - if (!Composite(ResultType, *this, Result)) + if (!Composite(ResultType, view(), Result)) return std::nullopt; return Result; } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index ea9c7d4cb04db..993ed62b616dc 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -33,6 +33,262 @@ class Context; class Pointer; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); +struct PtrView { + static constexpr unsigned PastEndMark = ~0u; + + Block *Pointee; + unsigned Base; + uint64_t Offset; + + bool isZero() const { return !Pointee; } + bool isLive() const { return Pointee && !Pointee->isDead(); } + bool isDummy() const { return Pointee && Pointee->isDummy(); } + bool isActive() const { return isRoot() || getInlineDesc()->IsActive; } + bool isArrayRoot() const { return inArray() && Offset == Base; } + bool isElementPastEnd() const { return Offset == PastEndMark; } + bool isZeroSizeArray() const { return getFieldDesc()->isZeroSizeArray(); } + bool isMutable() const { + return !isRoot() && getInlineDesc()->IsFieldMutable; + } + bool inUnion() const { return getInlineDesc()->InUnion; }; + bool inArray() const { return getFieldDesc()->IsArray; } + bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } + + unsigned getEvalID() { return Pointee->getEvalID(); } + + bool isRoot() const { + return Base == Pointee->getDescriptor()->getMetadataSize(); + } + + InlineDescriptor *getInlineDesc() const { + assert(Base != sizeof(GlobalInlineDescriptor)); + assert(Base <= Pointee->getSize()); + assert(Base >= sizeof(InlineDescriptor)); + return getDescriptor(Base); + } + + InlineDescriptor *getDescriptor(unsigned Offset) const { + assert(Offset != 0 && "Not a nested pointer"); + return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) - + 1; + } + + const Descriptor *getFieldDesc() const { + if (isRoot()) + return Pointee->getDescriptor(); + return getInlineDesc()->Desc; + } + + const Descriptor *getDeclDesc() const { return Pointee->getDescriptor(); } + + size_t elemSize() const { return getFieldDesc()->getElemSize(); } + + [[nodiscard]] PtrView narrow() const { + // Null pointers cannot be narrowed. + if (isZero() || isUnknownSizeArray()) + return *this; + + if (inArray()) { + // Pointer is one past end - magic offset marks that. + if (isOnePastEnd()) + return PtrView{Pointee, Base, PastEndMark}; + + if (Offset != Base) { + // If we're pointing to a primitive array element, there's nothing to + // do. + if (inPrimitiveArray()) + return *this; + // Pointer is to a composite array element - enter it. + return PtrView{Pointee, static_cast<unsigned>(Offset), Offset}; + } + } + // Otherwise, we're pointing to a non-array element or + // are already narrowed to a composite array element. Nothing to do. + return *this; + } + + [[nodiscard]] PtrView expand() const { + if (isElementPastEnd()) { + // Revert to an outer one-past-end pointer. + unsigned Adjust; + if (inPrimitiveArray()) + Adjust = sizeof(InitMapPtr); + else + Adjust = sizeof(InlineDescriptor); + return PtrView{Pointee, Base, Base + getSize() + Adjust}; + } + + // Do not step out of array elements. + if (Base != Offset) + return *this; + + if (isRoot()) + return PtrView{Pointee, Base, Base}; + + // Step into the containing array, if inside one. + unsigned Next = Base - getInlineDesc()->Offset; + const Descriptor *Desc = + (Next == Pointee->getDescriptor()->getMetadataSize()) + ? getDeclDesc() + : getDescriptor(Next)->Desc; + if (!Desc->IsArray) + return *this; + return PtrView{Pointee, Next, Offset}; + } + + [[nodiscard]] PtrView getArray() const { + assert(Offset != Base && "not an array element"); + return PtrView{Pointee, Base, Base}; + } + + const Record *getRecord() const { return getFieldDesc()->ElemRecord; } + const Record *getElemRecord() const { + const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; + return ElemDesc ? ElemDesc->ElemRecord : nullptr; + } + const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } + + bool isField() const { + return !isZero() && !isRoot() && getFieldDesc()->asDecl(); + } + + bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } + bool isVirtualBaseClass() const { + return isField() && getInlineDesc()->IsVirtualBase; + } + bool isUnknownSizeArray() const { + return getFieldDesc()->isUnknownSizeArray(); + } + + bool isPastEnd() const { return Offset > Pointee->getSize(); } + + unsigned getOffset() const { + assert(Offset != PastEndMark); + + unsigned Adjust = 0; + if (Offset != Base) { + if (getFieldDesc()->ElemDesc) + Adjust = sizeof(InlineDescriptor); + else + Adjust = sizeof(InitMapPtr); + } + return Offset - Base - Adjust; + } + size_t getSize() const { return getFieldDesc()->getSize(); } + + bool isOnePastEnd() const { + if (!Pointee) + return false; + + if (isUnknownSizeArray()) + return false; + return isPastEnd() || (getSize() == getOffset()); + } + + PtrView atIndex(unsigned Idx) const { + unsigned Off = Idx * elemSize(); + if (getFieldDesc()->ElemDesc) + Off += sizeof(InlineDescriptor); + else + Off += sizeof(InitMapPtr); + return PtrView{Pointee, Base, Base + Off}; + } + + int64_t getIndex() const { + if (isZero()) + return 0; + // narrow()ed element in a composite array. + if (Base > sizeof(InlineDescriptor) && Base == Offset) + return 0; + + if (auto ElemSize = elemSize()) + return getOffset() / ElemSize; + return 0; + } + + unsigned getNumElems() const { return getSize() / elemSize(); } + + bool isArrayElement() const { + if (inArray() && Base != Offset) + return true; + + // Might be a narrow()'ed element in a composite array. + // Check the inline descriptor. + if (Base >= sizeof(InlineDescriptor) && getInlineDesc()->IsArrayElement) + return true; + + return false; + } + + template <typename T> T &deref() const { + assert(isLive() && "Invalid pointer"); + assert(Pointee); + + if (isArrayRoot()) + return *reinterpret_cast<T *>(Pointee->rawData() + Base + + sizeof(InitMapPtr)); + + return *reinterpret_cast<T *>(Pointee->rawData() + Offset); + } + + template <typename T> T &elem(unsigned I) const { + assert(isLive() && "Invalid pointer"); + assert(Pointee); + assert(getFieldDesc()->isPrimitiveArray()); + assert(I < getFieldDesc()->getNumElems()); + + unsigned ElemByteOffset = I * getFieldDesc()->getElemSize(); + unsigned ReadOffset = Base + sizeof(InitMapPtr) + ElemByteOffset; + assert(ReadOffset + sizeof(T) <= Pointee->getDescriptor()->getAllocSize()); + + return *reinterpret_cast<T *>(Pointee->rawData() + ReadOffset); + } + + [[nodiscard]] PtrView getBase() const { + unsigned NewBase = Base - getInlineDesc()->Offset; + return PtrView{Pointee, NewBase, NewBase}; + } + + [[nodiscard]] PtrView atField(unsigned Offset) const { + unsigned F = this->Offset + Offset; + return PtrView{Pointee, F, F}; + } + + bool isInitialized() const { + if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) { + const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>(); + return GD.InitState == GlobalInitState::Initialized; + } + + assert(Pointee && "Cannot check if null pointer was initialized"); + const Descriptor *Desc = getFieldDesc(); + assert(Desc); + if (Desc->isPrimitiveArray()) + return isElementInitialized(getIndex()); + + if (Base == 0) + return true; + // Field has its bit in an inline descriptor. + return getInlineDesc()->IsInitialized; + } + + void initializeElement(unsigned Index) const; + bool allElementsInitialized() const; + bool isElementInitialized(unsigned Index) const; + InitMapPtr &getInitMap() const { + return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base); + } + void initialize() const; + void activate() const; + + bool operator==(const PtrView &Other) const { + return Other.Pointee == Pointee && Base == Other.Base && + Offset == Other.Offset; + } + + bool operator!=(const PtrView &Other) const { return !(Other == *this); } +}; + struct BlockPointer { /// The block the pointer is pointing to. Block *Pointee; @@ -95,10 +351,6 @@ enum class Storage { Int, Block, Fn, Typeid }; /// Base /// \endverbatim class Pointer { -private: - static constexpr unsigned PastEndMark = ~0u; - static constexpr unsigned RootPtrMark = ~0u; - public: Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {} Pointer(IntPointer &&IntPtr) @@ -116,7 +368,9 @@ class Pointer { Typeid.TypePtr = TypePtr; Typeid.TypeInfoType = TypeInfoType; } + Pointer(Block *Pointee, unsigned Base, uint64_t Offset); + explicit Pointer(PtrView V) : Pointer(V.Pointee, V.Base, V.Offset) {} ~Pointer(); Pointer &operator=(const Pointer &P); @@ -133,9 +387,7 @@ class Pointer { if (isFunctionPointer()) return P.Fn.Func == Fn.Func && P.Offset == Offset; - assert(isBlockPointer()); - return P.BS.Pointee == BS.Pointee && P.BS.Base == BS.Base && - P.Offset == Offset; + return P.view() == view(); } bool operator!=(const Pointer &P) const { return !(P == *this); } @@ -154,6 +406,11 @@ class Pointer { return reinterpret_cast<uint64_t>(BS.Pointee) + Offset; } + PtrView view() const { + assert(isBlockPointer()); + return PtrView{BS.Pointee, BS.Base, Offset}; + } + /// Converts the pointer to an APValue that is an rvalue. std::optional<APValue> toRValue(const Context &Ctx, QualType ResultType) const; @@ -165,21 +422,12 @@ class Pointer { if (isFunctionPointer()) return Pointer(Fn.Func, Idx); - if (BS.Base == RootPtrMark) - return Pointer(BS.Pointee, RootPtrMark, getDeclDesc()->getSize()); - uint64_t Off = Idx * elemSize(); - if (getFieldDesc()->ElemDesc) - Off += sizeof(InlineDescriptor); - else - Off += sizeof(InitMapPtr); - return Pointer(BS.Pointee, BS.Base, BS.Base + Off); + return Pointer(view().atIndex(Idx)); } /// Creates a pointer to a field. [[nodiscard]] Pointer atField(unsigned Off) const { - assert(isBlockPointer()); - unsigned Field = Offset + Off; - return Pointer(BS.Pointee, Field, Field); + return Pointer(view().atField(Off)); } /// Subtract the given offset from the current Base and Offset @@ -194,70 +442,14 @@ class Pointer { [[nodiscard]] Pointer narrow() const { if (!isBlockPointer()) return *this; - assert(isBlockPointer()); - // Null pointers cannot be narrowed. - if (isZero() || isUnknownSizeArray()) - return *this; - - unsigned Base = BS.Base; - // Pointer to an array of base types - enter block. - if (Base == RootPtrMark) - return Pointer(BS.Pointee, sizeof(InlineDescriptor), - Offset == 0 ? Offset : PastEndMark); - - if (inArray()) { - // Pointer is one past end - magic offset marks that. - if (isOnePastEnd()) - return Pointer(BS.Pointee, Base, PastEndMark); - - if (Offset != Base) { - // If we're pointing to a primitive array element, there's nothing to - // do. - if (inPrimitiveArray()) - return *this; - // Pointer is to a composite array element - enter it. - return Pointer(BS.Pointee, Offset, Offset); - } - } - - // Otherwise, we're pointing to a non-array element or - // are already narrowed to a composite array element. Nothing to do. - return *this; + return Pointer(view().narrow()); } /// Expands a pointer to the containing array, undoing narrowing. [[nodiscard]] Pointer expand() const { if (!isBlockPointer()) return *this; - assert(isBlockPointer()); - Block *Pointee = BS.Pointee; - - if (isElementPastEnd()) { - // Revert to an outer one-past-end pointer. - unsigned Adjust; - if (inPrimitiveArray()) - Adjust = sizeof(InitMapPtr); - else - Adjust = sizeof(InlineDescriptor); - return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust); - } - - // Do not step out of array elements. - if (BS.Base != Offset) - return *this; - - if (isRoot()) - return Pointer(Pointee, BS.Base, BS.Base); - - // Step into the containing array, if inside one. - unsigned Next = BS.Base - getInlineDesc()->Offset; - const Descriptor *Desc = - (Next == Pointee->getDescriptor()->getMetadataSize()) - ? getDeclDesc() - : getDescriptor(Next)->Desc; - if (!Desc->IsArray) - return *this; - return Pointer(Pointee, Next, Offset); + return Pointer(view().expand()); } /// Checks if the pointer is null. @@ -278,14 +470,14 @@ class Pointer { bool isLive() const { if (!isBlockPointer()) return true; - return BS.Pointee && !BS.Pointee->isDead(); + return view().isLive(); } /// Checks if the item is a field in an object. bool isField() const { if (!isBlockPointer()) return false; - return !isRoot() && getFieldDesc()->asDecl(); + return view().isField(); } /// Accessor for information about the declaration site. @@ -314,23 +506,9 @@ class Pointer { } /// Returns a pointer to the object of which this pointer is a field. - [[nodiscard]] Pointer getBase() const { - if (BS.Base == RootPtrMark) { - assert(Offset == PastEndMark && "cannot get base of a block"); - return Pointer(BS.Pointee, BS.Base, 0); - } - unsigned NewBase = BS.Base - getInlineDesc()->Offset; - return Pointer(BS.Pointee, NewBase, NewBase); - } + [[nodiscard]] Pointer getBase() const { return Pointer(view().getBase()); } /// Returns the parent array. - [[nodiscard]] Pointer getArray() const { - if (BS.Base == RootPtrMark) { - assert(Offset != 0 && Offset != PastEndMark && "not an array element"); - return Pointer(BS.Pointee, BS.Base, 0); - } - assert(Offset != BS.Base && "not an array element"); - return Pointer(BS.Pointee, BS.Base, BS.Base); - } + [[nodiscard]] Pointer getArray() const { return Pointer(view().getArray()); } /// Accessors for information about the innermost field. const Descriptor *getFieldDesc() const { @@ -373,9 +551,7 @@ class Pointer { return Int.Desc->getElemSize(); } - if (BS.Base == RootPtrMark) - return getDeclDesc()->getSize(); - return getFieldDesc()->getElemSize(); + return view().elemSize(); } /// Returns the total size of the innermost field. size_t getSize() const { @@ -385,41 +561,30 @@ class Pointer { /// Returns the offset into an array. unsigned getOffset() const { - assert(Offset != PastEndMark && "invalid offset"); - assert(isBlockPointer()); - if (BS.Base == RootPtrMark) - return Offset; - - unsigned Adjust = 0; - if (Offset != BS.Base) { - if (getFieldDesc()->ElemDesc) - Adjust = sizeof(InlineDescriptor); - else - Adjust = sizeof(InitMapPtr); - } - return Offset - BS.Base - Adjust; + assert(Offset != PtrView::PastEndMark && "invalid offset"); + return view().getOffset(); } /// Whether this array refers to an array, but not /// to the first element. - bool isArrayRoot() const { return inArray() && Offset == BS.Base; } + bool isArrayRoot() const { return view().isArrayRoot(); } /// Checks if the innermost field is an array. bool inArray() const { if (isBlockPointer()) - return getFieldDesc()->IsArray; + return view().inArray(); return false; } bool inUnion() const { if (isBlockPointer() && BS.Base >= sizeof(InlineDescriptor)) - return getInlineDesc()->InUnion; + return view().inUnion(); return false; }; /// Checks if the structure is a primitive array. bool inPrimitiveArray() const { if (isBlockPointer()) - return getFieldDesc()->isPrimitiveArray(); + return view().inPrimitiveArray(); return false; } /// Checks if the structure is an array of unknown size. @@ -433,23 +598,13 @@ class Pointer { if (!isBlockPointer()) return false; - const BlockPointer &BP = BS; - if (inArray() && BP.Base != Offset) - return true; - - // Might be a narrow()'ed element in a composite array. - // Check the inline descriptor. - if (BP.Base >= sizeof(InlineDescriptor) && getInlineDesc()->IsArrayElement) - return true; - - return false; + return view().isArrayElement(); } /// Pointer points directly to a block. bool isRoot() const { if (isZero() || !isBlockPointer()) return true; - return (BS.Base == BS.Pointee->getDescriptor()->getMetadataSize() || - BS.Base == 0); + return view().isRoot(); } /// If this pointer has an InlineDescriptor we can use to initialize. bool canBeInitialized() const { @@ -482,12 +637,9 @@ class Pointer { bool isTypeidPointer() const { return StorageKind == Storage::Typeid; } /// Returns the record descriptor of a class. - const Record *getRecord() const { return getFieldDesc()->ElemRecord; } + const Record *getRecord() const { return view().getRecord(); } /// Returns the element record type, if this is a non-primive array. - const Record *getElemRecord() const { - const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; - return ElemDesc ? ElemDesc->ElemRecord : nullptr; - } + const Record *getElemRecord() const { return view().getElemRecord(); } /// Returns the field information. const FieldDecl *getField() const { if (const Descriptor *FD = getFieldDesc()) @@ -531,7 +683,7 @@ class Pointer { bool isMutable() const { if (!isBlockPointer()) return false; - return !isRoot() && getInlineDesc()->IsFieldMutable; + return view().isMutable(); } bool isWeak() const { @@ -551,21 +703,17 @@ class Pointer { bool isActive() const { if (!isBlockPointer()) return true; - return isRoot() || getInlineDesc()->IsActive; + return view().isActive(); } /// Checks if a structure is a base class. - bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } - bool isVirtualBaseClass() const { - return isField() && getInlineDesc()->IsVirtualBase; - } + bool isBaseClass() const { return view().isBaseClass(); } + bool isVirtualBaseClass() const { return view().isVirtualBaseClass(); } + /// Checks if the pointer points to a dummy value. bool isDummy() const { if (!isBlockPointer()) return false; - - if (const Block *Pointee = BS.Pointee) - return Pointee->isDummy(); - return false; + return view().isDummy(); } /// Checks if an object or a subfield is mutable. @@ -603,7 +751,7 @@ class Pointer { if (isTypeidPointer()) return reinterpret_cast<uintptr_t>(Typeid.TypePtr) + Offset; if (isOnePastEnd()) - return PastEndMark; + return PtrView::PastEndMark; return Offset; } @@ -611,7 +759,7 @@ class Pointer { unsigned getNumElems() const { if (!isBlockPointer()) return ~0u; - return getSize() / elemSize(); + return view().getNumElems(); } const Block *block() const { return BS.Pointee; } @@ -628,16 +776,7 @@ class Pointer { if (!isBlockPointer()) return getIntegerRepresentation(); - if (isZero()) - return 0; - - // narrow()ed element in a composite array. - if (BS.Base > sizeof(InlineDescriptor) && BS.Base == Offset) - return 0; - - if (auto ElemSize = elemSize()) - return getOffset() / ElemSize; - return 0; + return view().getIndex(); } /// Checks if the index is one past end. @@ -663,7 +802,7 @@ class Pointer { } /// Checks if the pointer is an out-of-bounds element pointer. - bool isElementPastEnd() const { return Offset == PastEndMark; } + bool isElementPastEnd() const { return Offset == PtrView::PastEndMark; } /// Checks if the pointer is pointing to a zero-size array. bool isZeroSizeArray() const { @@ -691,11 +830,7 @@ class Pointer { assert(isDereferencable()); assert(Offset + sizeof(T) <= BS.Pointee->getDescriptor()->getAllocSize()); - if (isArrayRoot()) - return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base + - sizeof(InitMapPtr)); - - return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset); + return view().deref<T>(); } /// Dereferences the element at index \p I. @@ -708,12 +843,7 @@ class Pointer { assert(getFieldDesc()->isPrimitiveArray()); assert(I < getFieldDesc()->getNumElems()); - unsigned ElemByteOffset = I * getFieldDesc()->getElemSize(); - unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset; - assert(ReadOffset + sizeof(T) <= - BS.Pointee->getDescriptor()->getAllocSize()); - - return *reinterpret_cast<T *>(BS.Pointee->rawData() + ReadOffset); + return view().elem<T>(I); } /// Whether this block can be read from at all. This is only true for @@ -728,9 +858,15 @@ class Pointer { } /// Initializes a field. - void initialize() const; + void initialize() const { + if (!isBlockPointer()) + return; + view().initialize(); + } /// Initialized the given element of a primitive array. - void initializeElement(unsigned Index) const; + void initializeElement(unsigned Index) const { + view().initializeElement(Index); + } /// Initialize all elements of a primitive array at once. This can be /// used in situations where we *know* we have initialized *all* elements /// of a primtive array. @@ -738,15 +874,26 @@ class Pointer { /// Checks if an object was initialized. bool isInitialized() const; /// Like isInitialized(), but for primitive arrays. - bool isElementInitialized(unsigned Index) const; - bool allElementsInitialized() const; + bool isElementInitialized(unsigned Index) const { + if (!isBlockPointer()) + return true; + + return view().isElementInitialized(Index); + } + bool allElementsInitialized() const { + assert(getFieldDesc()->isPrimitiveArray()); + assert(isArrayRoot()); + return view().allElementsInitialized(); + } bool allElementsAlive() const; bool isElementAlive(unsigned Index) const; - /// Activats a field. - void activate() const; + /// Activates a field. + void activate() const { view().activate(); } /// Deactivates an entire strurcutre. - void deactivate() const; + void deactivate() const { + // TODO: this only appears in constructors, so nothing to deactivate. + } Lifetime getLifetime() const { if (!isBlockPointer()) @@ -784,10 +931,10 @@ class Pointer { /// The result is either a root pointer or something /// that isn't a base class anymore. [[nodiscard]] Pointer stripBaseCasts() const { - Pointer P = *this; - while (P.isBaseClass()) - P = P.getBase(); - return P; + PtrView V = view(); + while (V.isBaseClass()) + V = V.getBase(); + return Pointer(V); } /// Compare two pointers. @@ -810,7 +957,7 @@ class Pointer { /// Checks if both given pointers point to the same block. static bool pointToSameBlock(const Pointer &A, const Pointer &B); - static std::optional<std::pair<Pointer, Pointer>> + static std::optional<std::pair<PtrView, PtrView>> computeSplitPoint(const Pointer &A, const Pointer &B); /// Whether this points to a block that's been created for a "literal lvalue", @@ -848,16 +995,14 @@ class Pointer { assert(Offset != 0 && "Not a nested pointer"); assert(isBlockPointer()); assert(!isZero()); - return reinterpret_cast<InlineDescriptor *>(BS.Pointee->rawData() + - Offset) - - 1; + return view().getDescriptor(Offset); } /// Returns a reference to the InitMapPtr which stores the initialization map. InitMapPtr &getInitMap() const { assert(isBlockPointer()); assert(!isZero()); - return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base); + return view().getInitMap(); } /// Offset into the storage. diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index 9800fe01fcaf5..4d8f7cbcb5838 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -1306,7 +1306,6 @@ namespace PointerCmp { } namespace ExpandOnOPTEPointers { - template <class _BidirectionalIterator> constexpr void inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
