Skip to content

Commit 375f9b8

Browse files
committed
[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.
1 parent 9604bdf commit 375f9b8

File tree

6 files changed

+89
-13
lines changed

6 files changed

+89
-13
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3629,15 +3629,22 @@ template <class Emitter>
36293629
bool Compiler<Emitter>::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
36303630
const Type *TypeInfoType = E->getType().getTypePtr();
36313631

3632+
auto canonType = [](const Type *T) {
3633+
return T->getCanonicalTypeUnqualified().getTypePtr();
3634+
};
3635+
36323636
if (!E->isPotentiallyEvaluated()) {
36333637
if (DiscardResult)
36343638
return true;
36353639

36363640
if (E->isTypeOperand())
36373641
return this->emitGetTypeid(
3638-
E->getTypeOperand(Ctx.getASTContext()).getTypePtr(), TypeInfoType, E);
3639-
return this->emitGetTypeid(E->getExprOperand()->getType().getTypePtr(),
3640-
TypeInfoType, E);
3642+
canonType(E->getTypeOperand(Ctx.getASTContext()).getTypePtr()),
3643+
TypeInfoType, E);
3644+
3645+
return this->emitGetTypeid(
3646+
canonType(E->getExprOperand()->getType().getTypePtr()), TypeInfoType,
3647+
E);
36413648
}
36423649

36433650
// Otherwise, we need to evaluate the expression operand.

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1848,7 +1848,23 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
18481848
if (!P.isBlockPointer())
18491849
return false;
18501850

1851-
S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType);
1851+
// Pick the most-derived type.
1852+
const Type *T = P.getDeclPtr().getType().getTypePtr();
1853+
// ... unless we're currently constructing this object.
1854+
// FIXME: We have a similar check to this in more places.
1855+
if (S.Current->getFunction()) {
1856+
for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
1857+
if (const Function *Func = Frame->getFunction();
1858+
Func && (Func->isConstructor() || Func->isDestructor()) &&
1859+
P.block() == Frame->getThis().block()) {
1860+
T = Func->getParentDecl()->getTypeForDecl();
1861+
break;
1862+
}
1863+
}
1864+
}
1865+
1866+
S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(),
1867+
TypeInfoType);
18521868
return true;
18531869
}
18541870

clang/lib/AST/ByteCode/Interp.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,8 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
10061006
const Pointer &LHS = S.Stk.pop<Pointer>();
10071007

10081008
// Function pointers cannot be compared in an ordered way.
1009-
if (LHS.isFunctionPointer() || RHS.isFunctionPointer()) {
1009+
if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||
1010+
LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
10101011
const SourceInfo &Loc = S.Current->getSource(OpPC);
10111012
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
10121013
<< LHS.toDiagnosticString(S.getASTContext())
@@ -2478,13 +2479,15 @@ inline bool This(InterpState &S, CodePtr OpPC) {
24782479
// Ensure the This pointer has been cast to the correct base.
24792480
if (!This.isDummy()) {
24802481
assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2481-
[[maybe_unused]] const Record *R = This.getRecord();
2482-
if (!R)
2483-
R = This.narrow().getRecord();
2484-
assert(R);
2485-
assert(
2486-
R->getDecl() ==
2487-
cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2482+
if (!This.isTypeidPointer()) {
2483+
[[maybe_unused]] const Record *R = This.getRecord();
2484+
if (!R)
2485+
R = This.narrow().getRecord();
2486+
assert(R);
2487+
assert(R->getDecl() ==
2488+
cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())
2489+
->getParent());
2490+
}
24882491
}
24892492

24902493
S.Stk.push<Pointer>(This);

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,9 @@ void Pointer::print(llvm::raw_ostream &OS) const {
342342
<< " }";
343343
break;
344344
case Storage::Typeid:
345-
OS << "(Typeid)";
345+
OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
346+
<< (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
347+
<< "}";
346348
}
347349
}
348350

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,10 @@ class Pointer {
469469
assert(isFunctionPointer());
470470
return PointeeStorage.Fn;
471471
}
472+
[[nodiscard]] const TypeidPointer &asTypeidPointer() const {
473+
assert(isTypeidPointer());
474+
return PointeeStorage.Typeid;
475+
}
472476

473477
bool isBlockPointer() const { return StorageKind == Storage::Block; }
474478
bool isIntegralPointer() const { return StorageKind == Storage::Int; }
@@ -577,6 +581,8 @@ class Pointer {
577581
uint64_t getByteOffset() const {
578582
if (isIntegralPointer())
579583
return asIntPointer().Value + Offset;
584+
if (isTypeidPointer())
585+
return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
580586
if (isOnePastEnd())
581587
return PastEndMark;
582588
return Offset;

clang/test/AST/ByteCode/typeid.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
2+
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
3+
4+
namespace std {
5+
struct __type_info_implementations {
6+
struct __string_impl_base {
7+
typedef const char *__type_name_t;
8+
};
9+
struct __unique_impl : __string_impl_base {
10+
11+
static bool __eq(__type_name_t __lhs, __type_name_t __rhs);
12+
};
13+
typedef __unique_impl __impl;
14+
};
15+
16+
class type_info {
17+
protected:
18+
typedef __type_info_implementations::__impl __impl;
19+
__impl::__type_name_t __type_name;
20+
};
21+
}; // namespace std
22+
23+
static_assert(&typeid(int) != &typeid(long));
24+
static_assert(&typeid(int) == &typeid(int));
25+
static_assert(&typeid(int) < &typeid(long)); // both-error {{not an integral constant expression}} \
26+
// both-note {{comparison between pointers to unrelated objects '&typeid(int)' and '&typeid(long)' has unspecified value}}
27+
static_assert(&typeid(int) > &typeid(long)); // both-error {{not an integral constant expression}} \
28+
// both-note {{comparison between pointers to unrelated objects '&typeid(int)' and '&typeid(long)' has unspecified value}}
29+
30+
struct Base {
31+
virtual void func() ;
32+
};
33+
struct Derived : Base {};
34+
35+
constexpr bool test() {
36+
Derived derived;
37+
Base const &as_base = derived;
38+
if (&typeid(as_base) != &typeid(Derived))
39+
__builtin_abort();
40+
return true;
41+
}
42+
static_assert(test());

0 commit comments

Comments
 (0)