https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/135322
Fix comparing type id pointers, add mor info when print()ing them, use the most derived type in GetTypeidPtr() and the canonically unqualified type when we know the type statically. >From 375f9b8c00e2c4a01f162a0ec688f76676c672fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Thu, 10 Apr 2025 23:14:15 +0200 Subject: [PATCH] [clang][bytecode] Misc TypeidPointer fixes Fix comparing type id pointers, add mor info when print()ing them, use the most derived type in GetTypeidPtr() and the canonically unqualified type when we know the type statically. --- clang/lib/AST/ByteCode/Compiler.cpp | 13 ++++++--- clang/lib/AST/ByteCode/Interp.cpp | 18 ++++++++++++- clang/lib/AST/ByteCode/Interp.h | 19 +++++++------ clang/lib/AST/ByteCode/Pointer.cpp | 4 ++- clang/lib/AST/ByteCode/Pointer.h | 6 +++++ clang/test/AST/ByteCode/typeid.cpp | 42 +++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 clang/test/AST/ByteCode/typeid.cpp diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index eafe735c2dce1..86b43585cd292 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3629,15 +3629,22 @@ template <class Emitter> bool Compiler<Emitter>::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { const Type *TypeInfoType = E->getType().getTypePtr(); + auto canonType = [](const Type *T) { + return T->getCanonicalTypeUnqualified().getTypePtr(); + }; + if (!E->isPotentiallyEvaluated()) { if (DiscardResult) return true; if (E->isTypeOperand()) return this->emitGetTypeid( - E->getTypeOperand(Ctx.getASTContext()).getTypePtr(), TypeInfoType, E); - return this->emitGetTypeid(E->getExprOperand()->getType().getTypePtr(), - TypeInfoType, E); + canonType(E->getTypeOperand(Ctx.getASTContext()).getTypePtr()), + TypeInfoType, E); + + return this->emitGetTypeid( + canonType(E->getExprOperand()->getType().getTypePtr()), TypeInfoType, + E); } // Otherwise, we need to evaluate the expression operand. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 768ae6e49b13e..0afd772c73b85 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1848,7 +1848,23 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { if (!P.isBlockPointer()) return false; - S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType); + // Pick the most-derived type. + const Type *T = P.getDeclPtr().getType().getTypePtr(); + // ... unless we're currently constructing this object. + // FIXME: We have a similar check to this in more places. + if (S.Current->getFunction()) { + for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) { + if (const Function *Func = Frame->getFunction(); + Func && (Func->isConstructor() || Func->isDestructor()) && + P.block() == Frame->getThis().block()) { + T = Func->getParentDecl()->getTypeForDecl(); + break; + } + } + } + + S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(), + TypeInfoType); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index e5813d6f7c982..4e84dcc8d551d 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1006,7 +1006,8 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { const Pointer &LHS = S.Stk.pop<Pointer>(); // Function pointers cannot be compared in an ordered way. - if (LHS.isFunctionPointer() || RHS.isFunctionPointer()) { + if (LHS.isFunctionPointer() || RHS.isFunctionPointer() || + LHS.isTypeidPointer() || RHS.isTypeidPointer()) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) << LHS.toDiagnosticString(S.getASTContext()) @@ -2478,13 +2479,15 @@ inline bool This(InterpState &S, CodePtr OpPC) { // Ensure the This pointer has been cast to the correct base. if (!This.isDummy()) { assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl())); - [[maybe_unused]] const Record *R = This.getRecord(); - if (!R) - R = This.narrow().getRecord(); - assert(R); - assert( - R->getDecl() == - cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent()); + if (!This.isTypeidPointer()) { + [[maybe_unused]] const Record *R = This.getRecord(); + if (!R) + R = This.narrow().getRecord(); + assert(R); + assert(R->getDecl() == + cast<CXXMethodDecl>(S.Current->getFunction()->getDecl()) + ->getParent()); + } } S.Stk.push<Pointer>(This); diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 918a434301461..c09d3224b1f36 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -342,7 +342,9 @@ void Pointer::print(llvm::raw_ostream &OS) const { << " }"; break; case Storage::Typeid: - OS << "(Typeid)"; + OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", " + << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset + << "}"; } } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index f892cf1159b55..5eef9d2e1885e 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -469,6 +469,10 @@ class Pointer { assert(isFunctionPointer()); return PointeeStorage.Fn; } + [[nodiscard]] const TypeidPointer &asTypeidPointer() const { + assert(isTypeidPointer()); + return PointeeStorage.Typeid; + } bool isBlockPointer() const { return StorageKind == Storage::Block; } bool isIntegralPointer() const { return StorageKind == Storage::Int; } @@ -577,6 +581,8 @@ class Pointer { uint64_t getByteOffset() const { if (isIntegralPointer()) return asIntPointer().Value + Offset; + if (isTypeidPointer()) + return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset; if (isOnePastEnd()) return PastEndMark; return Offset; diff --git a/clang/test/AST/ByteCode/typeid.cpp b/clang/test/AST/ByteCode/typeid.cpp new file mode 100644 index 0000000000000..5be5604016db5 --- /dev/null +++ b/clang/test/AST/ByteCode/typeid.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s + +namespace std { +struct __type_info_implementations { + struct __string_impl_base { + typedef const char *__type_name_t; + }; + struct __unique_impl : __string_impl_base { + + static bool __eq(__type_name_t __lhs, __type_name_t __rhs); + }; + typedef __unique_impl __impl; +}; + +class type_info { +protected: + typedef __type_info_implementations::__impl __impl; + __impl::__type_name_t __type_name; +}; +}; // namespace std + +static_assert(&typeid(int) != &typeid(long)); +static_assert(&typeid(int) == &typeid(int)); +static_assert(&typeid(int) < &typeid(long)); // both-error {{not an integral constant expression}} \ + // both-note {{comparison between pointers to unrelated objects '&typeid(int)' and '&typeid(long)' has unspecified value}} +static_assert(&typeid(int) > &typeid(long)); // both-error {{not an integral constant expression}} \ + // both-note {{comparison between pointers to unrelated objects '&typeid(int)' and '&typeid(long)' has unspecified value}} + + struct Base { + virtual void func() ; + }; + struct Derived : Base {}; + +constexpr bool test() { + Derived derived; + Base const &as_base = derived; + if (&typeid(as_base) != &typeid(Derived)) + __builtin_abort(); + return true; +} +static_assert(test()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits