llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tidy Author: GopinathBalaji <details> <summary>Changes</summary> `cppcoreguidelines-missing-std-forward` warns that a generic lambda's `auto&&` parameter is never forwarded even when its body calls `std::forward<decltype(x)>(x)`. My change uses `TK_AsIs` traversal and associates each parameter with its owning function through `hasDeclContext`, allowing the check to recognize forwarding inside implicit lambda call operators. Template instantiations are excluded to avoid diagnosing instantiated copies. The regression test coverage includes: generic lambdas in C++14 and later, explicitly templated C++20 lambdas, nested lambdas and function templates, reference and value captures, unevaluated contexts, and forwarding only one of multiple parameters. Unforwarded parameters continue to warn. ### Validation: - All `missing-std-forward` lit tests pass. - The original reproducer no longer emits the false positive. Assisted-by: GPT 6.1 Sol Fixes #<!-- -->228393 --- Full diff: https://github.com/llvm/llvm-project/pull/231260.diff 4 Files Affected: - (modified) clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp (+5-7) - (modified) clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h (+1-1) - (modified) clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-cxx20.cpp (+6) - (modified) clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp (+108-1) ``````````diff diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp index 0cae9e232cd50..25aa86f86cf96 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 2dd13e2124d74..c8ccfc1864628 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 cbf3def7800bb..a6c53a51b20bb 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 136e4af7c8ee5..d4dbe7310c604 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 `````````` </details> https://github.com/llvm/llvm-project/pull/231260 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
