Skip to content

Commit fafeaab

Browse files
authored
[clang][bytecode] Misc TypeidPointer fixes (llvm#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.
1 parent 0276915 commit fafeaab

File tree

6 files changed

+89
-13
lines changed

6 files changed

+89
-13
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

+10-3
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

+17-1
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

+11-8
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

+3-1
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

+6
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

+42
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)