0
0
mirror of https://github.com/llvm/llvm-project.git synced 2025-04-21 11:16:50 +00:00

[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.
This commit is contained in:
Timm Baeder 2025-04-11 10:35:28 +02:00 committed by GitHub
parent 0276915a6c
commit fafeaab6d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 89 additions and 13 deletions

@ -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.

@ -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;
}

@ -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);

@ -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
<< "}";
}
}

@ -469,6 +469,10 @@ public:
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 @@ public:
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;

@ -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());