llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> 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. --- Full diff: https://github.com/llvm/llvm-project/pull/135322.diff 6 Files Affected: - (modified) clang/lib/AST/ByteCode/Compiler.cpp (+10-3) - (modified) clang/lib/AST/ByteCode/Interp.cpp (+17-1) - (modified) clang/lib/AST/ByteCode/Interp.h (+11-8) - (modified) clang/lib/AST/ByteCode/Pointer.cpp (+3-1) - (modified) clang/lib/AST/ByteCode/Pointer.h (+6) - (added) clang/test/AST/ByteCode/typeid.cpp (+42) ``````````diff 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()); `````````` </details> https://github.com/llvm/llvm-project/pull/135322 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits