https://github.com/GopinathBalaji created 
https://github.com/llvm/llvm-project/pull/231260

`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

>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] [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 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

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to