Author: Moonn Date: 2026-10-13T13:29:44+08:00 New Revision: f1136210323eb4cf169ea544c48fa650275a8c79
URL: https://github.com/llvm/llvm-project/commit/f1136210323eb4cf169ea544c48fa650275a8c79 DIFF: https://github.com/llvm/llvm-project/commit/f1136210323eb4cf169ea544c48fa650275a8c79.diff LOG: [clang-tidy] Fix false positive in performance-no-automatic-move for captured variables (#231359) performance-no-automatic-move matched any `return x` where `x` is a const local variable, without checking whether `x` is actually local to the function doing the return. Inside a lambda, a captured variable still points at the enclosing function's VarDecl, so `[&x] { return x; }` was diagnosed. But captured variables are never implicitly moved from (Sema bails on refersToEnclosingVariableOrCapture() before it looks at constness), so dropping the const still gives a copy. Now we skip DeclRefExprs that refer to a capture, same as UseStdMoveCheck. A const local declared inside the lambda body is still diagnosed. AI Usage: an AI assistant was used while working on this fix, and I went through and tested every change myself. Fixes #227240 Added: Modified: clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp clang-tools-extra/docs/ReleaseNotes.md clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp index ca23488be204a..3722d33cf54cb 100644 --- a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp @@ -20,6 +20,10 @@ namespace { AST_MATCHER(VarDecl, isNRVOVariable) { return Node.isNRVOVariable(); } +AST_MATCHER(DeclRefExpr, refersToEnclosingVariableOrCapture) { + return Node.refersToEnclosingVariableOrCapture(); +} + } // namespace NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name, @@ -62,8 +66,11 @@ void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) { ignoringElidableConstructorCall(ignoringParenImpCasts( cxxConstructExpr( hasDeclaration(anyOf(LValueRefCtor, ConstRefRefCtor)), - hasArgument(0, ignoringParenImpCasts(declRefExpr( - to(NonNrvoConstLocalVariable))))) + hasArgument( + 0, + ignoringParenImpCasts(declRefExpr( + to(NonNrvoConstLocalVariable), + unless(refersToEnclosingVariableOrCapture()))))) .bind("ctor_call")))))), this); } diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index a6d8c764728b4..1448005253556 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -314,6 +314,11 @@ infrastructure are described first, followed by tool-specific sections. {option}`ForRangeLoopClasses` to configure container classes that can be used as sources in range-based `for` loops. +- Improved {doc}`performance-no-automatic-move + <clang-tidy/checks/performance/no-automatic-move>` check by no longer + warning when returning a variable captured by a lambda or a block, which is + never implicitly moved from. + - Improved {doc}`performance-prefer-single-char-overloads <clang-tidy/checks/performance/prefer-single-char-overloads>` check to avoid offering fix-its for string literals originating from macro diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp index 1ef7d16e38393..70b017b936148 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s performance-no-automatic-move %t +// RUN: %check_clang_tidy -std=c++11-or-later %s performance-no-automatic-move %t -- -- -fblocks struct Obj { Obj(); @@ -115,3 +115,32 @@ FromConstRefOnly FromConstRefOnly() { const Obj obj = Make<Obj>(); return obj; } + +void Captures() { + const Obj obj = Make<Obj>(); + auto ByRef = [&obj]() -> NonTemplate { return obj; }; + auto ByCopy = [obj]() -> NonTemplate { return obj; }; + auto DefaultByRef = [&]() -> NonTemplate { return obj; }; + auto DefaultByCopy = [=]() -> NonTemplate { return obj; }; +} + +void LambdaLocal() { + auto L = []() -> NonTemplate { + const Obj obj = Make<Obj>(); + return obj; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: constness of 'obj' prevents automatic move [performance-no-automatic-move] + }; +} + +void BlockCaptures() { + const Obj obj = Make<Obj>(); + auto B = ^NonTemplate { return obj; }; +} + +void BlockLocal() { + auto B = ^NonTemplate { + const Obj obj = Make<Obj>(); + return obj; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: constness of 'obj' prevents automatic move [performance-no-automatic-move] + }; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
