[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