llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Iris Shi (el-ev)

<details>
<summary>Changes</summary>

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:
&lt;details&gt;

```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 &amp;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
}
```
&lt;/details&gt;

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


2 Files Affected:

- (modified) clang/lib/AST/ExprCXX.cpp (+5) 
- (added) clang/test/CodeGenCXX/typeid-most-derived.cpp (+57) 


``````````diff
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

``````````

</details>


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

Reply via email to