Author: Iris Shi Date: 2026-05-11T21:54:32+08:00 New Revision: 6443657de563bfb5870529e92075a2c13e9f4acb
URL: https://github.com/llvm/llvm-project/commit/6443657de563bfb5870529e92075a2c13e9f4acb DIFF: https://github.com/llvm/llvm-project/commit/6443657de563bfb5870529e92075a2c13e9f4acb.diff LOG: [clang][AST] Teach `CXXTypeidExpr::isMostDerived` to use `isEffectivelyFinal` (#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. Added: clang/test/CodeGenCXX/typeid-most-derived.cpp Modified: clang/docs/ReleaseNotes.rst clang/lib/AST/ExprCXX.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 53f3d42270f1a..bd91b8723a5c6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -250,6 +250,9 @@ Non-comprehensive list of changes in this release enabling tools such as language servers and refactoring engines to accurately map source locations back to explicit instantiation sites. +- ``typeid`` on references and pointers of ``final`` types no longer emits a + vtable lookup at runtime. + New Compiler Flags ------------------ - New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added 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..2b6bb850ff415 --- /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 Base { + virtual int foo() { return 42; } + virtual ~Base(); +}; + +struct NonFinal : Base {}; +struct Final final : Base { + int foo() override { return 84; } +}; + +// Most derived +void base_by_value(Base b) { typeid(b); } +// CHECK-LABEL: define {{.*}}void @_Z13base_by_value4Base +// 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 base_ref(Base &b) { typeid(b); } +// CHECK-LABEL: define {{.*}}void @_Z8base_refR4Base +// CHECK: %vtable +// CHECK: ret void + +// Not most derived +void base_deref(Base *b) { typeid(*b); } +// CHECK-LABEL: define {{.*}}void @_Z10base_derefP4Base +// CHECK: %vtable +// CHECK: ret void + +// Not most derived +void nonfinal_ref(NonFinal &d) { typeid(d); } +// CHECK-LABEL: define {{.*}}void @_Z12nonfinal_refR8NonFinal +// CHECK: %vtable +// CHECK: ret void + +// Not most derived +void nonfinal_deref(NonFinal *d) { typeid(*d); } +// CHECK-LABEL: define {{.*}}void @_Z14nonfinal_derefP8NonFinal +// CHECK: %vtable +// CHECK: ret void _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
