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&amp;&amp;` parameter is never forwarded even when its body calls 
`std::forward&lt;decltype(x)&gt;(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

Reply via email to