Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
19 changes: 11 additions & 8 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
<< "}";
}
}

Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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;
Expand Down
42 changes: 42 additions & 0 deletions clang/test/AST/ByteCode/typeid.cpp
Original file line number Diff line number Diff line change
@@ -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());