https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/222599
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 >From 6f76a8fa4a2961be199aeebb645d3261caa1aba0 Mon Sep 17 00:00:00 2001 From: Timm Baeder <[email protected]> Date: Thu, 10 Sep 2026 12:39:15 +0200 Subject: [PATCH] =?UTF-8?q?Revert=20"[clang][bytecode]=20Use=20opaque=20po?= =?UTF-8?q?inters=20for=20decl-based=20dummy=20pointers=20(=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a9f7095c26175f363282ed2cdfb52acada3c2d93. --- clang/lib/AST/ByteCode/Compiler.cpp | 19 +- clang/lib/AST/ByteCode/Interp.cpp | 218 +++--------------- clang/lib/AST/ByteCode/Interp.h | 107 +++------ clang/lib/AST/ByteCode/InterpBuiltin.cpp | 57 ++--- clang/lib/AST/ByteCode/InterpHelpers.h | 5 - clang/lib/AST/ByteCode/MemberPointer.h | 2 - clang/lib/AST/ByteCode/Opcodes.td | 9 +- clang/lib/AST/ByteCode/Pointer.cpp | 82 ++----- clang/lib/AST/ByteCode/Pointer.h | 37 +-- clang/test/AST/ByteCode/records.cpp | 11 - clang/test/CodeGen/pr4349.c | 3 +- clang/test/SemaCXX/new-delete.cpp | 14 +- .../SemaTemplate/temp_arg_nontype_cxx1z.cpp | 1 - clang/unittests/AST/ByteCode/toAPValue.cpp | 2 + 14 files changed, 123 insertions(+), 444 deletions(-) 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@-2 {{array size is not a constant expression}} // expected-note@-3 {{cannot refer to element 12 of non-array}} +#elif __cplusplus == 201103L +#if defined(NEW_INTERP) +// expected-error@-6 {{only the first dimension of an allocated array may have dynamic size}} +// expected-note@-7 {{cannot refer to element 12 of non-array}} +#endif #elif __cplusplus < 201103L -// expected-error@-5 {{cannot allocate object of variably modified type}} -// expected-warning@-6 {{variable length arrays in C++ are a Clang extension}} +#if defined(NEW_INTERP) +// expected-error@-11 {{only the first dimension of an allocated array may have dynamic size}} +// expected-note@-12 {{cannot refer to element 12 of non-array}} +#else +// expected-error@-14 {{cannot allocate object of variably modified type}} +// expected-warning@-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()); } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
