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

>From a49ec7448b98c9262363e8400133c7a7a7ee07f8 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Thu, 13 Aug 2026 16:54:31 +0200
Subject: [PATCH] [clang-tidy] Add [[clang::annotate("clang-tidy",
 "bugprone-use-after-move", "specified_after_move")]] to inform
 bugprone-use-after-move that a call usage is safe after a move
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

À la std::unique_ptr where it's ok to test for nullability a moved-from
instance, several user-class may allow some method call on a moved-from
object, typically checking if a moved-from container is empty, etc.
---
 .../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 50 ++++++++++++++-----
 clang-tools-extra/docs/ReleaseNotes.md        |  4 ++
 .../checkers/bugprone/use-after-move.cpp      | 12 +++++
 3 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index b13367e25dcb2..a184e616e62a1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -30,6 +30,14 @@ namespace clang::tidy::bugprone {
 
 using matchers::hasUnevaluatedContext;
 
+static std::optional<StringRef> getStringLiteral(const Expr *E) {
+  assert(E);
+  if (const auto *SL = dyn_cast<StringLiteral>(E->IgnoreParenImpCasts()))
+    return SL->getString();
+  return std::nullopt;
+}
+
+
 namespace {
 AST_MATCHER_P(Expr, hasParentIgnoringParenImpCasts,
               ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
@@ -46,6 +54,28 @@ AST_MATCHER_P(Expr, hasParentIgnoringParenImpCasts,
   return InnerMatcher.matches(*E, Finder, Builder);
 }
 
+// Methods can be decorated with [[clang::annotate]] to specify it has
+// a user-defined behavior when called on a moved-from.
+AST_MATCHER(CXXMethodDecl, hasSpecifiedAfterMoveAnnotation) {
+  for(const AnnotateAttr *Attr : Node.specific_attrs<AnnotateAttr>()) {
+    if (Attr->getAnnotation() != "clang-tidy")
+      continue;
+
+    if (Attr->args_size() != 2)
+      continue;
+
+    std::optional<StringRef> Plugin = getStringLiteral(Attr->args_begin()[0]);
+    std::optional<StringRef> Annotation =
+        getStringLiteral(Attr->args_begin()[1]);
+
+    if (Plugin && Annotation && *Plugin == "bugprone-use-after-move" &&
+        *Annotation == "specified_after_move")
+      return true;
+         }
+         return false;
+              }
+
+
 /// Contains information about a use-after-move.
 struct UseAfterMove {
   // The DeclRefExpr that constituted the use of the object.
@@ -351,13 +381,6 @@ void UseAfterMoveFinder::getUsesAndReinits(
   });
 }
 
-static std::optional<StringRef> getStringLiteral(const Expr *E) {
-  assert(E);
-  if (const auto *SL = dyn_cast<StringLiteral>(E->IgnoreParenImpCasts()))
-    return SL->getString();
-  return std::nullopt;
-}
-
 // User defined types can use [[clang::annotate]] to mark smart-pointer-like
 // types with a specified move from state that matches the standard smart
 // pointer's moved-from state (nullptr).
@@ -434,12 +457,13 @@ void UseAfterMoveFinder::getDeclRefs(
     };
 
     const auto DeclRefMatcher =
-        declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
-                    unless(inDecltypeOrTemplateArg()),
-                    unless(hasParentIgnoringParenImpCasts(
-                        memberExpr(hasDeclaration(cxxDestructorDecl())))),
-                    optionally(hasParentIgnoringParenImpCasts(
-                        memberExpr().bind("member-expr"))))
+        declRefExpr(
+            hasDeclaration(equalsNode(MovedVariable)),
+            unless(inDecltypeOrTemplateArg()),
+            unless(hasParentIgnoringParenImpCasts(memberExpr(hasDeclaration(
+                anyOf(cxxDestructorDecl(), 
cxxMethodDecl(hasSpecifiedAfterMoveAnnotation())))))),
+            optionally(hasParentIgnoringParenImpCasts(
+                memberExpr().bind("member-expr"))))
             .bind("declref");
 
     AddDeclRefs(match(traverse(TK_AsIs, findAll(DeclRefMatcher)), 
*S->getStmt(),
diff --git a/clang-tools-extra/docs/ReleaseNotes.md 
b/clang-tools-extra/docs/ReleaseNotes.md
index ef3e6c49ce172..0fd8398b86839 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -118,6 +118,10 @@ infrastructure are described first, followed by 
tool-specific sections.
   <clang-tidy/checks/bugprone/std-namespace-modification>` when checking
   lambda closure types used as template arguments.
 
+- Improved {doc}`bugprone-use-after-move
+  <clang-tidy/checks/bugprone/use-after-move>` check to honor new
+  `[[clang::annotate("clang-tidy", "bugprone-use-after-move", 
"specified_after_move")]]` attribute.
+
 - Improved {doc}`cppcoreguidelines-pro-type-member-init
   <clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check by treating
   `std::array` the same as built-in arrays when `IgnoreArrays` option is 
enabled.
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 1dd67941bd84c..d6a68f30e3c0d 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
@@ -68,6 +68,9 @@ class AnnotatedContainer {
 
   void foo() const;
   [[clang::reinitializes]] void clear();
+  [[clang::annotate("clang-tidy",
+                        "bugprone-use-after-move",
+                        "specified_after_move")]] bool empty() const;
 };
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -1007,6 +1010,15 @@ void reinitAnnotation() {
   }
 }
 
+void usableOnMovedAnnotation() {
+  {
+    AnnotatedContainer<int> obj;
+    std::move(obj);
+    obj.empty();
+    // No warning expected, empty is flagged as usable_on_moved
+  }
+}
+
 
////////////////////////////////////////////////////////////////////////////////
 // Tests for annotations on smart-pointer-like types
 

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

Reply via email to