[llvm-branch-commits] [clang] 6f76a8f - Revert "[clang][bytecode] Use opaque pointers for decl-based dummy pointers (…"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Sep 10 03:39:20 PDT 2026


Author: Timm Baeder
Date: 2026-09-10T12:39:15+02:00
New Revision: 6f76a8fa4a2961be199aeebb645d3261caa1aba0

URL: https://github.com/llvm/llvm-project/commit/6f76a8fa4a2961be199aeebb645d3261caa1aba0
DIFF: https://github.com/llvm/llvm-project/commit/6f76a8fa4a2961be199aeebb645d3261caa1aba0.diff

LOG: Revert "[clang][bytecode] Use opaque pointers for decl-based dummy pointers (…"

This reverts commit a9f7095c26175f363282ed2cdfb52acada3c2d93.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/lib/AST/ByteCode/InterpHelpers.h
    clang/lib/AST/ByteCode/MemberPointer.h
    clang/lib/AST/ByteCode/Opcodes.td
    clang/lib/AST/ByteCode/Pointer.cpp
    clang/lib/AST/ByteCode/Pointer.h
    clang/test/AST/ByteCode/records.cpp
    clang/test/CodeGen/pr4349.c
    clang/test/SemaCXX/new-delete.cpp
    clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
    clang/unittests/AST/ByteCode/toAPValue.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 473494c694a98..daa5307c92298 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7935,18 +7935,12 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     // check), so that e.g. '&*(int *)0' is not rejected.
     if (!Ctx.getLangOpts().CPlusPlus) {
       const Expr *Sub = SubExpr->IgnoreParens();
-
       if (const auto *Deref = dyn_cast<UnaryOperator>(Sub);
-          Deref && Deref->getOpcode() == UO_Deref) {
-        if (DiscardResult)
-          return this->discard(Deref->getSubExpr());
-        return this->visit(Deref->getSubExpr()) && this->emitAddrOf(E);
-      }
+          Deref && Deref->getOpcode() == UO_Deref)
+        return this->delegate(Deref->getSubExpr());
     }
     // We should already have a pointer when we get here.
-    if (DiscardResult)
-      return this->discard(SubExpr);
-    return this->delegate(SubExpr) && this->emitAddrOf(E);
+    return this->delegate(SubExpr);
   case UO_Deref: // *x
     if (DiscardResult)
       return this->discard(SubExpr);
@@ -8735,10 +8729,11 @@ template <class Emitter>
 bool Compiler<Emitter>::emitDummyPtr(DeclOrExpr D, const Expr *E, bool CU) {
   assert(!DiscardResult && "Should've been checked before");
 
-  if (const auto *VD = D.asValueDecl())
-    return this->emitGetOpaquePtr(VD, CU, E);
+  if (ToLValue) {
+    if (const auto *VD = D.asValueDecl())
+      return this->emitGetOpaquePtr(VD, CU, E);
+  }
 
-  assert(D.asExpr());
   unsigned DummyID = P.getOrCreateDummy(D, CU);
   if (!this->emitGetPtrGlobal(DummyID, E))
     return false;

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 160cc745c89b6..e205b025bbe01 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -97,23 +97,6 @@ static void noteValueLocation(InterpState &S, const Block *B) {
     S.Note(Desc->getLocation(), diag::note_declared_at);
 }
 
-static void noteValueLocation(InterpState &S, const Pointer &Ptr) {
-  if (Ptr.isBlockPointer()) {
-    const Block *B = Ptr.block();
-    const Descriptor *Desc = B->getDescriptor();
-    if (B->isDynamic())
-      S.Note(Desc->getLocation(), diag::note_constexpr_dynamic_alloc_here);
-    else if (B->isTemporary())
-      S.Note(Desc->getLocation(), diag::note_constexpr_temporary_here);
-    else
-      S.Note(Desc->getLocation(), diag::note_declared_at);
-    return;
-  }
-
-  if (Ptr.isOpaquePointer())
-    S.Note(Ptr.asOpaquePointer().Base->getLocation(), diag::note_declared_at);
-}
-
 static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
                                      const ValueDecl *VD,
                                      AccessKinds AK = AK_Read);
@@ -217,38 +200,6 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
   S.Note(VD->getLocation(), diag::note_declared_at);
 }
 
-static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                           AccessKinds AK) {
-
-  if (!Ptr.isBlockPointer())
-    return true;
-
-  const Block *B = Ptr.block();
-  if (B->getDeclID()) {
-    if (!(B->isStatic() && B->isTemporary()))
-      return true;
-
-    const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
-        B->getDescriptor()->asExpr());
-    if (!MTE)
-      return true;
-
-    // FIXME(perf): Since we do this check on every Load from a static
-    // temporary, it might make sense to cache the value of the
-    // isUsableInConstantExpressions call.
-    if (S.checkingConstantDestruction() ||
-        (B->getEvalID() != S.EvalID &&
-         !MTE->isUsableInConstantExpressions(S.getASTContext()))) {
-      const SourceInfo &E = S.Current->getSource(OpPC);
-      S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
-      noteValueLocation(S, B);
-      return false;
-    }
-  }
-
-  return true;
-}
-
 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
                            AccessKinds AK) {
   if (B->getDeclID()) {
@@ -509,7 +460,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
     } else if (!S.checkingPotentialConstantExpression()) {
       S.FFDiag(Src, diag::note_constexpr_access_uninit)
           << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
-      noteValueLocation(S, Ptr);
+      noteValueLocation(S, Ptr.block());
     }
 
     return false;
@@ -946,7 +897,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
   }
   // Block and string pointers are the only ones we can actually read from.
   if (!Ptr.isReadablePointerType())
-    return CheckDummy(S, OpPC, Ptr, AK);
+    return false;
 
   if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
     if (!CheckLive(S, OpPC, Ptr, AK))
@@ -1013,7 +964,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
 bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
   assert(!Ptr.isZero());
   if (!Ptr.isReadablePointerType())
-    return CheckDummy(S, OpPC, Ptr, AK_Read);
+    return false;
 
   if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
     if (!CheckLive(S, OpPC, Ptr, AK_Read))
@@ -1045,13 +996,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
 
 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                 bool WillBeActivated) {
-  if (Ptr.isZero())
-    return false;
-
-  if (Ptr.isOpaquePointer())
-    return CheckDummy(S, OpPC, Ptr, AK_Assign);
-
-  if (!Ptr.isBlockPointer())
+  if (!Ptr.isBlockPointer() || Ptr.isZero())
     return false;
 
   if (!Ptr.block()->isAccessible()) {
@@ -1098,8 +1043,6 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
     return false;
   if (!CheckRange(S, OpPC, Ptr, AK_Assign))
     return false;
-  if (!Ptr.isBlockPointer())
-    return false;
   return true;
 }
 
@@ -1320,8 +1263,6 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
 
 bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
                        const Pointer &Ptr) {
-  if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
-    return false;
   // Regular new type(...) call.
   if (isa_and_nonnull<CXXNewExpr>(Source))
     return true;
@@ -1338,7 +1279,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
   const SourceInfo &Loc = S.Current->getSource(OpPC);
   S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
       << Ptr.toDiagnosticString(S.getASTContext());
-  noteValueLocation(S, Ptr);
+  noteValueLocation(S, Ptr.block());
   return false;
 }
 
@@ -1364,24 +1305,6 @@ bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
   return CheckDeclRef(S, OpPC, DR);
 }
 
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                AccessKinds AK) {
-  if (!Ptr.isDummy())
-    return true;
-
-  const VarDecl *D = Ptr.getRootVarDecl();
-  if (!D)
-    return false;
-
-  if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
-    return diagnoseUnknownDecl(S, OpPC, D, AK);
-
-  if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14)
-    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_modify_global);
-  return false;
-}
-
-// FIXME: Remove this once all dummy pointers are opaque pointers.
 bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
   if (!B->isDummy())
     return true;
@@ -1506,7 +1429,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
       return true;
 
     if (!Ptr.isBlockPointer())
-      return CheckDeleteSource(S, OpPC, nullptr, Ptr);
+      return false;
 
     // Remove base casts.
     QualType InitialType = Ptr.getType();
@@ -1888,7 +1811,7 @@ static bool diagnoseOutOfLifetimeDestroy(InterpState &S, CodePtr OpPC,
 bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
   if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
     return false;
-  if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))
+  if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))
     return false;
   if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
     return false;
@@ -1904,7 +1827,7 @@ bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
     return true;
 
   // Can't call a dtor on a global variable.
-  if (Ptr.isOpaquePointer() || Ptr.block()->isStatic()) {
+  if (Ptr.block()->isStatic()) {
     const SourceInfo &E = S.Current->getSource(OpPC);
     S.FFDiag(E, diag::note_constexpr_modify_global);
     return false;
@@ -2133,22 +2056,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
   return true;
 }
 
-static bool getDynamicDecl(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr,
                            const CXXRecordDecl *&DynamicDecl) {
 
-  auto diagUnknownDynamicType = [&](const Pointer &P) -> bool {
-    APValue V = P.toAPValue(S.getASTContext());
-    QualType TT = S.getASTContext().getLValueReferenceType(P.getType());
-    S.FFDiag(S.Current->getSource(OpPC),
-             diag::note_constexpr_polymorphic_unknown_dynamic_type)
-        << AK_MemberCall << V.getAsString(S.getASTContext(), TT);
-    return false;
-  };
-
-  if (!Ptr.isBlockPointer())
-    return diagUnknownDynamicType(Ptr);
-
-  PtrView TypePtr = Ptr.view();
   if (S.InitializingPtrs.empty()) {
     TypePtr = TypePtr.stripBaseCasts();
   } else {
@@ -2180,8 +2090,14 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
   QualType DynamicType = TypePtr.getType();
   if (TypePtr.Pointee->isStatic() || TypePtr.isConst()) {
     if (const VarDecl *VD = Pointer(TypePtr).getRootVarDecl();
-        VD && !VD->isConstexpr())
-      return diagUnknownDynamicType(Pointer(TypePtr));
+        VD && !VD->isConstexpr()) {
+      const Expr *E = S.Current->getExpr(OpPC);
+      APValue V = Pointer(TypePtr).toAPValue(S.getASTContext());
+      QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
+      S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
+          << AK_MemberCall << V.getAsString(S.getASTContext(), TT);
+      return false;
+    }
   }
 
   if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {
@@ -2246,7 +2162,7 @@ bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr,
   const auto &Ptr = S.Stk.pop<Pointer>();
   QualType TargetType = QualType(DestTypePtr, 0);
 
-  if (Ptr.isConstexprUnknown() || Ptr.isOpaquePointer()) {
+  if (Ptr.isConstexprUnknown()) {
     QualType T = Ptr.getType();
     const Expr *E = S.Current->getExpr(OpPC);
     APValue V = Ptr.toAPValue(S.getASTContext());
@@ -2415,13 +2331,13 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
   size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
   Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
 
-  if (!ThisPtr.isBlockPointer() && !ThisPtr.isOpaquePointer())
+  if (!ThisPtr.isBlockPointer())
     return false;
 
   const FunctionDecl *Callee = Func->getDecl();
 
   const CXXRecordDecl *DynamicDecl = nullptr;
-  if (!getDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))
+  if (!getDynamicDecl(S, OpPC, ThisPtr.view(), DynamicDecl))
     return false;
   assert(DynamicDecl);
 
@@ -2695,7 +2611,7 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
   }
 
   if (!Ptr.isBlockPointer())
-    return CheckDummy(S, OpPC, Ptr, AK_Construct);
+    return false;
 
   if (!CheckRange(S, OpPC, Ptr, AK_Construct))
     return false;
@@ -2709,9 +2625,9 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
       return false;
     if (!CheckLive(S, OpPC, Ptr, AK_Construct))
       return false;
-    return CheckDummy(S, OpPC, Ptr, AK_Construct);
+    return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);
   }
-  if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
+  if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
     return false;
 
   // CheckLifetime for this and all base pointers.
@@ -2857,12 +2773,6 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
   if (Ptr.isIntegralPointer())
     return true;
 
-  if (Ptr.isOpaquePointer()) {
-    if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
-      return false;
-    return Ptr.isRoot();
-  }
-
   if (Ptr.isDummy()) {
     if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
       return false;
@@ -2952,7 +2862,7 @@ bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType) {
 bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
   const auto &P = S.Stk.pop<Pointer>();
 
-  if (!P.isBlockPointer() && !P.isOpaquePointer())
+  if (!P.isBlockPointer())
     return false;
 
   if (P.isConstexprUnknown()) {
@@ -2966,12 +2876,7 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
   }
 
   // Pick the most-derived type.
-  CanQualType T;
-  if (P.isBlockPointer())
-    T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
-  else
-    T = P.getType()->getCanonicalTypeUnqualified();
-
+  CanQualType T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
   // ... unless we're currently constructing this object.
   // FIXME: We have a similar check to this in more places.
   if (S.Current->getFunction()) {
@@ -3074,17 +2979,6 @@ static void copyPrimitiveMemory(InterpState &S, PtrView Ptr, PrimType T) {
     auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
     std::copy_n(Val.path(), PathLength, NewPath);
     Val.takePath(NewPath);
-  } else if (T == PT_Ptr) {
-    auto &Val = Ptr.deref<Pointer>();
-    if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
-      const OpaquePointer &OP = Val.asOpaquePointer();
-      auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
-      std::memcpy(NewPath, OP.Path, OP.PathLength * sizeof(PointerPathEntry));
-      Val = Pointer(OP.withPath(NewPath, OP.PathLength,
-                                OP.getFieldType().getTypePtr(),
-                                OP.isOnePastEnd()),
-                    Val.getByteOffset());
-    }
   }
 }
 
@@ -3097,17 +2991,6 @@ static void copyPrimitiveMemory(InterpState &S, PtrView Ptr) {
     auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
     std::copy_n(Val.path(), PathLength, NewPath);
     Val.takePath(NewPath);
-  } else if constexpr (std::is_same_v<T, Pointer>) {
-    auto &Val = Ptr.deref<Pointer>();
-    if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
-      const OpaquePointer &OP = Val.asOpaquePointer();
-      auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
-      std::memcpy(NewPath, OP.Path, OP.PathLength * sizeof(PointerPathEntry));
-      Val = Pointer(OP.withPath(NewPath, OP.PathLength,
-                                OP.getFieldType().getTypePtr(),
-                                OP.isOnePastEnd()),
-                    Val.getByteOffset());
-    }
   } else {
     auto &Val = Ptr.deref<T>();
     if (!Val.singleWord()) {
@@ -3167,8 +3050,6 @@ static void finishGlobalRecurse(InterpState &S, PtrView Ptr) {
 
 bool FinishInitGlobal(InterpState &S) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
-  if (!Ptr.isBlockPointer())
-    return true;
 
   finishGlobalRecurse(S, Ptr.view());
   if (Ptr.canBeInitialized()) {
@@ -3474,16 +3355,13 @@ std::optional<Pointer> addSubOffsetOpaque(InterpState &S, CodePtr OpPC,
     return Ptr;
 
   const OpaquePointer &OP = Ptr.asOpaquePointer();
-  QualType ArrTy = OP.getSurroundingArray().getCanonicalType();
-  QualType ElemTy = OP.getFieldType();
+  QualType ArrTy = OP.getSurroundingArray();
+  QualType ElemTy = ArrTy;
   unsigned NumElems = 1;
-
-  if (OP.isArrayElement()) {
-    if (const ConstantArrayType *CAT =
-            S.getASTContext().getAsConstantArrayType(ArrTy))
+  if (const ArrayType *AT = ArrTy->getAsArrayTypeUnsafe()) {
+    ElemTy = AT->getElementType();
+    if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
       NumElems = CAT->getZExtSize();
-  } else {
-    ArrTy = ElemTy;
   }
 
   if (isa<IncompleteArrayType>(ArrTy)) {
@@ -3495,10 +3373,10 @@ std::optional<Pointer> addSubOffsetOpaque(InterpState &S, CodePtr OpPC,
   if (Offset > NumElems) {
     if (Op == ArithOp::Add)
       S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
-          << Offset << /*non-array*/ !OP.isArrayElement() << NumElems;
+          << Offset << /*non-array*/ !isa<ArrayType>(ArrTy) << NumElems;
     else
       S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
-          << -Offset << /*non-array*/ !OP.isArrayElement() << NumElems;
+          << -Offset << /*non-array*/ !isa<ArrayType>(ArrTy) << NumElems;
   }
 
   if (!validType(ElemTy) || !validType(ArrTy)) {
@@ -3534,38 +3412,6 @@ std::optional<Pointer> addSubOffsetOpaque(InterpState &S, CodePtr OpPC,
   return Pointer(OP.withPastEnd(true), NewOffset);
 }
 
-bool virtBaseHelper(InterpState &S, const CXXRecordDecl *Decl,
-                    const Pointer &Ptr) {
-  if (Ptr.isOpaquePointer()) {
-    const OpaquePointer &OP = Ptr.asOpaquePointer();
-    if (!OP.getFieldType()->isRecordType()) {
-      S.Stk.push<Pointer>(Ptr);
-      return true;
-    }
-
-    PointerPathEntry *NewPath =
-        S.extendPointerPath(OP.PathLength + 1, OP.Path,
-                            PointerPathEntry::base(Decl, /*IsVirtual=*/true));
-
-    S.Stk.push<Pointer>(
-        OP.withPath(NewPath, OP.PathLength + 1,
-                    S.getASTContext().getCanonicalTagType(Decl).getTypePtr()),
-        Ptr.getByteOffset());
-    return true;
-  }
-
-  if (!Ptr.isBlockPointer())
-    return false;
-  if (!Ptr.getFieldDesc()->isRecord())
-    return false;
-  Pointer Base = Ptr.stripBaseCasts();
-  const Record::Base *VirtBase = Base.getRecord()->findVirtualBase(Decl);
-  if (!VirtBase)
-    return false;
-  S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
-  return true;
-}
-
 // FIXME: Would be nice to generate this instead of hardcoding it here.
 [[maybe_unused]] static constexpr bool OpReturns(Opcode Op) {
   return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet ||

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 343883872728b..61118d77b7ac2 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1494,30 +1494,15 @@ bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
   const T &LHS = S.Stk.pop<T>();
   const Pointer &P = S.Stk.peek<Pointer>();
 
-  ComparisonCategoryResult CmpResult;
+  ComparisonCategoryResult CmpResult = LHS.compare(RHS);
   if constexpr (std::is_same_v<T, Pointer>) {
-    if (!Pointer::hasSameBase(LHS, RHS)) {
-      S.FFDiag(S.Current->getSource(OpPC),
-               diag::note_constexpr_pointer_comparison_unspecified)
+    if (CmpResult == ComparisonCategoryResult::Unordered) {
+      const SourceInfo &Loc = S.Current->getSource(OpPC);
+      S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
           << LHS.toDiagnosticString(S.getASTContext())
           << RHS.toDiagnosticString(S.getASTContext());
       return false;
     }
-    std::optional<size_t> LHSOffset =
-        LHS.computeLayoutOffset(S.getASTContext());
-    std::optional<size_t> RHSOffset =
-        RHS.computeLayoutOffset(S.getASTContext());
-    if (!LHSOffset || !RHSOffset)
-      return false;
-
-    if (LHSOffset < RHSOffset)
-      CmpResult = ComparisonCategoryResult::Less;
-    else if (LHSOffset > RHSOffset)
-      CmpResult = ComparisonCategoryResult::Greater;
-    else
-      CmpResult = ComparisonCategoryResult::Equal;
-  } else {
-    CmpResult = LHS.compare(RHS);
   }
 
   assert(CmpInfo);
@@ -1688,9 +1673,6 @@ bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (!CheckRange(S, OpPC, Obj, CSK_Field))
     return false;
 
-  if (!Obj.isBlockPointer())
-    return false;
-
   // FIXME(postswitch): The isUnknownSizeArray() check here is only needed
   // to keep an invalid sample producing the same diagnostics as the current
   // interpreter.
@@ -1714,9 +1696,6 @@ bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (!CheckRange(S, OpPC, Obj, CSK_Field))
     return false;
 
-  if (!Obj.isBlockPointer())
-    return false;
-
   // FIXME(postswitch): The isUnknownSizeArray() check here is only needed
   // to keep an invalid sample producing the same diagnostics as the current
   // interpreter.
@@ -1737,10 +1716,6 @@ bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (!CheckThis(S, OpPC))
     return false;
   const Pointer &This = S.Current->getThis();
-
-  if (!This.isBlockPointer())
-    return false;
-
   const Pointer &Field = This.atField(I);
   if (!CheckLoad(S, OpPC, Field))
     return false;
@@ -1798,18 +1773,6 @@ bool InitGlobal(InterpState &S, uint32_t I) {
       NewPath[I] = Val.getPathEntry(I);
     }
     Val.takePath(NewPath);
-  } else if constexpr (std::is_same_v<T, Pointer>) {
-    auto &Val = P.deref<Pointer>();
-    if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
-      const OpaquePointer &OP = Val.asOpaquePointer();
-      auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
-      std::memcpy(NewPath, OP.Path, OP.PathLength * sizeof(PointerPathEntry));
-      Val = Pointer(OP.withPath(NewPath, OP.PathLength,
-                                OP.getFieldType().getTypePtr(),
-                                OP.isOnePastEnd()),
-                    Val.getByteOffset());
-    }
-
   } else if constexpr (needsAlloc<T>()) {
     auto &Val = P.deref<T>();
     if (!Val.singleWord()) {
@@ -2127,8 +2090,6 @@ inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
   if (!CheckThis(S, OpPC))
     return false;
   const Pointer &This = S.Current->getThis();
-  if (!This.isBlockPointer())
-    return false;
   S.Stk.push<Pointer>(This.atField(Off));
   return true;
 }
@@ -2192,36 +2153,46 @@ inline bool CheckNull(InterpState &S, CodePtr OpPC) {
   return true;
 }
 
-bool virtBaseHelper(InterpState &S, const CXXRecordDecl *Decl,
-                    const Pointer &Ptr);
+inline bool VirtBaseHelper(InterpState &S, const RecordDecl *Decl,
+                           const Pointer &Ptr) {
+  if (!Ptr.isBlockPointer())
+    return false;
+  if (!Ptr.getFieldDesc()->isRecord())
+    return false;
+  Pointer Base = Ptr.stripBaseCasts();
+  const Record::Base *VirtBase = Base.getRecord()->findVirtualBase(Decl);
+  if (!VirtBase)
+    return false;
+  S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
+  return true;
+}
 
 inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
-                              const CXXRecordDecl *D) {
+                              const RecordDecl *D) {
   assert(D);
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
     return false;
-  return virtBaseHelper(S, D, Ptr);
+  return VirtBaseHelper(S, D, Ptr);
 }
 
-inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC,
-                           const CXXRecordDecl *D) {
+inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
   assert(D);
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
     return false;
-  return virtBaseHelper(S, D, Ptr);
+  return VirtBaseHelper(S, D, Ptr);
 }
 
 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
-                               const CXXRecordDecl *D) {
+                               const RecordDecl *D) {
   assert(D);
   if (S.checkingPotentialConstantExpression())
     return false;
   if (!CheckThis(S, OpPC))
     return false;
   const Pointer &This = S.Current->getThis();
-  return virtBaseHelper(S, D, This);
+  return VirtBaseHelper(S, D, This);
 }
 
 //===----------------------------------------------------------------------===//
@@ -3066,22 +3037,6 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   }
 }
 
-inline bool AddrOf(InterpState &S, CodePtr OpPC) {
-  const Pointer Ptr = S.Stk.pop<Pointer>();
-
-  if (Ptr.isOpaquePointer()) {
-    const OpaquePointer &OP = Ptr.asOpaquePointer();
-    QualType T = QualType(OP.FieldType.getPointer(), 0);
-    T = S.getASTContext().getPointerType(T);
-
-    S.Stk.push<Pointer>(OP.withFieldType(T.getTypePtr(), OP.isOnePastEnd()));
-  } else {
-    S.Stk.push<Pointer>(Ptr);
-  }
-
-  return true;
-}
-
 bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
                                 const Pointer &Ptr, unsigned BitWidth);
 bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth);
@@ -3113,8 +3068,6 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
         Kind = IntegralKind::BlockAddress;
       }
       S.Stk.push<T>(Kind, PtrVal, /*Offset=*/0);
-    } else if (Ptr.isOpaquePointer()) {
-      S.Stk.push<T>(IntegralKind::Address, Ptr.asOpaquePointer().Base, 0);
     } else if (Ptr.isFunctionPointer()) {
       const void *FuncDecl = Ptr.asFunctionPointer().Func->getDecl();
       S.Stk.push<T>(IntegralKind::FunctionAddress, FuncDecl, /*Offset=*/0);
@@ -3543,17 +3496,15 @@ inline bool ExpandPtr(InterpState &S) {
   return true;
 }
 
+bool arrayElemPtrOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+                        APSInt &&Index, bool AllowReplace = true);
+
 // Implementation for ArrayElemPtr and ArrayElemPtrPop ops.
 template <typename T>
 inline bool arrayElemPtr(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                          const T &Offset) {
-  if (Ptr.isOpaquePointer()) {
-    if (S.inConstantContext() && !Offset.isZero() &&
-        !CheckArray(S, OpPC, Ptr)) {
-      return false;
-    }
+  if (Ptr.isOpaquePointer())
     return arrayElemPtrOpaque(S, OpPC, Ptr, Offset.toAPSInt());
-  }
 
   if (Offset.isZero()) {
     if (const Descriptor *Desc = Ptr.getFieldDesc();
@@ -4190,10 +4141,6 @@ inline bool BitCast(InterpState &S, CodePtr OpPC) {
   Pointer FromPtr = S.Stk.pop<Pointer>();
   Pointer &ToPtr = S.Stk.peek<Pointer>();
 
-  // FIXME: Could allow reading from string pointers?
-  if (!FromPtr.isBlockPointer() || !ToPtr.isBlockPointer())
-    return false;
-
   const Descriptor *D = FromPtr.getFieldDesc();
   if (D->isPrimitiveArray() && FromPtr.isArrayRoot())
     FromPtr = FromPtr.atIndex(0);

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 42ee33541b41b..0432308ef55f6 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -165,9 +165,6 @@ static QualType getElemType(const Pointer &P) {
         ->getElementType();
   }
 
-  if (P.isOpaquePointer() || P.isIntegralPointer())
-    return P.getType();
-
   const Descriptor *Desc = P.getFieldDesc();
   QualType T = Desc->getType();
   if (Desc->isPrimitive())
@@ -412,7 +409,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
   if (!StrPtr.isBlockPointer())
     return false;
 
-  if (!CheckDummy(S, OpPC, StrPtr, AK_Read))
+  if (!CheckDummy(S, OpPC, StrPtr.block(), AK_Read))
     return false;
 
   if (!StrPtr.getFieldDesc()->isPrimitiveArray())
@@ -1321,13 +1318,13 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
   }
   assert(FirstArgT == PT_Ptr);
   const Pointer &Ptr = S.Stk.pop<Pointer>();
-  if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer()) {
+  if (!Ptr.isBlockPointer()) {
     S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_compute)
         << Alignment;
     return false;
   }
 
-  const VarDecl *PtrDecl = Ptr.getRootVarDecl();
+  const ValueDecl *PtrDecl = Ptr.getDeclDesc()->asValueDecl();
   // We need a pointer for a declaration here.
   if (!PtrDecl) {
     if (BuiltinOp == Builtin::BI__builtin_is_aligned)
@@ -1339,19 +1336,10 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
     return false;
   }
 
-  unsigned PtrOffset;
-  if (Ptr.isBlockPointer()) {
-    // For one-past-end pointers, we can't call getIndex() since it asserts.
-    // Use getNumElems() instead which gives the correct index for past-end.
-    PtrOffset = Ptr.isElementPastEnd() ? Ptr.getNumElems() : Ptr.getIndex();
-  } else {
-    if (std::optional<size_t> PtrOff =
-            Ptr.computeLayoutOffset(S.getASTContext()))
-      PtrOffset = *PtrOff;
-    else
-      return false;
-  }
-
+  // For one-past-end pointers, we can't call getIndex() since it asserts.
+  // Use getNumElems() instead which gives the correct index for past-end.
+  unsigned PtrOffset =
+      Ptr.isElementPastEnd() ? Ptr.getNumElems() : Ptr.getIndex();
   CharUnits BaseAlignment = S.getASTContext().getDeclAlign(PtrDecl);
   CharUnits PtrAlign =
       BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));
@@ -1400,18 +1388,8 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
                                     ? llvm::alignDown(PtrOffset, Alignment64)
                                     : llvm::alignTo(PtrOffset, Alignment64));
 
-    if (Ptr.isBlockPointer()) {
-      S.Stk.push<Pointer>(Ptr.atIndex(NewOffset.getQuantity()));
-      return true;
-    }
-
-    assert(Ptr.isOpaquePointer());
-
-    APSInt APOffset =
-        APSInt(APInt(64, NewOffset.getQuantity(), /*IsSigned=*/true),
-               /*IsUnsigned=*/false);
-    return arrayElemPtrOpaque(S, OpPC, Ptr, std::move(APOffset),
-                              /*AllocReplace=*/true);
+    S.Stk.push<Pointer>(Ptr.atIndex(NewOffset.getQuantity()));
+    return true;
   }
 
   // Otherwise, we cannot constant-evaluate the result.
@@ -1442,9 +1420,9 @@ static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC,
   CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
 
   // If there is a base object, then it must have the correct alignment.
-  if (Ptr.isBlockPointer() || Ptr.isOpaquePointer()) {
+  if (Ptr.isBlockPointer()) {
     CharUnits BaseAlignment;
-    if (const auto *VD = Ptr.getRootVarDecl())
+    if (const auto *VD = Ptr.getDeclDesc()->asValueDecl())
       BaseAlignment = ASTCtx.getDeclAlign(VD);
     else if (const auto *E = Ptr.getRootExpr())
       BaseAlignment = GetAlignOfExpr(ASTCtx, E, UETT_AlignOf);
@@ -1465,7 +1443,7 @@ static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC,
   if (ExtraOffset)
     AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue());
   if (AVOffset.alignTo(Align) != AVOffset) {
-    if (Ptr.isBlockPointer() || Ptr.isOpaquePointer())
+    if (Ptr.isBlockPointer())
       S.CCEDiag(Call->getArg(0),
                 diag::note_constexpr_baa_insufficient_alignment)
           << 1 << AVOffset.getQuantity() << Align.getQuantity();
@@ -2145,6 +2123,10 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
     pushInteger(S, 0, Call->getType());
     return true;
   }
+
+  if (!PtrA.isReadablePointerType() || !PtrB.isReadablePointerType())
+    return false;
+
   bool IsWide =
       (ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);
 
@@ -2162,9 +2144,6 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
     return false;
   }
 
-  if (!PtrA.isReadablePointerType() || !PtrB.isReadablePointerType())
-    return false;
-
   if (!CheckLoad(S, OpPC, PtrA, AK_Read) || !CheckLoad(S, OpPC, PtrB, AK_Read))
     return false;
 
@@ -2444,14 +2423,14 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
       return false;
     if (!CheckMutable(S, OpPC, Ptr))
       return false;
-    if (!CheckDummy(S, OpPC, Ptr, AK_Read))
+    if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
       return false;
   }
 
   // Check if we're currently running an initializer.
   if (S.initializingBlock(Ptr.block()))
     return Error(2);
-  if (S.EvaluatingDecl && Ptr.getRootVarDecl() == S.EvaluatingDecl)
+  if (S.EvaluatingDecl && Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)
     return Error(2);
 
   pushInteger(S, Result, Call->getType());

diff  --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index f183efb5b19d1..4c60670ac5a0c 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -41,11 +41,6 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
 
 /// Checks if a pointer is a dummy pointer.
 bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                AccessKinds AK);
-
-bool arrayElemPtrOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                        APSInt &&Index, bool AllowReplace = true);
 
 /// Checks if a pointer is in range.
 template <typename T>

diff  --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h
index 39c7c24e1a304..b23acf7befc67 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -101,8 +101,6 @@ class MemberPointer final {
   std::optional<Pointer> toPointer(const Context &Ctx) const;
 
   bool isBaseCastPossible() const {
-    if (!Base.isBlockPointer())
-      return false;
     if (PtrOffset < 0)
       return true;
     return static_cast<uint64_t>(PtrOffset) <= Base.getByteOffset();

diff  --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 1831dc161f0a5..4be5495a7ed25 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -55,7 +55,6 @@ def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; }
 def ArgFunction : ArgType { let Name = "const Function *"; }
 def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; }
 def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
-def ArgCXXRecordDecl : ArgType { let Name = "const CXXRecordDecl *"; }
 def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
 def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; }
 def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; }
@@ -329,8 +328,6 @@ class OffsetOpcode : Opcode {
   let Args = [ArgUint32];
 }
 
-def AddrOf : Opcode;
-
 // [] -> [Pointer]
 def GetPtrLocal : OffsetOpcode {
   bit HasCustomEval = 1;
@@ -382,11 +379,11 @@ def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }
 // [Pointer] -> [Pointer]
 def GetPtrVirtBasePop : Opcode {
   // RecordDecl of base class.
-  let Args = [ArgCXXRecordDecl];
+  let Args = [ArgRecordDecl];
 }
 def GetPtrVirtBase : Opcode {
   // RecordDecl of base class.
-  let Args = [ArgCXXRecordDecl];
+  let Args = [ArgRecordDecl];
 }
 
 def IsBaseClass : SuccessOpcode;
@@ -400,7 +397,7 @@ def GetPtrThisBase : Opcode {
 // [] -> [Pointer]
 def GetPtrThisVirtBase : Opcode {
   // RecordDecl of base class.
-  let Args = [ArgCXXRecordDecl];
+  let Args = [ArgRecordDecl];
 }
 // [] -> [Pointer]
 def This : Opcode;

diff  --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 8016680ef9c0a..81fa2beaedb24 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -242,34 +242,9 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
     return APValue(APValue::LValueBase(Str.Base),
                    CharUnits::fromQuantity(Offset * elemSize()), Path,
                    /*OnePastTheEnd=*/false, /*IsNull=*/false);
-  case Storage::Opaque: {
-    if (!Opaque.Base->getType()->isPointerType()) {
-      for (const PointerPathEntry &Entry : Opaque.path()) {
-        switch (Entry.Kind) {
-        case PointerPathEntry::Field:
-          Path.push_back(APValue::LValuePathEntry({Entry.FD, false}));
-          break;
-        case PointerPathEntry::Base:
-          Path.push_back(APValue::LValuePathEntry(
-              {Entry.RD.getPointer(), Entry.RD.getInt()}));
-          break;
-        case PointerPathEntry::Array:
-          Path.push_back(APValue::LValuePathEntry::ArrayIndex(Entry.Index));
-          break;
-        case PointerPathEntry::NegativeArray:
-          Path.push_back(APValue::LValuePathEntry::ArrayIndex(-Entry.Index));
-          break;
-        }
-      }
-    }
-    size_t LayoutOffset = Opaque.computeLayoutOffset(ASTCtx).value_or(0);
-    auto Offset = CharUnits::fromQuantity(LayoutOffset + getByteOffset());
-    auto Result =
-        APValue(Opaque.Base, Offset, Path,
-                /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
-    Result.setConstexprUnknown(Opaque.isConstexprUnknown());
-    return Result;
-  }
+  case Storage::Opaque:
+    return APValue(APValue::LValueBase(Opaque.Base), CharUnits::Zero(), Path,
+                   /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
   }
 
   assert(isBlockPointer());
@@ -471,9 +446,7 @@ Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
   case Storage::String:
     return reinterpret_cast<uintptr_t>(Str.getLiteral()) + Offset;
   case Storage::Opaque:
-    if (auto O = Opaque.computeLayoutOffset(ASTCtx))
-      return *O + Offset;
-    return std::nullopt;
+    return reinterpret_cast<uintptr_t>(asOpaquePointer().Base) + Offset;
   }
 
   auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
@@ -554,9 +527,7 @@ Pointer::computeLayoutOffset(const ASTContext &ASTCtx) const {
   case Storage::String:
     return Offset * Str.getLiteral()->getCharByteWidth();
   case Storage::Opaque:
-    if (auto O = Opaque.computeLayoutOffset(ASTCtx))
-      return *O + Offset;
-    return std::nullopt;
+    return Opaque.computeLayoutOffset(ASTCtx);
   }
 
   auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
@@ -905,39 +876,17 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
   if (A.isZero() && B.isZero())
     return true;
 
-  // We allow comparisons between opaque pointers and block pointers, provided
-  // they have the same declaration as base.
-  if (A.StorageKind != B.StorageKind) {
-    if (A.isOpaquePointer() && B.isBlockPointer()) {
-      if (const VarDecl *BDecl = B.block()->getDescriptor()->asVarDecl())
-        return BDecl == A.Opaque.Base->getMostRecentDecl();
-
-      return false;
-    }
-    if (B.isOpaquePointer() && A.isBlockPointer()) {
-      if (const VarDecl *ADecl = A.block()->getDescriptor()->asVarDecl())
-        return ADecl == B.Opaque.Base->getMostRecentDecl();
-      return false;
-    }
-    return false;
-  }
-
-  switch (A.StorageKind) {
-  case Storage::Int:
+  if (A.isIntegralPointer() && B.isIntegralPointer())
     return true;
-  case Storage::Block:
-    // See below.
-    break;
-  case Storage::Fn:
+  if (A.isFunctionPointer() && B.isFunctionPointer())
     return true;
-  case Storage::Typeid:
+  if (A.isTypeidPointer() && B.isTypeidPointer())
     return A.asTypeidPointer().TypePtr == B.asTypeidPointer().TypePtr;
-  case Storage::String:
+  if (A.isStringPointer() && B.isStringPointer())
     return A.Str.ID == B.Str.ID && A.Str.getLiteral() == B.Str.getLiteral();
-  case Storage::Opaque:
-    return A.asOpaquePointer().Base->getMostRecentDecl() ==
-           B.asOpaquePointer().Base->getMostRecentDecl();
-  }
+
+  if (A.StorageKind != B.StorageKind)
+    return false;
 
   return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
 }
@@ -1343,12 +1292,7 @@ OpaquePointer::computeLayoutOffset(const ASTContext &ASTCtx) const {
         return std::nullopt;
 
       const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
-      if (Entry.RD.getInt())
-        Offset +=
-            Layout.getVBaseClassOffset(Entry.RD.getPointer()).getQuantity();
-      else
-        Offset +=
-            Layout.getBaseClassOffset(Entry.RD.getPointer()).getQuantity();
+      Offset += Layout.getBaseClassOffset(Entry.RD.getPointer()).getQuantity();
 
       CurType = ASTCtx.getCanonicalTagType(Entry.RD.getPointer());
     } break;

diff  --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 3bf6a363d6afd..fd09b4908f0b5 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -494,6 +494,7 @@ struct OpaquePointer {
   bool isUnknownSizeArray() const;
   bool isRoot() const;
 };
+struct OpaqueTag {};
 
 enum class Storage { Int, Block, Fn, Typeid, String, Opaque };
 
@@ -569,33 +570,18 @@ class Pointer {
 
   /// Equality operators are just for tests.
   bool operator==(const Pointer &P) const {
-    if (StorageKind != P.StorageKind)
+    if (P.StorageKind != StorageKind)
       return false;
-
-    switch (StorageKind) {
-    case Storage::Int:
+    if (isIntegralPointer())
       return P.Int.Value == Int.Value && P.Int.Ty == Int.Ty &&
              P.Offset == Offset;
-    case Storage::Block:
-      return P.view() == view();
-    case Storage::Fn:
+
+    if (isFunctionPointer())
       return P.Fn.Func == Fn.Func && P.Offset == Offset;
-    case Storage::Typeid:
-      llvm_unreachable("typeid in operator==?");
-    case Storage::String:
+    if (isStringPointer())
       return Str.Base == P.Str.Base && Offset == P.Offset;
-    case Storage::Opaque:
-      if (!(P.Opaque.Base == Opaque.Base &&
-            P.Opaque.PathLength == Opaque.PathLength))
-        return false;
-      if (P.Offset != Offset)
-        return false;
-      if (Opaque.PathLength == 0)
-        return true;
-      return std::memcmp(P.Opaque.Path, Opaque.Path,
-                         sizeof(PointerPathEntry) * Opaque.PathLength) == 0;
-    }
-    llvm_unreachable("Unhandled storage kind");
+
+    return P.view() == view();
   }
 
   bool operator!=(const Pointer &P) const { return !(P == *this); }
@@ -936,9 +922,6 @@ class Pointer {
 
       return Fn.Func->getDecl()->isWeak();
     }
-
-    if (isOpaquePointer())
-      return Opaque.Base->isWeak();
     if (!isBlockPointer())
       return false;
 
@@ -957,8 +940,6 @@ class Pointer {
 
   /// Checks if the pointer points to a dummy value.
   bool isDummy() const {
-    if (isOpaquePointer())
-      return true;
     if (!isBlockPointer())
       return false;
     return view().isDummy();
@@ -970,8 +951,6 @@ class Pointer {
       return true;
     if (isStringPointer())
       return true;
-    if (!isBlockPointer())
-      return false;
     return view().isConst();
   }
   bool isConstInMutable() const {

diff  --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index 90e7c1eb6ec64..36b5cb62fe95f 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -2054,14 +2054,3 @@ namespace BaseInitViaDIE {
   constexpr SS ss {};
   static_assert(ss.b == 42, "");
 }
-
-namespace OPEOpaque {
-  struct S {char c[14];};
-  extern S s;
-  static_assert((&s + 1) - &s == 1, "");
-
-  extern int a[12];
-  static_assert ((&a + 12 - &a) == 12, ""); // both-error {{not an integral constant expression}} \
-                                            // both-note {{cannot refer to element 12 of non-array object in a constant expression}}
-
-}

diff  --git a/clang/test/CodeGen/pr4349.c b/clang/test/CodeGen/pr4349.c
index 025a9b3903775..3bec499e0b3f5 100644
--- a/clang/test/CodeGen/pr4349.c
+++ b/clang/test/CodeGen/pr4349.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o -                                         | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -o - -fexperimental-new-constant-interpreter | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
 // PR 4349
 
 union reg

diff  --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp
index bd1eb23023d6f..595d0325be12f 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -721,9 +721,19 @@ int (*const_fold)[12] = new int[3][&const_fold + 12 - &const_fold];
 #if __cplusplus >= 201402L
 // expected-error at -2 {{array size is not a constant expression}}
 // expected-note at -3 {{cannot refer to element 12 of non-array}}
+#elif __cplusplus == 201103L
+#if defined(NEW_INTERP)
+// expected-error at -6 {{only the first dimension of an allocated array may have dynamic size}}
+// expected-note at -7 {{cannot refer to element 12 of non-array}}
+#endif
 #elif __cplusplus < 201103L
-// expected-error at -5 {{cannot allocate object of variably modified type}}
-// expected-warning at -6 {{variable length arrays in C++ are a Clang extension}}
+#if defined(NEW_INTERP)
+// expected-error at -11 {{only the first dimension of an allocated array may have dynamic size}}
+// expected-note at -12 {{cannot refer to element 12 of non-array}}
+#else
+// expected-error at -14 {{cannot allocate object of variably modified type}}
+// expected-warning at -15 {{variable length arrays in C++ are a Clang extension}}
+#endif
 #endif
 
 #if __cplusplus >= 201103L

diff  --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index cede91cd41997..9c25e26f43c36 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s -fexperimental-new-constant-interpreter
 
 template<typename T, T val> struct A {}; // expected-note 3{{template parameter is declared here}}
 

diff  --git a/clang/unittests/AST/ByteCode/toAPValue.cpp b/clang/unittests/AST/ByteCode/toAPValue.cpp
index a8e1d5e217597..702a07a638915 100644
--- a/clang/unittests/AST/ByteCode/toAPValue.cpp
+++ b/clang/unittests/AST/ByteCode/toAPValue.cpp
@@ -102,6 +102,8 @@ TEST(ToAPValue, Pointers) {
     ASSERT_EQ(A.getLValuePath()[0].getAsArrayIndex(), 2u);
     ASSERT_EQ(A.getLValuePath()[1].getAsArrayIndex(), 4u);
     ASSERT_EQ(A.getLValueOffset().getQuantity(), 56u);
+    ASSERT_TRUE(
+        GP.atIndex(0).getFieldDesc()->getElemQualType()->isIntegerType());
   }
 }
 


        


More information about the llvm-branch-commits mailing list