[clang] Revert "[clang][bytecode] Use opaque pointers for decl-based dummy pointers" (PR #222599)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 10 03:41:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

Reverts llvm/llvm-project#<!-- -->220917

Looks like this breaks some memory-sanitizier builders:
https://lab.llvm.org/buildbot/#/builders/169/builds/26405
https://lab.llvm.org/buildbot/#/builders/164/builds/25236

---

Patch is 44.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/222599.diff


14 Files Affected:

- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+7-12) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+32-186) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+27-80) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+18-39) 
- (modified) clang/lib/AST/ByteCode/InterpHelpers.h (-5) 
- (modified) clang/lib/AST/ByteCode/MemberPointer.h (-2) 
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+3-6) 
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+13-69) 
- (modified) clang/lib/AST/ByteCode/Pointer.h (+8-29) 
- (modified) clang/test/AST/ByteCode/records.cpp (-11) 
- (modified) clang/test/CodeGen/pr4349.c (+1-2) 
- (modified) clang/test/SemaCXX/new-delete.cpp (+12-2) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (-1) 
- (modified) clang/unittests/AST/ByteCode/toAPValue.cpp (+2) 


``````````diff
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...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/222599


More information about the cfe-commits mailing list