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
