https://github.com/el-ev created 
https://github.com/llvm/llvm-project/pull/196544

Resolves #196476.

When a class is marked final, typeid on references to that type can be resolved 
at compile time since the most-derived type is statically known.

Example:
<details>

```cpp
// clang -cc1 -std=c++11 -emit-llvm -o - example.cpp

namespace std {
  class type_info {};
}

struct Poly {
  virtual ~Poly();
};

struct Final final : Poly {};

void final_ref(Final &f) { typeid(f); }
void final_deref(Final *f) { typeid(*f); }
```

Before:
```
define void @_Z9final_refR5Final(ptr %f) {
entry:
  %f.addr = alloca ptr, align 8
  store ptr %f, ptr %f.addr, align 8
  %0 = load ptr, ptr %f.addr, align 8, !nonnull !2, !align !3
  %vtable = load ptr, ptr %0, align 8
  %1 = getelementptr inbounds ptr, ptr %vtable, i64 -1
  %2 = load ptr, ptr %1, align 8
  ret void
}

define void @_Z11final_derefP5Final(ptr %f) {
entry:
  %f.addr = alloca ptr, align 8
  store ptr %f, ptr %f.addr, align 8
  %0 = load ptr, ptr %f.addr, align 8
  %1 = icmp eq ptr %0, null
  br i1 %1, label %typeid.bad_typeid, label %typeid.end

typeid.bad_typeid:                                ; preds = %entry
  call void @__cxa_bad_typeid() #1
  unreachable

typeid.end:                                       ; preds = %entry
  %vtable = load ptr, ptr %0, align 8
  %2 = getelementptr inbounds ptr, ptr %vtable, i64 -1
  %3 = load ptr, ptr %2, align 8
  ret void
}   
```

After:
```
define void @_Z9final_refR5Final(ptr %f) {
entry:
  %f.addr = alloca ptr, align 8
  store ptr %f, ptr %f.addr, align 8
  ret void
}

define void @_Z11final_derefP5Final(ptr %f) {
entry:
  %f.addr = alloca ptr, align 8
  store ptr %f, ptr %f.addr, align 8
  ret void
}
```
</details>

>From 1e5ed20100a2d42b3daaf76db426e77698aba6bb Mon Sep 17 00:00:00 2001
From: Iris Shi <[email protected]>
Date: Fri, 8 May 2026 22:18:54 +0800
Subject: [PATCH] [clang][AST] Teach `CXXTypeidExpr::isMostDerived` to use
 `isEffectivelyFinal`

---
 clang/lib/AST/ExprCXX.cpp                     |  5 ++
 clang/test/CodeGenCXX/typeid-most-derived.cpp | 57 +++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/typeid-most-derived.cpp

diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index be1bd3ba913ea..40e129d03dcea 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -149,6 +149,11 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const {
 bool CXXTypeidExpr::isMostDerived(const ASTContext &Context) const {
   assert(!isTypeOperand() && "Cannot call isMostDerived for typeid(type)");
   const Expr *E = getExprOperand()->IgnoreParenNoopCasts(Context);
+
+  if (const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl())
+    if (RD->isEffectivelyFinal())
+      return true;
+
   if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
     QualType Ty = DRE->getDecl()->getType();
     if (!Ty->isPointerOrReferenceType())
diff --git a/clang/test/CodeGenCXX/typeid-most-derived.cpp 
b/clang/test/CodeGenCXX/typeid-most-derived.cpp
new file mode 100644
index 0000000000000..a2d9f2e2bc6eb
--- /dev/null
+++ b/clang/test/CodeGenCXX/typeid-most-derived.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -Wno-unused-value -emit-llvm 
-o - -std=c++11 | FileCheck %s
+
+namespace std {
+  class type_info {};
+}
+
+struct Poly {
+  virtual int foo() { return 42; }
+  virtual ~Poly();
+};
+
+struct Derived : Poly {};
+struct Final final : Poly {
+    int foo() override { return 84; }
+};
+
+// Most derived
+void value(Poly p) { typeid(p); }
+// CHECK-LABEL: define {{.*}}void @_Z5value4Poly
+// CHECK-NOT:   %vtable
+// CHECK:       ret void
+
+// Most derived
+void final_ref(Final &f) { typeid(f); }
+// CHECK-LABEL: define {{.*}}void @_Z9final_refR5Final
+// CHECK-NOT:   %vtable
+// CHECK:       ret void
+
+// Most derived
+void final_deref(Final *f) { typeid(*f); }
+// CHECK-LABEL: define {{.*}}void @_Z11final_derefP5Final
+// CHECK-NOT:   %vtable
+// CHECK:       ret void
+
+// Not most derived
+void poly_ref(Poly &p) { typeid(p); }
+// CHECK-LABEL: define {{.*}}void @_Z8poly_refR4Poly
+// CHECK:       %vtable
+// CHECK:       ret void
+
+// Not most derived
+void poly_deref(Poly *p) { typeid(*p); }
+// CHECK-LABEL: define {{.*}}void @_Z10poly_derefP4Poly
+// CHECK:       %vtable
+// CHECK:       ret void
+
+// Not most derived
+void derived_ref(Derived &d) { typeid(d); }
+// CHECK-LABEL: define {{.*}}void @_Z11derived_refR7Derived
+// CHECK:       %vtable
+// CHECK:       ret void
+
+// Not most derived
+void derived_deref(Derived *d) { typeid(*d); }
+// CHECK-LABEL: define {{.*}}void @_Z13derived_derefP7Derived
+// CHECK:       %vtable
+// CHECK:       ret void

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to