https://github.com/serge-sans-paille updated 
https://github.com/llvm/llvm-project/pull/188866

>From da13e5808957a852a92435431e4a78541fbe912b Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Thu, 26 Mar 2026 22:40:37 +0100
Subject: [PATCH 1/3] [clang-tidy] Improve bugprone.use-after-move interaction
 with explicit destructor call.

It is valid (although niche) to  call an explicit destructor after
moving the object.
---
 .../clang-tidy/bugprone/UseAfterMoveCheck.cpp          |  9 ++++++---
 clang-tools-extra/docs/ReleaseNotes.rst                |  2 ++
 .../docs/clang-tidy/checks/bugprone/use-after-move.rst |  2 +-
 .../clang-tidy/checkers/bugprone/use-after-move.cpp    | 10 ++++++++++
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 06b5940c648a3..d60098eab85ee 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -401,9 +401,12 @@ void UseAfterMoveFinder::getDeclRefs(
       }
     };
 
-    auto DeclRefMatcher = 
declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
-                                      unless(inDecltypeOrTemplateArg()))
-                              .bind("declref");
+    auto DeclRefMatcher =
+        declRefExpr(
+            hasDeclaration(equalsNode(MovedVariable)),
+            unless(inDecltypeOrTemplateArg()),
+            unless(hasParent(memberExpr(hasDeclaration(cxxDestructorDecl())))))
+            .bind("declref");
 
     AddDeclRefs(match(traverse(TK_AsIs, findAll(DeclRefMatcher)), 
*S->getStmt(),
                       *Context));
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 49901f8a706c6..25cef90df1e07 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -258,6 +258,8 @@ Changes in existing checks
   - Add support for annotation of user-defined types as having the same
     moved-from semantics as standard smart pointers.
 
+  - Do not report explicit call to destructor after move as an invalid use.
+
 - Improved :doc:`cppcoreguidelines-init-variables
   <clang-tidy/checks/cppcoreguidelines/init-variables>` check by ensuring that
   member pointers are correctly flagged as uninitialized.
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
index a0e2cc767854d..da72f742b38d0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
@@ -193,7 +193,7 @@ Use
 ---
 
 Any occurrence of the moved variable that is not a reinitialization (see below)
-is considered to be a use.
+or an explicit call to the variable destructor is considered to be a use.
 
 An exception to this are objects of type ``std::unique_ptr``,
 ``std::shared_ptr``, ``std::weak_ptr``, ``std::optional``, and ``std::any``,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index 94b950f855f72..dcab9c5e59665 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -89,6 +89,16 @@ void selfMove() {
   a.foo();
 }
 
+void * operator new(size_t, void *p);
+
+// Don't flag an explicit destructor call
+void explicitDestrucotr() {
+  alignas(A) char storage[sizeof(A)];
+  A& a = *new (storage) A();
+  std::move(a);
+  a.~A(); // It's always valid to destruct a moved object.
+}
+
 // A warning should only be emitted for one use-after-move.
 void onlyFlagOneUseAfterMove() {
   A a;

>From 6a8f95833b352cdefd698a080bbe0674d72f11bb Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Fri, 27 Mar 2026 23:37:28 +0100
Subject: [PATCH 2/3] fixup! [clang-tidy] Improve bugprone.use-after-move
 interaction with explicit destructor call.

---
 .../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 23 +++++++++++++++----
 .../checkers/bugprone/use-after-move.cpp      | 16 ++++++++++++-
 2 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index d60098eab85ee..9e9dfdc5de11e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -82,6 +82,21 @@ class UseAfterMoveFinder {
   llvm::SmallPtrSet<const CFGBlock *, 8> Visited;
 };
 
+AST_MATCHER_P(Expr, hasParentIgnoringParenImpCasts,
+              ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+  const Expr *E = &Node;
+  do {
+    const DynTypedNodeList Parents = Finder->getASTContext().getParents(*E);
+    if (Parents.size() != 1)
+      return false;
+    E = Parents[0].get<Expr>();
+    if (!E)
+      return false;
+  } while (isa<ImplicitCastExpr, ParenExpr>(E));
+
+  return InnerMatcher.matches(*E, Finder, Builder);
+}
+
 } // namespace
 
 static auto getNameMatcher(llvm::ArrayRef<StringRef> InvalidationFunctions) {
@@ -402,10 +417,10 @@ void UseAfterMoveFinder::getDeclRefs(
     };
 
     auto DeclRefMatcher =
-        declRefExpr(
-            hasDeclaration(equalsNode(MovedVariable)),
-            unless(inDecltypeOrTemplateArg()),
-            unless(hasParent(memberExpr(hasDeclaration(cxxDestructorDecl())))))
+        declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
+                    unless(inDecltypeOrTemplateArg()),
+                    unless(hasParentIgnoringParenImpCasts(
+                        memberExpr(hasDeclaration(cxxDestructorDecl())))))
             .bind("declref");
 
     AddDeclRefs(match(traverse(TK_AsIs, findAll(DeclRefMatcher)), 
*S->getStmt(),
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index dcab9c5e59665..6e354c215fc63 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -92,11 +92,25 @@ void selfMove() {
 void * operator new(size_t, void *p);
 
 // Don't flag an explicit destructor call
-void explicitDestrucotr() {
+void explicitDestructor() {
   alignas(A) char storage[sizeof(A)];
   A& a = *new (storage) A();
   std::move(a);
   a.~A(); // It's always valid to destruct a moved object.
+
+  A& b = *new (storage) A();
+  std::move(b);
+  (b).~A(); // Parenthesis should not change the behavior.
+  b.foo(); // But destruction is not a reinitialization.
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: 'b' used after it was moved
+  // CHECK-NOTES: [[@LINE-4]]:3: note: move occurred here
+
+  A& c = *new (storage) A();
+  std::move(c);
+  c.foo();
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: 'c' used after it was moved
+  // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+  c.~A();
 }
 
 // A warning should only be emitted for one use-after-move.

>From 412c6cb1bc3430100bcc1d18cbaa18172d100023 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Fri, 3 Apr 2026 12:08:44 +0200
Subject: [PATCH 3/3] fixup! fixup! [clang-tidy] Improve
 bugprone.use-after-move interaction with explicit destructor call.

---
 .../test/clang-tidy/checkers/bugprone/use-after-move.cpp    | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index 6e354c215fc63..80df2b99eb874 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -98,6 +98,12 @@ void explicitDestructor() {
   std::move(a);
   a.~A(); // It's always valid to destruct a moved object.
 
+  using B = AnnotatedContainer<int>;
+  alignas(B) char other_storage[sizeof(B)];
+  B& a_p = *new (other_storage) B();
+  std::move(a_p);
+  a_p.~B(); // Same as above, but with a template class.
+
   A& b = *new (storage) A();
   std::move(b);
   (b).~A(); // Parenthesis should not change the behavior.

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

Reply via email to