https://github.com/mugiwaraluffy56 updated 
https://github.com/llvm/llvm-project/pull/178654

>From 694b4bbb2a1469f7e40b7aba59bef640b940cf08 Mon Sep 17 00:00:00 2001
From: mugiwaraluffy56 <[email protected]>
Date: Thu, 29 Jan 2026 19:09:20 +0530
Subject: [PATCH] [clang][analyzer] Don't warn about virtual calls in final
 class destructors

When a class is marked 'final', there can be no derived classes, so
calling a virtual method in the destructor is safe and won't bypass
virtual dispatch unexpectedly.

The existing check in isVirtualCall() uses getBestDynamicClassType()
which may not return the correct class during destruction. Instead,
directly check if the class whose constructor/destructor we're in
is marked final.

Fixes #178643
---
 .../Checkers/VirtualCallChecker.cpp           | 15 ++++++++
 clang/test/Analysis/virtualcall.cpp           | 38 ++++++++++++++++++-
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 6c27f58d308aa..cea25fe0aaaa7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -123,6 +123,21 @@ void VirtualCallChecker::checkPreCall(const CallEvent 
&Call,
   if (!ObState)
     return;
 
+  // If we're directly inside the constructor/destructor of a final class,
+  // virtual dispatch is safe because there can be no derived classes.
+  // Note: We only suppress when directly in the ctor/dtor, not in helper
+  // functions, and not in base class ctors/dtors (which have broken vtables
+  // even when constructing a final derived class).
+  const auto *LCtx = C.getLocationContext();
+  const auto *CurDecl = LCtx->getDecl();
+  const CXXRecordDecl *CurClass = nullptr;
+  if (const auto *CurCtor = dyn_cast<CXXConstructorDecl>(CurDecl))
+    CurClass = CurCtor->getParent();
+  else if (const auto *CurDtor = dyn_cast<CXXDestructorDecl>(CurDecl))
+    CurClass = CurDtor->getParent();
+  if (CurClass && CurClass->hasAttr<FinalAttr>())
+    return;
+
   bool IsPure = MD->isPureVirtual();
 
   // At this point we're sure that we're calling a virtual method
diff --git a/clang/test/Analysis/virtualcall.cpp 
b/clang/test/Analysis/virtualcall.cpp
index 82285b6d12844..a533d35ca689b 100644
--- a/clang/test/Analysis/virtualcall.cpp
+++ b/clang/test/Analysis/virtualcall.cpp
@@ -84,6 +84,40 @@ class E final : public B {
   int foo() override;
 };
 
+// GH#178643: Virtual calls in destructor of a final class should not warn.
+class GH178643Base {
+public:
+  virtual void virtualMethod() {}
+  virtual ~GH178643Base() {
+    // Base class destructor should still warn even when destructing a final
+    // derived class, because the vtable points to the base class at this 
point.
+    virtualMethod(); // impure-warning {{Call to virtual method 
'GH178643Base::virtualMethod' during destruction bypasses virtual dispatch}}
+  }
+};
+
+class GH178643Derived final : public GH178643Base {
+public:
+  ~GH178643Derived() {
+    virtualMethod(); // no-warning: class is final, no derived classes exist
+  }
+};
+
+// Test constructor case for final class.
+class GH178643CtorBase {
+public:
+  virtual void virtualMethod() {}
+  GH178643CtorBase() {
+    virtualMethod(); // impure-warning {{Call to virtual method 
'GH178643CtorBase::virtualMethod' during construction bypasses virtual 
dispatch}}
+  }
+};
+
+class GH178643CtorDerived final : public GH178643CtorBase {
+public:
+  GH178643CtorDerived() {
+    virtualMethod(); // no-warning: class is final
+  }
+};
+
 class F {
 public:
   F() {
@@ -175,12 +209,14 @@ int main() {
   G g;
   H h;
   H h1(1);
-  X x; 
+  X x;
   X x1(1);
   M m;
   Y *y = new Y;
   delete y;
   header::Z z;
+  GH178643Derived gh178643;
+  GH178643CtorDerived gh178643ctor;
 }
 
 namespace PR34451 {

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

Reply via email to