[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