[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.
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index eafe735..86b4358 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3629,15 +3629,22 @@
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.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 768ae6e..0afd772 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1848,7 +1848,23 @@
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;
}
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index e5813d6..4e84dcc 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1006,7 +1006,8 @@
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 @@
// 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);
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 918a434..c09d322 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -342,7 +342,9 @@
<< " }";
break;
case Storage::Typeid:
- OS << "(Typeid)";
+ OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
+ << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
+ << "}";
}
}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index f892cf1..5eef9d2 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -469,6 +469,10 @@
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 @@
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;
diff --git a/clang/test/AST/ByteCode/typeid.cpp b/clang/test/AST/ByteCode/typeid.cpp
new file mode 100644
index 0000000..5be5604
--- /dev/null
+++ b/clang/test/AST/ByteCode/typeid.cpp
@@ -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());