Author: Piotr Fusik
Date: 2026-06-25T11:25:29+02:00
New Revision: 5a0106d9f7f9b26dd36972665ee5e5b9806d975c

URL: 
https://github.com/llvm/llvm-project/commit/5a0106d9f7f9b26dd36972665ee5e5b9806d975c
DIFF: 
https://github.com/llvm/llvm-project/commit/5a0106d9f7f9b26dd36972665ee5e5b9806d975c.diff

LOG: [Clang] Fix missing vtable for `dynamic_cast<FinalClass *>(this)` in a 
function template (#202594)

9d525bf94b255df89587db955b5fa2d3c03c2c3e introduced an optimization
of `dynamic_cast<FinalClass *>` by comparing vtable pointers. This requires
the vtable to be emitted, which was fixed for most cases in #64088.

This change addresses a missing case of a `dynamic_cast` of `this`
in a function template. We ensure that `Sema::MarkVTableUsed`
gets called during template instantiation. It wasn't because
`CXXThisExpr` is unaffected by template instantiation.

Fix #198511

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/TypeBase.h
    clang/lib/AST/Type.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/test/CodeGenCXX/dynamic-cast-exact.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 96e36f99f558b..d4c286644033b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -811,6 +811,7 @@ Bug Fixes to C++ Support
 - Fixed a crash in constant evaluation using placement new on an array which 
was later initialized. (#GH196450)
 - Fixed an issue where Clang incorrectly accepted invalid unqualified uses of 
local nested class names outside their declaring scope. (#GH184622)
 - Fixed a crash when parsing invalid friend declaration with storage-class 
specifier. (#GH186569)
+- Fixed a missing vtable for ``dynamic_cast<FinalClass *>(this)`` in a 
function template. (#GH198511)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index c9658775f0470..3a801e2857b13 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2950,7 +2950,7 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
   ///
   /// If this is not a pointer or reference, or the type being pointed to does
   /// not refer to a CXXRecordDecl, returns NULL.
-  const CXXRecordDecl *getPointeeCXXRecordDecl() const;
+  CXXRecordDecl *getPointeeCXXRecordDecl() const;
 
   /// Get the DeducedType whose type will be deduced for a variable with
   /// an initializer of this type. This looks through declarators like pointer

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index b7bef40ca89f3..dffb3f1b50207 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1955,7 +1955,7 @@ const ObjCObjectPointerType 
*Type::getAsObjCInterfacePointerType() const {
   return nullptr;
 }
 
-const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
+CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
   QualType PointeeType;
   if (const auto *PT = getAsCanonical<PointerType>())
     PointeeType = PT->getPointeeType();

diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 427b634a92e46..a77ea5fd3dfff 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1886,6 +1886,16 @@ namespace {
         SmallVectorImpl<QualType> &PTypes,
         SmallVectorImpl<ParmVarDecl *> &TransParams,
         Sema::ExtParameterInfoBuilder &PInfos);
+
+    ExprResult TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+      ExprResult Ret = inherited::TransformCXXDynamicCastExpr(E);
+      if (Ret.isInvalid())
+        return Ret;
+      auto *DestDecl = Ret.get()->getType()->getPointeeCXXRecordDecl();
+      if (DestDecl && DestDecl->isEffectivelyFinal())
+        getSema().MarkVTableUsed(Ret.get()->getExprLoc(), DestDecl);
+      return Ret;
+    }
   };
 }
 

diff  --git a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp 
b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
index 588d80844a2fa..86a97f764e729 100644
--- a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
+++ b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
@@ -125,3 +125,17 @@ namespace GH64088 {
   struct B final : A { virtual ~B() = default; };
   B *cast(A *p) { return dynamic_cast<B*>(p); }
 }
+
+namespace GH198511 {
+  // Ensure we mark the B vtable as used here, because we're going to emit a
+  // reference to it.
+  // CHECK: define {{.*}} @_ZN8GH1985111BD0
+  struct B;
+  struct A {
+    virtual ~A() = default;
+    template<class T> B *cast();
+  };
+  struct B final : A { };
+  template<class T> B *A::cast() { return dynamic_cast<B*>(this); }
+  template B *A::cast<int>();
+}


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

Reply via email to