[clang] [clang][bytecode] Misc TypeidPointer fixes (PR #135322)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 10 23:50:23 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/135322.diff


6 Files Affected:

- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+10-3) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+17-1) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+11-8) 
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+3-1) 
- (modified) clang/lib/AST/ByteCode/Pointer.h (+6) 
- (added) clang/test/AST/ByteCode/typeid.cpp (+42) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index eafe735c2dce1..86b43585cd292 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -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.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 768ae6e49b13e..0afd772c73b85 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -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;
 }
 
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index e5813d6f7c982..4e84dcc8d551d 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -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);
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 918a434301461..c09d3224b1f36 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -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
+       << "}";
   }
 }
 
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index f892cf1159b55..5eef9d2e1885e 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -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; }
@@ -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;
diff --git a/clang/test/AST/ByteCode/typeid.cpp b/clang/test/AST/ByteCode/typeid.cpp
new file mode 100644
index 0000000000000..5be5604016db5
--- /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());

``````````

</details>


https://github.com/llvm/llvm-project/pull/135322


More information about the cfe-commits mailing list