https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/184129

>From e039a5bb8998c14a838ebc9356f084062759e46b 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 |  39 +-
 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, 426 insertions(+), 293 deletions(-)

diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp 
b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index 039848f00764e..9fa63996e8ae6 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,23 @@ 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);
       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 +210,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

Reply via email to