https://github.com/GopinathBalaji updated https://github.com/llvm/llvm-project/pull/231260
>From 67bb6e96c311998e6e6103a20ab547b421f10b9b Mon Sep 17 00:00:00 2001 From: Gopinath Balaji <[email protected]> Date: Mon, 12 Oct 2026 13:24:44 -0500 Subject: [PATCH 1/3] [clang-tidy] Fixed missing-std-forward false positives in lambdas Recognize forwarding inside generic lambda call operators by using TK_AsIs traversal and matching each parameter's owing function through its declaration context. Exclude template instantiations to avoid diagnosing instantiated copies. Also added regression coverage for generic and explicitly templated lambdas, nested callables, captures, unevaluated contexts, and parameter-specific forwarding. Fixes #228393 --- .../MissingStdForwardCheck.cpp | 12 +- .../MissingStdForwardCheck.h | 2 +- .../missing-std-forward-cxx20.cpp | 6 + .../cppcoreguidelines/missing-std-forward.cpp | 109 +++++++++++++++++- 4 files changed, 120 insertions(+), 9 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp index 0cae9e232cd501..25aa86f86cf96c 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp @@ -136,13 +136,11 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( parmVarDecl( parmVarDecl().bind("param"), hasIdentifier(), - unless(hasAttr(attr::Kind::Unused)), isTemplateTypeParameter(), - hasAncestor(functionDecl().bind("func")), - hasAncestor(functionDecl( - isDefinition(), equalsBoundNode("func"), ToParam, - unless(anyOf( - isDeleted(), - traverse(TK_AsIs, hasDescendant(ForwardCallMatcher))))))), + unless(hasAttr(attr::Kind::Unused)), unless(isInstantiated()), + isTemplateTypeParameter(), + hasDeclContext(functionDecl( + functionDecl().bind("func"), isDefinition(), ToParam, + unless(anyOf(isDeleted(), hasDescendant(ForwardCallMatcher)))))), this); } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h index 2dd13e2124d742..c8ccfc18646285 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h @@ -28,7 +28,7 @@ class MissingStdForwardCheck : public ClangTidyCheck { return LangOpts.CPlusPlus11; } std::optional<TraversalKind> getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; + return TK_AsIs; } void storeOptions(ClangTidyOptions::OptionMap &Opts) override; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-cxx20.cpp index cbf3def7800bb6..a6c53a51b20bb5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-cxx20.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-cxx20.cpp @@ -22,3 +22,9 @@ void mixed_parameters(T &&t, auto &&u) { (void)t; (void)u; } + +void explicitly_templated_lambda_forwards() { + auto forwards = []<typename T>(T &&x) { + (void)std::forward<T>(x); + }; +} 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 136e4af7c8ee57..d4dbe7310c604f 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 @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-missing-std-forward %t -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++11 %s cppcoreguidelines-missing-std-forward %t -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++14-or-later -check-suffixes=,CXX14 %s cppcoreguidelines-missing-std-forward %t -- -- -fno-delayed-template-parsing #include <utility> @@ -279,3 +280,109 @@ template<typename F> void unused_argument3(F&& _) {} } // namespace unused_arguments + +#if __cplusplus >= 201402L + +namespace generic_lambdas { + +void forwards_parameter() { + auto lambda = [](auto &&x) { + (void)std::forward<decltype(x)>(x); + }; +} + +void does_not_forward_parameter() { + auto lambda = [](auto &&x) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:27: warning: forwarding reference parameter 'x' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + (void)x; + }; +} + +void forwards_parameter_by_reference_capture() { + auto lambda = [](auto &&x) { + [&x]() { + (void)std::forward<decltype(x)>(x); + }(); + }; +} + +void does_not_forward_parameter_by_value_capture() { + auto lambda = [](auto &&x) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:27: warning: forwarding reference parameter 'x' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + [x]() { + (void)std::forward<decltype(x)>(x); + }(); + }; +} + +template <typename T> +void forwards_parameter_in_template() { + auto lambda = [](auto &&x) { + (void)std::forward<decltype(x)>(x); + }; +} + +void forwards_only_one_parameter() { + auto lambda = [](auto &&x, auto &&y) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:37: warning: forwarding reference parameter 'y' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + (void)std::forward<decltype(x)>(x); + (void)y; + }; +} + +void forwards_only_inner_lambda_parameter() { + auto outer = [](auto &&x) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:26: warning: forwarding reference parameter 'x' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + (void)x; + auto inner = [](auto &&x) { + (void)std::forward<decltype(x)>(x); + }; + }; +} + +// decltype examines a type; it does not execute the forwarding expression. +void does_not_forward_in_decltype() { + auto lambda = [](auto &&x) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:27: warning: forwarding reference parameter 'x' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + using ForwardedType = decltype(std::forward<decltype(x)>(x)); + }; +} + +// sizeof does not execute this forwarding expression either. +void does_not_forward_in_sizeof() { + auto lambda = [](auto &&x) { + // CHECK-MESSAGES-CXX14: :[[@LINE-1]]:27: warning: forwarding reference parameter 'x' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward] + (void)sizeof(std::forward<decltype(x)>(x)); + }; +} + +// Instantiating the lambda for lvalues and rvalues must not introduce warnings. +void forwards_instantiated_parameter() { + auto lambda = [](auto &&x) { + (void)std::forward<decltype(x)>(x); + }; + + int value = 0; + lambda(value); + lambda(0); +} + +// const auto&& is not a forwarding reference. +void const_rvalue_reference_parameter() { + auto lambda = [](const auto &&x) { + (void)x; + }; +} + +template <typename T> +void forwards_outer_and_inner_parameters(T &&x) { + auto inner = [](auto &&y) { + (void)std::forward<decltype(y)>(y); + }; + + (void)std::forward<T>(x); +} + +} // namespace generic_lambdas + +#endif // __cplusplus >= 201402L >From 0dc10d6978425dd8327c4899c845959909306bf2 Mon Sep 17 00:00:00 2001 From: Gopinath Balaji <[email protected]> Date: Wed, 14 Oct 2026 06:07:22 -0500 Subject: [PATCH 2/3] [clang-tidy] Added release note for missing-std-forward lambda fix --- clang-tools-extra/docs/ReleaseNotes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 41aa783cabd248..7c638e50996c2e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -198,6 +198,11 @@ infrastructure are described first, followed by tool-specific sections. <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by diagnosing unforwarded `auto&&` parameters in C++20 abbreviated function templates. +- Improved {doc}`cppcoreguidelines-missing-std-forward + <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by fixing + false positives for correctly forwarded parameters in generic lambdas, + including C++20 explicitly templated lambdas. + - 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. >From d5fc1f6240f8e183fb96db3c9d28d33cce64531e Mon Sep 17 00:00:00 2001 From: Gopinath Balaji <[email protected]> Date: Wed, 14 Oct 2026 06:27:38 -0500 Subject: [PATCH 3/3] [clang-tidy] Removed duplicate point for missing-std-forward lambda fix --- clang-tools-extra/docs/ReleaseNotes.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 7c638e50996c2e..32c88f691e8314 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -196,10 +196,7 @@ infrastructure are described first, followed by tool-specific sections. - Improved {doc}`cppcoreguidelines-missing-std-forward <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by diagnosing - unforwarded `auto&&` parameters in C++20 abbreviated function templates. - -- Improved {doc}`cppcoreguidelines-missing-std-forward - <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by fixing + unforwarded `auto&&` parameters in C++20 abbreviated function templates. Also fixed false positives for correctly forwarded parameters in generic lambdas, including C++20 explicitly templated lambdas. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
