https://github.com/voyager-jhk updated 
https://github.com/llvm/llvm-project/pull/199905

>From ab4dd9bee328573e052fc0dfacf8a939c897801c Mon Sep 17 00:00:00 2001
From: voyager-jhk <[email protected]>
Date: Wed, 27 May 2026 16:54:08 +0800
Subject: [PATCH] [clang-tidy] Fix false positive in bugprone-use-after-move
 with std::forward on derived classes

The `bugprone-use-after-move` check correctly identified partial moves when 
using `std::move` by matching the `ImplicitCastExpr` (DerivedToBase) as the 
parent of the call. However, when using `std::forward<Base>`, the cast occurs 
inside the argument, causing the matcher to miss the cast and falsely report a 
use-after-move.

This patch manually checks the first argument of the moving call for a 
`DerivedToBase` cast if the parent matcher fails, ensuring both `move` and 
`forward` are correctly identified as partial moves.

Fixes #63202
---
 .../clang-tidy/bugprone/UseAfterMoveCheck.cpp |  8 ++++
 .../use-after-move-forward-derived.cpp        | 42 +++++++++++++++++++
 2 files changed, 50 insertions(+)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move-forward-derived.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 399442f52bd33..1570c3a39ab07 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -641,6 +641,14 @@ void UseAfterMoveCheck::check(const 
MatchFinder::MatchResult &Result) {
   const CXXRecordDecl *MovedAs =
       ParentCast ? ParentCast->getType()->getAsCXXRecordDecl() : nullptr;
 
+  if (!MovedAs && CallMove && CallMove->getNumArgs() > 0) {
+    if (const auto *ArgCast =
+            dyn_cast<ImplicitCastExpr>(CallMove->getArg(0)->IgnoreParens())) {
+      if (ArgCast->getCastKind() == CK_DerivedToBase)
+        MovedAs = ArgCast->getType()->getAsCXXRecordDecl();
+    }
+  }
+
   for (Stmt *CodeBlock : CodeBlocks) {
     UseAfterMoveFinder Finder(Result.Context, InvalidationFunctions,
                               ReinitializationFunctions, MovedAs);
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move-forward-derived.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move-forward-derived.cpp
new file mode 100644
index 0000000000000..4322b94bdf00d
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move-forward-derived.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t
+
+#include <utility>
+
+struct Person {
+    Person() = default;
+    Person(Person&&) {}
+};
+
+struct SpecialPerson : Person {
+    int surname;
+    
+    // Valid partial move
+    SpecialPerson(SpecialPerson&& sp) 
+      : Person(std::move(sp)),
+        surname(std::move(sp.surname))
+        // CHECK-NOTES-NOT: [[@LINE-1]]:{{[0-9]+}}: warning: 'sp' used after 
it was moved
+    {}
+
+    // Valid partial forward (The original false positive bug)
+    SpecialPerson(SpecialPerson&& sp, int) 
+      : Person(std::forward<Person>(sp)),
+        surname(std::move(sp.surname))
+        // CHECK-NOTES-NOT: [[@LINE-1]]:{{[0-9]+}}: warning: 'sp' used after 
it was forwarded
+    {}
+
+    // Invalid full move (Must warn)
+    SpecialPerson(SpecialPerson&& sp, float) {
+        SpecialPerson other(std::move(sp));
+        sp.surname = 1;
+        // CHECK-NOTES: [[@LINE-1]]:{{[0-9]+}}: warning: 'sp' used after it 
was moved [bugprone-use-after-move]
+        // CHECK-NOTES: [[@LINE-3]]:{{[0-9]+}}: note: move occurred here
+    }
+
+    // Invalid full forward (Must warn)
+    SpecialPerson(SpecialPerson&& sp, double) {
+        SpecialPerson other(std::forward<SpecialPerson>(sp));
+        sp.surname = 1;
+        // CHECK-NOTES: [[@LINE-1]]:{{[0-9]+}}: warning: 'sp' used after it 
was forwarded [bugprone-use-after-move]
+        // CHECK-NOTES: [[@LINE-3]]:{{[0-9]+}}: note: forward occurred here
+    }
+};

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

Reply via email to