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

>From 8e302b40c42988bc8afd95445ab987d04412cc55 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           | 17 +++++++
 clang/test/Analysis/virtualcall.cpp           | 45 ++++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 6c27f58d308aa..7b5c0a36e5452 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -123,6 +123,23 @@ 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();
+  if (const auto *CurCtor =
+          dyn_cast_or_null<CXXConstructorDecl>(CurDecl)) {
+    if (CurCtor->getParent()->hasAttr<FinalAttr>())
+      return;
+  } else if (const auto *CurDtor =
+                 dyn_cast_or_null<CXXDestructorDecl>(CurDecl)) {
+    if (CurDtor->getParent()->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..536b14af0a2b9 100644
--- a/clang/test/Analysis/virtualcall.cpp
+++ b/clang/test/Analysis/virtualcall.cpp
@@ -84,6 +84,47 @@ 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
+    helperMethod();  // Calls through helper still analyze the helper's context
+  }
+  void helperMethod() {
+    // Virtual calls through helper functions should still warn, because
+    // the helper could be called from other contexts where the object
+    // might not be of a final class type.
+    virtualMethod(); // impure-warning {{Call to virtual method 
'GH178643Base::virtualMethod' during destruction bypasses virtual dispatch}}
+  }
+};
+
+// 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 +216,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