https://github.com/zeyi2 created https://github.com/llvm/llvm-project/pull/178651
Closes #176873 >From bab89778820a11949f63dce48b9a404a41a025aa Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Wed, 28 Jan 2026 23:39:33 +0800 Subject: [PATCH] [clang-tidy] Fix FP/FN in cppcoreguidelines-missing-std-forward --- .../MissingStdForwardCheck.cpp | 18 ++++---- clang-tools-extra/docs/ReleaseNotes.rst | 8 ++++ .../cppcoreguidelines/missing-std-forward.cpp | 46 +++++++++++++++++++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp index d1d81d510c8fb..77517a629030f 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp @@ -107,19 +107,21 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { auto CapturedInLambda = hasDeclContext(cxxRecordDecl( isLambda(), - hasParent(lambdaExpr(forCallable(equalsBoundNode("func")), - anyOf(CapturedInCaptureList, CapturedInBody))))); + hasAncestor(lambdaExpr(forCallable(equalsBoundNode("func")), + anyOf(CapturedInCaptureList, CapturedInBody))))); auto ToParam = hasAnyParameter(parmVarDecl(equalsBoundNode("param"))); auto ForwardCallMatcher = callExpr( callExpr().bind("call"), argumentCountIs(1), - hasArgument(0, declRefExpr(to(varDecl().bind("var")))), - forCallable( - anyOf(allOf(equalsBoundNode("func"), - functionDecl(hasAnyParameter(parmVarDecl(allOf( - equalsBoundNode("param"), equalsBoundNode("var")))))), - CapturedInLambda)), + hasArgument( + 0, declRefExpr(to( + varDecl(anyOf(equalsBoundNode("param"), + hasSameNameAsBoundNode("param"), + hasInitializer(ignoringParenImpCasts( + declRefExpr(to(equalsBoundNode("param"))))))) + .bind("var")))), + forCallable(anyOf(equalsBoundNode("func"), CapturedInLambda)), callee(unresolvedLookupExpr(hasAnyDeclaration( namedDecl(hasUnderlyingDecl(hasName(ForwardFunction)))))), diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 754880bd1a381..6faf18fc96b55 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,6 +136,14 @@ Changes in existing checks the invalidating function in the warning message when a custom invalidation function is used (via the `InvalidationFunctions` option). +- Improved :doc:`cppcoreguidelines-missing-std-forward + <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by: + + - Correctly handling forwarding in deeply nested lambdas. + + - Fixing a false negative when multiple parameters are used in a lambda and + only some of them are forwarded. + - Improved :doc:`llvm-use-ranges <clang-tidy/checks/llvm/use-ranges>` check by adding support for the following algorithms: ``std::accumulate``, ``std::replace_copy``, and diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp index 98c592db7ce22..47e2977d6fc12 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp @@ -105,6 +105,26 @@ void foo(X &&x, Y &&y) { use(y); } +template <typename T> +void nested_but_no_forward(T &&arg) { + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: forwarding reference parameter 'arg' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + [&]() + { + [&]() + { consumes_all(arg); }(); + }(); +} + +template <typename T, typename U> +void nested_forward_only_one(T &&arg1, U &&arg2) { + // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: forwarding reference parameter 'arg2' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + [&]() + { + [&]() + { consumes_all(std::forward<T>(arg1)); }(); + }(); +} + } // namespace positive_cases namespace negative_cases { @@ -182,6 +202,32 @@ void lambda_value_reference_auxiliary_var(T&& t) { [&x = t]() { T other = std::forward<T>(x); }; } +template <typename T> +void nested_forward(T &&arg) { + [&]() + { + [&]() + { consumes_all(std::forward<T>(arg)); }(); + }(); +} + +template <typename T> +void triple_nested_forward(T &&arg) { + [&]() + { + [&]() + { + [&]() + { consumes_all(std::forward<T>(arg)); }(); + }(); + }(); +} + +template <class T> +void lambda_renamed_capture(T&& t) { + [&a = t]() { consumes_all(std::forward<T>(a)); }; +} + } // namespace negative_cases namespace deleted_functions { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
