mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-21 11:16:50 +00:00
[clang][bytecode] Misc TypeidPointer fixes (#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.
This commit is contained in:
parent
0276915a6c
commit
fafeaab6d9
clang
@ -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;
|
||||
|
42
clang/test/AST/ByteCode/typeid.cpp
Normal file
42
clang/test/AST/ByteCode/typeid.cpp
Normal file
@ -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());
|
Loading…
x
Reference in New Issue
Block a user