[clang-tools-extra] [clang-tidy] Let `bugprone-use-after-move` also handle calls to `std::forward` (PR #82673)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 22 10:31:47 PST 2024


https://github.com/AMS21 updated https://github.com/llvm/llvm-project/pull/82673

>From a3729196f3208c4f214ffbfbb28a9a51874a8fd2 Mon Sep 17 00:00:00 2001
From: AMS21 <AMS21.github at gmail.com>
Date: Thu, 22 Feb 2024 19:24:43 +0100
Subject: [PATCH] [clang-tidy] Let `bugprone-use-after-move` also handle calls
 to `std::forward`

Fixes #82023
---
 .../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 36 +++++++++---------
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 ++
 .../checkers/bugprone/use-after-move.cpp      | 37 +++++++++++++++++++
 3 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index c5b6b541096ca9..a55432cfa3ea4b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -330,7 +330,8 @@ void UseAfterMoveFinder::getReinits(
                             traverse(TK_AsIs, DeclRefMatcher),
                             unless(parmVarDecl(hasType(
                                 references(qualType(isConstQualified())))))),
-                        unless(callee(functionDecl(hasName("::std::move")))))))
+                        unless(callee(functionDecl(
+                            hasAnyName("::std::move", "::std::forward")))))))
           .bind("reinit");
 
   Stmts->clear();
@@ -387,22 +388,23 @@ void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
   // the bool.
   auto TryEmplaceMatcher =
       cxxMemberCallExpr(callee(cxxMethodDecl(hasName("try_emplace"))));
-  auto CallMoveMatcher =
-      callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
-               hasArgument(0, declRefExpr().bind("arg")),
-               unless(inDecltypeOrTemplateArg()),
-               unless(hasParent(TryEmplaceMatcher)), expr().bind("call-move"),
-               anyOf(hasAncestor(compoundStmt(
-                         hasParent(lambdaExpr().bind("containing-lambda")))),
-                     hasAncestor(functionDecl(anyOf(
-                         cxxConstructorDecl(
-                             hasAnyConstructorInitializer(withInitializer(
-                                 expr(anyOf(equalsBoundNode("call-move"),
-                                            hasDescendant(expr(
-                                                equalsBoundNode("call-move")))))
-                                     .bind("containing-ctor-init"))))
-                             .bind("containing-ctor"),
-                         functionDecl().bind("containing-func"))))));
+  auto CallMoveMatcher = callExpr(
+      argumentCountIs(1),
+      callee(functionDecl(hasAnyName("::std::move", "::std::forward"))),
+      hasArgument(0, declRefExpr().bind("arg")),
+      unless(inDecltypeOrTemplateArg()), unless(hasParent(TryEmplaceMatcher)),
+      expr().bind("call-move"),
+      anyOf(hasAncestor(compoundStmt(
+                hasParent(lambdaExpr().bind("containing-lambda")))),
+            hasAncestor(functionDecl(
+                anyOf(cxxConstructorDecl(
+                          hasAnyConstructorInitializer(withInitializer(
+                              expr(anyOf(equalsBoundNode("call-move"),
+                                         hasDescendant(expr(
+                                             equalsBoundNode("call-move")))))
+                                  .bind("containing-ctor-init"))))
+                          .bind("containing-ctor"),
+                      functionDecl().bind("containing-func"))))));
 
   Finder->addMatcher(
       traverse(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a0b9fcfe0d7774..55c47c7617ce2a 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -130,6 +130,10 @@ Changes in existing checks
   <clang-tidy/checks/bugprone/unused-local-non-trivial-variable>` check by
   ignoring local variable with ``[maybe_unused]`` attribute.
 
+- Improved :doc:`bugprone-use-after-move
+  <clang-tidy/checks/bugprone/use-after-move>` check to also handle
+  calls to ``std::forward``.
+
 - Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer
   <clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>`
   by removing enforcement of rule `C.48
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 00b1da1e727e4f..0138064ed811b5 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
@@ -111,6 +111,18 @@ constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
   return static_cast<typename remove_reference<_Tp>::type &&>(__t);
 }
 
+template <class _Tp>
+constexpr _Tp&&
+forward(typename std::remove_reference<_Tp>::type& __t) noexcept {
+  return static_cast<_Tp&&>(__t);
+}
+
+template <class _Tp>
+constexpr _Tp&&
+forward(typename std::remove_reference<_Tp>::type&& __t) noexcept {
+  return static_cast<_Tp&&>(__t);
+}
+
 } // namespace std
 
 class A {
@@ -1525,3 +1537,28 @@ class PR38187 {
 private:
   std::string val_;
 };
+
+namespace issue82023
+{
+
+struct S {
+  S();
+  S(S&&);
+};
+
+void consume(S s);
+
+template <typename T>
+void forward(T&& t) {
+  consume(std::forward<T>(t));
+  consume(std::forward<T>(t));
+  // CHECK-NOTES: [[@LINE-1]]:27: warning: 't' used after it was moved
+  // CHECK-NOTES: [[@LINE-3]]:11: note: move occurred here
+}
+
+void create() {
+  S s;
+  forward(std::move(s));
+}
+
+} // namespace issue82023



More information about the cfe-commits mailing list