[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -388,9 +397,10 @@ void UseAfterMoveFinder::getReinits(
}
}
-enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+enum MoveType {
+ Forward = 0, // std::forward
+ Move = 1, // std::move
+ Invalidation = 2, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
higher-performance wrote:
Ah good point, done, thanks.
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 3fca92f9762cfa572d3098498b4c8e4ed0e0c86b Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 76 ---
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 56 +-
5 files changed, 123 insertions(+), 30 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6d134a0e896a0..b2e08fe688a1b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -388,18 +397,21 @@ void UseAfterMoveFinder::getReinits(
}
}
-enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+enum MoveType {
+ Forward = 0, // std::forward
+ Move = 1, // std::move
+ Invalidation = 2, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
- if (FuncDecl->getName() == "move")
-return MoveType::Move;
- if (FuncDecl->getName() == "forward")
-return MoveType::Forward;
+ if (FuncDecl->isInStdNamespace()) {
+if (FuncDecl->getName() == "move")
+ return MoveType::Move;
+if (FuncDecl->getName() == "forward")
+ return MoveType::Forward;
+ }
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +420,38 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
-
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Type;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Type;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{f
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -388,9 +397,10 @@ void UseAfterMoveFinder::getReinits(
}
}
-enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+enum MoveType {
+ Forward = 0, // std::forward
+ Move = 1, // std::move
+ Invalidation = 2, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
zeyi2 wrote:
A tiny suggestion: IMO we need to distinguish `std::move` and user-defined
`move` function.
If a user adds a custom function to `InvalidationFunctions` that happens to be
named `move`, the current logic will hit the early return `if
(FuncDecl->getName() == "move")` and treat it as `MoveType::Move`.
So the diagnostic will report: "variable used after it was moved", which might
be misleading.
Can we add another if before checking "move" and "forward"?
```c++
if (FuncDecl->isInStdNamespace()) {
if (FuncDecl->getName() == "move") return ...
if (FuncDecl->getName() == "forward") return ...
}
```
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 1ecfecc1a4a5af2171ecacca843e30443ad1cabb Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 66 ---
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 56 +++-
5 files changed, 117 insertions(+), 26 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6d134a0e896a0..cc1fa135c7f39 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -388,9 +397,10 @@ void UseAfterMoveFinder::getReinits(
}
}
-enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+enum MoveType {
+ Forward = 0, // std::forward
+ Move = 1, // std::move
+ Invalidation = 2, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,38 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
-
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Type;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Type;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -408,41 +418,55 @@ static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg, const SourceLocation UseLoc = Use.DeclRef->getExprLoc(); const SourceLocation MoveLoc = MovingCall->getExprLoc(); - const bool IsMove = (Type == MoveType::Move); + const int Kind = static_cast(Type); higher-performance wrote: Done. https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -253,3 +253,13 @@ For example, if an additional member variable is added to ``S``, it is easy to forget to add the reinitialization for this additional member. Instead, it is safer to assign to the entire struct in one go, and this will also avoid the use-after-move warning. + +Options +--- + +.. option:: InvalidationFunctions + + A semicolon-separated list of names of functions that cause their initial + arguments to be invalidated (e.g., closing a handle). + For member functions, the initial argument is considered to be the implicit + object argument (`this`). higher-performance wrote: Done. https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -384,37 +309,21 @@ Changes in existing checks - Improved :doc:`bugprone-unchecked-optional-access ` check by supporting ``NullableValue::makeValue`` and ``NullableValue::makeValueInplace`` to - prevent false-positives for ``BloombergLP::bdlb::NullableValue`` type, and by - adding the `IgnoreValueCalls` option to suppress diagnostics for - ``optional::value()`` and the `IgnoreSmartPointerDereference` option to - ignore optionals reached via smart-pointer-like dereference, while still - diagnosing UB-prone dereferences via ``operator*`` and ``operator->``. + prevent false-positives for ``BloombergLP::bdlb::NullableValue`` type. - Improved :doc:`bugprone-unhandled-self-assignment ` check by adding an additional matcher that generalizes the copy-and-swap idiom pattern detection. -- Improved :doc:`bugprone-unsafe-functions - ` check by hiding the default - suffix when the reason starts with the character `>` in the `CustomFunctions` - option. - -- Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables - ` check - by adding a new option `AllowThreadLocal` that suppresses warnings on - non-const global variables with thread-local storage duration. +- Improved :doc:`bugprone-bugprone-use-after-move + ` check by adding + an option to support custom invalidation functions. higher-performance wrote: Done. https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -1,5 +1,5 @@
-// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s
bugprone-use-after-move %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t --
-- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s
bugprone-use-after-move %t -- -config="{CheckOptions:
{bugprone-use-after-move.InvalidationFunctions:
'Database::StaticCloseConnection;Database::CloseConnection;FriendCloseConnection'}}"
-- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t --
-config="{CheckOptions: {bugprone-use-after-move.InvalidationFunctions:
'Database::StaticCloseConnection;Database::CloseConnection;FriendCloseConnection'}}"
-- -fno-delayed-template-parsing
higher-performance wrote:
Done.
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -1645,3 +1645,41 @@ void create() {
}
} // namespace issue82023
+
+namespace custom_invalidation
+{
+
+struct Database {
+ void CloseConnection();
+ static void StaticCloseConnection(Database&);
+ friend void FriendCloseConnection(Database&);
+ void Query();
+};
+
+void Run() {
higher-performance wrote:
Done.
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 66f76595d8a1a82923cb8dc14f222559f3b97f00 Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 66 ---
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 56 +++-
5 files changed, 117 insertions(+), 26 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6d134a0e896a0..ffa513099d058 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -388,9 +397,10 @@ void UseAfterMoveFinder::getReinits(
}
}
-enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+enum MoveType {
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,38 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
-
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Type;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Type;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-<< IsMove;
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
higher-performance wrote:
I can't do this. Name patterns are not necessarily exact string matches.
(Notice how we can have `::std::move`, `std::move`, `move`, etc.)
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 8b65f32ebba4913c793ec09a0919f7f7035f6cad Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 64 +--
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 42 +++-
5 files changed, 103 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6d134a0e896a0..8eef5445a1b77 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 63cd086b79a40d60bbd6a209ac48c24b7925728d Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 64 +--
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 42 +++-
5 files changed, 103 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6d134a0e896a0..8eef5445a1b77 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -1645,3 +1645,41 @@ void create() {
}
} // namespace issue82023
+
+namespace custom_invalidation
+{
+
+struct Database {
+ void CloseConnection();
+ static void StaticCloseConnection(Database&);
+ friend void FriendCloseConnection(Database&);
+ void Query();
+};
+
+void Run() {
vbvictor wrote:
Please add tests with template invalidation function, templated `struct
Database` class, templated `CloseConnection` method.
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -253,3 +253,13 @@ For example, if an additional member variable is added to ``S``, it is easy to forget to add the reinitialization for this additional member. Instead, it is safer to assign to the entire struct in one go, and this will also avoid the use-after-move warning. + +Options +--- + +.. option:: InvalidationFunctions + + A semicolon-separated list of names of functions that cause their initial + arguments to be invalidated (e.g., closing a handle). + For member functions, the initial argument is considered to be the implicit + object argument (`this`). vbvictor wrote: ```suggestion object argument (`this`). Default value is an empty string. ``` https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -384,37 +309,21 @@ Changes in existing checks - Improved :doc:`bugprone-unchecked-optional-access ` check by supporting ``NullableValue::makeValue`` and ``NullableValue::makeValueInplace`` to - prevent false-positives for ``BloombergLP::bdlb::NullableValue`` type, and by - adding the `IgnoreValueCalls` option to suppress diagnostics for - ``optional::value()`` and the `IgnoreSmartPointerDereference` option to - ignore optionals reached via smart-pointer-like dereference, while still - diagnosing UB-prone dereferences via ``operator*`` and ``operator->``. + prevent false-positives for ``BloombergLP::bdlb::NullableValue`` type. - Improved :doc:`bugprone-unhandled-self-assignment ` check by adding an additional matcher that generalizes the copy-and-swap idiom pattern detection. -- Improved :doc:`bugprone-unsafe-functions - ` check by hiding the default - suffix when the reason starts with the character `>` in the `CustomFunctions` - option. - -- Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables - ` check - by adding a new option `AllowThreadLocal` that suppresses warnings on - non-const global variables with thread-local storage duration. +- Improved :doc:`bugprone-bugprone-use-after-move + ` check by adding + an option to support custom invalidation functions. vbvictor wrote: ```suggestion `InvalidationFunctions` option to support custom invalidation functions. ``` https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -408,41 +418,55 @@ static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg, const SourceLocation UseLoc = Use.DeclRef->getExprLoc(); const SourceLocation MoveLoc = MovingCall->getExprLoc(); - const bool IsMove = (Type == MoveType::Move); + const int Kind = static_cast(Type); vbvictor wrote: Since we anyway cast `Type` to `int`, It's better to drop `class` in `enum class` and hardcode enum values to deterministic `int` values. Or there are places that still benefit having `enum class`? https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -1,5 +1,5 @@
-// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s
bugprone-use-after-move %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t --
-- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s
bugprone-use-after-move %t -- -config="{CheckOptions:
{bugprone-use-after-move.InvalidationFunctions:
'Database::StaticCloseConnection;Database::CloseConnection;FriendCloseConnection'}}"
-- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t --
-config="{CheckOptions: {bugprone-use-after-move.InvalidationFunctions:
'Database::StaticCloseConnection;Database::CloseConnection;FriendCloseConnection'}}"
-- -fno-delayed-template-parsing
vbvictor wrote:
Could we split into multiple `RUN` directives to keeps lines at reasonable
length (see other test files with `-config`).
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
vbvictor wrote:
To keep ~sanity~ _soundness_ check, I think we should pass
`InvalidationFunctions` to `determineMoveType` and write another `if
(llvm::is_contained(FuncDecl->getName(), InvalidationFunctions))` if IIRC that
`is_contained` does exist.
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From b3dc437a7eb6c921f1f418e65cdec834bf262e6c Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 64 +--
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../checks/bugprone/use-after-move.rst| 10 +++
.../checkers/bugprone/use-after-move.cpp | 42 +++-
5 files changed, 103 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index efb5ec64689cf..e557126fa2156 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,6 +73,7 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
@@ -78,6 +81,11 @@ class UseAfterMoveFinder {
} // namespace
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
// seeing if they are children of a TypeLoc), or
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/vbvictor commented: Please add release notes and documentation for new option https://github.com/llvm/llvm-project/pull/170346 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance updated
https://github.com/llvm/llvm-project/pull/170346
>From 0855ab7a54d19590f2e491be011f8260384b08e3 Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 64 +--
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
.../checkers/bugprone/use-after-move.cpp | 42 +++-
3 files changed, 89 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index efb5ec64689cf..3bf009b782306 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,11 +73,17 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
};
+auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
} // namespace
// Matches nodes that are
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-<< IsMove;
+<< Kind;
} else if (Use.UseHappensInLaterLoopIteration) {
Check->diag(UseLoc,
"the use happens in a later loop iteration than the "
-"%select{forward|move}0",
+"%select{forward|move|invalidation}0",
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
github-actions[bot] wrote:
:warning: C/C++ code linter clang-tidy found issues in your code. :warning:
You can test this locally with the following command:
```bash
git diff -U0 origin/main...HEAD --
clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h |
python3 clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py \
-path build -p1 -quiet
```
View the output from clang-tidy here.
```
clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp:82:13: warning:
place static function 'getNameMatcher' outside of an anonymous namespace
[llvm-prefer-static-over-anonymous-namespace]
82 | static auto getNameMatcher(llvm::ArrayRef
InvalidationFunctions) {
| ^
```
https://github.com/llvm/llvm-project/pull/170346
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
llvmbot wrote:
@llvm/pr-subscribers-clang-tidy
Author: None (higher-performance)
Changes
---
Full diff: https://github.com/llvm/llvm-project/pull/170346.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
(+44-20)
- (modified) clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h (+5-2)
- (modified)
clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp (+40-2)
``diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index efb5ec64689cf..404fc4de8ef3c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,11 +73,17 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
};
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
} // namespace
// Matches nodes that are
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-<< IsMove;
+<< Kind;
} else if (Use.UseHappensInLaterLoopIteration) {
Check->diag(UseLoc,
"the use happens in a later loop iteration than the "
-"%select{forward|move}0",
+"%select{forward|move|invalidation}0",
DiagnosticIDs::Note)
-<< IsMove;
+<< Kind;
}
}
+UseAfterMoveCheck::UseAfterMove
[clang-tools-extra] Extend bugprone-use-after-move check to allow custom invalidation functions (PR #170346)
https://github.com/higher-performance created
https://github.com/llvm/llvm-project/pull/170346
None
>From 8fbbf33787ff20fdc10df800e6b8c95935f493c7 Mon Sep 17 00:00:00 2001
From: higher-performance
Date: Tue, 2 Dec 2025 13:20:24 -0500
Subject: [PATCH] Extend bugprone-use-after-move check to allow custom
invalidation functions
---
.../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 64 +--
.../clang-tidy/bugprone/UseAfterMoveCheck.h | 7 +-
.../checkers/bugprone/use-after-move.cpp | 42 +++-
3 files changed, 89 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index efb5ec64689cf..404fc4de8ef3c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -19,6 +19,7 @@
#include "../utils/ExprSequence.h"
#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
#include
using namespace clang::ast_matchers;
@@ -48,7 +49,8 @@ struct UseAfterMove {
/// various internal helper functions).
class UseAfterMoveFinder {
public:
- UseAfterMoveFinder(ASTContext *TheContext);
+ UseAfterMoveFinder(ASTContext *TheContext,
+ llvm::ArrayRef InvalidationFunctions);
// Within the given code block, finds the first use of 'MovedVariable' that
// occurs after 'MovingCall' (the expression that performs the move). If a
@@ -71,11 +73,17 @@ class UseAfterMoveFinder {
llvm::SmallPtrSetImpl *DeclRefs);
ASTContext *Context;
+ llvm::ArrayRef InvalidationFunctions;
std::unique_ptr Sequence;
std::unique_ptr BlockMap;
llvm::SmallPtrSet Visited;
};
+static auto getNameMatcher(llvm::ArrayRef InvalidationFunctions) {
+ return anyOf(hasAnyName("::std::move", "::std::forward"),
+ matchers::matchesAnyListedName(InvalidationFunctions));
+}
+
} // namespace
// Matches nodes that are
@@ -92,8 +100,9 @@ static StatementMatcher inDecltypeOrTemplateArg() {
hasAncestor(expr(hasUnevaluatedContext(;
}
-UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
-: Context(TheContext) {}
+UseAfterMoveFinder::UseAfterMoveFinder(
+ASTContext *TheContext, llvm::ArrayRef InvalidationFunctions)
+: Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
std::optional
UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -359,7 +368,7 @@ void UseAfterMoveFinder::getReinits(
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())),
unless(callee(functionDecl(
-hasAnyName("::std::move", "::std::forward")))
+getNameMatcher(InvalidationFunctions)))
.bind("reinit");
Stmts->clear();
@@ -389,8 +398,9 @@ void UseAfterMoveFinder::getReinits(
}
enum class MoveType {
- Move,// std::move
- Forward, // std::forward
+ Forward, // std::forward
+ Move, // std::move
+ Invalidation, // other
};
static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
@@ -399,7 +409,7 @@ static MoveType determineMoveType(const FunctionDecl
*FuncDecl) {
if (FuncDecl->getName() == "forward")
return MoveType::Forward;
- llvm_unreachable("Invalid move type");
+ return MoveType::Invalidation;
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
@@ -408,29 +418,40 @@ static void emitDiagnostic(const Expr *MovingCall, const
DeclRefExpr *MoveArg,
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();
- const bool IsMove = (Type == MoveType::Move);
+ const int Kind = static_cast(Type);
- Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
- << MoveArg->getDecl()->getName() << IsMove;
- Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
+ Check->diag(UseLoc,
+ "'%0' used after it was %select{forwarded|moved|invalidated}1")
+ << MoveArg->getDecl()->getName() << Kind;
+ Check->diag(MoveLoc, "%select{forward|move|invalidation}0 occurred here",
DiagnosticIDs::Note)
- << IsMove;
+ << Kind;
if (Use.EvaluationOrderUndefined) {
Check->diag(
UseLoc,
-"the use and %select{forward|move}0 are unsequenced, i.e. "
+"the use and %select{forward|move|invalidation}0 are unsequenced, i.e.
"
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
-<< IsMove;
+<< Kind;
} else if (Use.UseHappensInLaterLoopIteration) {
Check->diag(UseLoc,
"the use happens in a later loop iteration than the "
-"%select{forward|move}0",
+"%select{forward|move|invalidation}0",
