https://github.com/WillemKauf updated 
https://github.com/llvm/llvm-project/pull/182916

>From 267e91b89c918eb9680a70d2ea5740a069780c67 Mon Sep 17 00:00:00 2001
From: Willem Kaufmann <[email protected]>
Date: Thu, 19 Mar 2026 21:14:08 -0400
Subject: [PATCH] [clang-tidy] Add `AllowExplicitObjectParameters` option to
 `avoid-capturing-lambda-coroutines`

Add an off-by-default `AllowExplicitObjectParameters` option to the
existing `cppcoreguidelines-avoid-capturing-lambda-coroutines` check.

When enabled, lambda coroutines that use C++23 "deducing this" (explicit
object parameter) are not flagged, since captures are moved into the
coroutine frame ([1], [2], [3]). In C++23 mode, the check also provides
fix-it hints to add `this auto` as the first parameter for lambdas that
don't use it.

The option is off by default to match the current C++ Core Guidelines,
which do not yet recognize explicit object parameters as a solution ([4]).
Once the guidelines adopt the proposal, the default can be flipped.

[1]: 
https://github.com/scylladb/seastar/blob/master/doc/lambda-coroutine-fiasco.md#solution-c23-and-up

[2]: https://www.scs.stanford.edu/~dm/blog/vexing-capture.html

[3]: https://lists.isocpp.org/std-proposals/2020/05/1391.php

[4]: 
https://github.com/isocpp/CppCoreGuidelines/pull/2289#issuecomment-3756500251
---
 .../AvoidCapturingLambdaCoroutinesCheck.cpp   | 103 +++++-
 .../AvoidCapturingLambdaCoroutinesCheck.h     |   8 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |   7 +
 .../avoid-capturing-lambda-coroutines.rst     |  32 ++
 ...tines-allow-explicit-object-parameters.cpp | 346 ++++++++++++++++++
 5 files changed, 489 insertions(+), 7 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines-allow-explicit-object-parameters.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
index 618554663ab91..1f8c13d950842 100644
--- 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
+++ 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
@@ -9,6 +9,7 @@
 #include "AvoidCapturingLambdaCoroutinesCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
 
 using namespace clang::ast_matchers;
 
@@ -21,12 +22,27 @@ AST_MATCHER(LambdaExpr, hasCoroutineBody) {
 }
 
 AST_MATCHER(LambdaExpr, hasCaptures) { return Node.capture_size() != 0U; }
+
+AST_MATCHER(LambdaExpr, hasDeducingThis) {
+  return Node.getCallOperator()->isExplicitObjectMemberFunction();
+}
 } // namespace
 
+AvoidCapturingLambdaCoroutinesCheck::AvoidCapturingLambdaCoroutinesCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      AllowExplicitObjectParameters(
+          Options.get("AllowExplicitObjectParameters", false)) {}
+
 void AvoidCapturingLambdaCoroutinesCheck::registerMatchers(
     MatchFinder *Finder) {
-  Finder->addMatcher(
-      lambdaExpr(hasCaptures(), hasCoroutineBody()).bind("lambda"), this);
+  auto Matcher = lambdaExpr(hasCaptures(), hasCoroutineBody());
+
+  if (AllowExplicitObjectParameters)
+    Matcher = lambdaExpr(hasCaptures(), hasCoroutineBody(),
+                         unless(hasDeducingThis()));
+
+  Finder->addMatcher(Matcher.bind("lambda"), this);
 }
 
 bool AvoidCapturingLambdaCoroutinesCheck::isLanguageVersionSupported(
@@ -34,12 +50,89 @@ bool 
AvoidCapturingLambdaCoroutinesCheck::isLanguageVersionSupported(
   return LangOpts.CPlusPlus20;
 }
 
+void AvoidCapturingLambdaCoroutinesCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "AllowExplicitObjectParameters",
+                AllowExplicitObjectParameters);
+}
+
 void AvoidCapturingLambdaCoroutinesCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *MatchedLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
-  diag(MatchedLambda->getExprLoc(),
-       "coroutine lambda may cause use-after-free, avoid captures or ensure "
-       "lambda closure object has guaranteed lifetime");
+
+  if (AllowExplicitObjectParameters && getLangOpts().CPlusPlus23) {
+    const CXXMethodDecl *Call = MatchedLambda->getCallOperator();
+    const bool HasExplicitParams = MatchedLambda->hasExplicitParameters();
+
+    auto DiagBuilder =
+        diag(MatchedLambda->getExprLoc(),
+             "coroutine lambda with captures may cause use-after-free; use "
+             "'this auto' as the first parameter to move captures into the "
+             "coroutine frame");
+
+    if (HasExplicitParams) {
+      const bool HasParams = !Call->param_empty();
+      if (HasParams) {
+        const ParmVarDecl *FirstParam = Call->parameters().front();
+        DiagBuilder << FixItHint::CreateInsertion(FirstParam->getBeginLoc(),
+                                                  "this auto, ");
+      } else {
+        DiagBuilder << FixItHint::CreateInsertion(
+            Call->getFunctionTypeLoc().getRParenLoc(), "this auto");
+      }
+    } else {
+      // No explicit parameter list — insert `(this auto) ` where the
+      // parameter list would go in the grammar:
+      // [captures] <tparams> t-requires front-attr (params)
+      // Start after the template parameter list (including its requires
+      // clause) or the capture list, then skip past any attributes that
+      // appear before the implicit parameter list position.
+      const auto &SM = *Result.SourceManager;
+      const auto &LO = getLangOpts();
+      SourceLocation InsertLoc;
+
+      if (const auto *TPL = MatchedLambda->getTemplateParameterList()) {
+        if (const Expr *RC = TPL->getRequiresClause())
+          InsertLoc = Lexer::getLocForEndOfToken(RC->getEndLoc(), 0, SM, LO);
+        else
+          InsertLoc =
+              Lexer::getLocForEndOfToken(TPL->getRAngleLoc(), 0, SM, LO);
+      } else {
+        InsertLoc = Lexer::getLocForEndOfToken(
+            MatchedLambda->getIntroducerRange().getEnd(), 0, SM, LO);
+      }
+
+      // Skip past any front-attributes. getRange() covers only the
+      // attribute name/arguments, not the enclosing brackets.
+      // Advance past the closing brackets based on the syntax:
+      //   `[[attr]]`                 — 2 tokens (`]]`)
+      //   `__attribute__((attr))`    — 2 tokens (`))`)
+      //   `__declspec(attr)`         — 1 token  (`)`)
+      //   keyword / other            — 0 tokens
+      if (Call->hasAttrs()) {
+        const auto *LastAttr = Call->getAttrs().back();
+        SourceLocation AttrEnd = Lexer::getLocForEndOfToken(
+            LastAttr->getRange().getEnd(), 0, SM, LO);
+        unsigned ClosingTokens = 0;
+        if (LastAttr->isStandardAttributeSyntax() ||
+            LastAttr->getSyntax() == AttributeCommonInfo::AS_GNU)
+          ClosingTokens = 2;
+        else if (LastAttr->getSyntax() == AttributeCommonInfo::AS_Declspec ||
+                 LastAttr->getSyntax() == AttributeCommonInfo::AS_Microsoft)
+          ClosingTokens = 1;
+        for (unsigned I = 0; I < ClosingTokens; ++I)
+          AttrEnd = Lexer::getLocForEndOfToken(AttrEnd, 0, SM, LO);
+        if (AttrEnd.isValid())
+          InsertLoc = AttrEnd;
+      }
+
+      DiagBuilder << FixItHint::CreateInsertion(InsertLoc, " (this auto)");
+    }
+  } else {
+    diag(MatchedLambda->getExprLoc(),
+         "coroutine lambda may cause use-after-free, avoid captures or ensure "
+         "lambda closure object has guaranteed lifetime");
+  }
 }
 
 } // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
index de59ff189c595..72e5ff3168719 100644
--- 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
+++ 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
@@ -21,11 +21,15 @@ namespace clang::tidy::cppcoreguidelines {
 /// 
https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.html
 class AvoidCapturingLambdaCoroutinesCheck : public ClangTidyCheck {
 public:
-  AvoidCapturingLambdaCoroutinesCheck(StringRef Name, ClangTidyContext 
*Context)
-      : ClangTidyCheck(Name, Context) {}
+  AvoidCapturingLambdaCoroutinesCheck(StringRef Name,
+                                      ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+
+private:
+  const bool AllowExplicitObjectParameters;
 };
 
 } // namespace clang::tidy::cppcoreguidelines
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 64c8fbbe2f07a..681e159c60599 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -191,6 +191,13 @@ 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-avoid-capturing-lambda-coroutines
+  <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>`
+  check by adding the `AllowExplicitObjectParameters` option. When enabled,
+  lambda coroutines using C++23 deducing ``this`` (explicit object parameter)
+  are not flagged, and fix-it hints are provided to add ``this auto`` to the
+  argument list of those that don't use it.
+
 - Improved :doc:`cppcoreguidelines-init-variables
   <clang-tidy/checks/cppcoreguidelines/init-variables>` check by ensuring that
   member pointers are correctly flagged as uninitialized.
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
index 58bfc35c557dc..ecf4519b11219 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
@@ -52,3 +52,35 @@ captures or ensuring the lambda closure object has a 
guaranteed lifetime.
 
 Following these guidelines can help ensure the safe and reliable use of
 coroutine lambdas in C++ code.
+
+Options
+-------
+
+.. option:: AllowExplicitObjectParameters
+
+   When set to `true`, lambda coroutines that use C++23 "deducing this"
+   (explicit object parameter, e.g. ``this auto``) are not flagged by this
+   check, because the captures are moved into the coroutine frame, decoupling
+   their lifetime from the lambda object. Additionally, when compiling in C++23
+   mode or later, the check will provide fix-it hints to add ``this auto`` as
+   the first parameter to lambda coroutines that do not already use it.
+
+   Default is `false`.
+
+   The example from above can be made safe and will pass this check with the
+   following change:
+
+.. code-block:: c++
+
+    int value = get_value();
+    std::shared_ptr<Foo> sharedFoo = get_foo();
+    {
+        // Pass "this auto" as the first argument to the lambda
+        const auto lambda = [value, sharedFoo](this auto) -> std::future<void>
+        {
+            co_await something();
+        };
+        lambda();
+    } // the lambda closure object has now gone out of scope, but captures are
+      // no longer coupled to its lifetime
+
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines-allow-explicit-object-parameters.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines-allow-explicit-object-parameters.cpp
new file mode 100644
index 0000000000000..ca59407ab8ca3
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines-allow-explicit-object-parameters.cpp
@@ -0,0 +1,346 @@
+// RUN: %check_clang_tidy -std=c++23 %s 
cppcoreguidelines-avoid-capturing-lambda-coroutines %t \
+// RUN:   -- -config='{CheckOptions: 
{cppcoreguidelines-avoid-capturing-lambda-coroutines.AllowExplicitObjectParameters:
 true}}' \
+// RUN:   -- -isystem %S/Inputs/system
+
+#include <coroutines.h>
+
+// --- Cases that SHOULD trigger the warning and provide fix-its ---
+
+void test_capture_no_parens() {
+  int x = 42;
+  [&x] -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free; use 'this auto' as the first parameter to move 
captures into the coroutine frame 
[cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    // CHECK-FIXES: {{^}}  [&x] (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_capture_empty_parens() {
+  int x = 42;
+  [&x]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_capture_with_params() {
+  int x = 42;
+  [&x](int a) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto, int a) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_capture_with_multiple_params() {
+  int x = 42;
+  [&x](int a, int b) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto, int a, int b) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_capture_by_value() {
+  int x = 42;
+  [x]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [x](this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_default_capture_ref() {
+  int x = 42;
+  [&]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&](this auto) -> task {{{$}}
+    (void)x;
+    co_return;
+  };
+}
+
+void test_default_capture_copy() {
+  int x = 42;
+  [=]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [=](this auto) -> task {{{$}}
+    (void)x;
+    co_return;
+  };
+}
+
+void test_init_capture() {
+  int x = 42;
+  [y = x]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [y = x](this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_init_capture_brace() {
+  int x = 42;
+  [y{x}]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [y{x}](this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+struct S {
+  void test_this_capture() {
+    [this]() -> task {
+      // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: coroutine lambda with 
captures may cause use-after-free
+      // CHECK-FIXES: {{^}}    [this](this auto) -> task {{{$}}
+      co_return;
+    };
+  }
+
+  void test_star_this_capture() {
+    [*this]() -> task {
+      // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: coroutine lambda with 
captures may cause use-after-free
+      // CHECK-FIXES: {{^}}    [*this](this auto) -> task {{{$}}
+      co_return;
+    };
+  }
+};
+
+void test_mutable() {
+  int x = 42;
+  [x]() mutable -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [x](this auto) mutable -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_noexcept() {
+  int x = 42;
+  [&x]() noexcept -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto) noexcept -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_template_params() {
+  int x = 42;
+  [&x]<typename T>(T a) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T>(this auto, T a) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_template_params_empty_parens() {
+  int x = 42;
+  [&x]<typename T>() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T>(this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_template_params_no_parens() {
+  int x = 42;
+  [&x]<typename T> -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T> (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_auto_param() {
+  int x = 42;
+  [&x](auto a) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto, auto a) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_front_attr_with_parens() {
+  int x = 42;
+  [&x] [[nodiscard]] () -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x] {{\[\[}}nodiscard]] (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_front_attr_no_parens() {
+  int x = 42;
+  [&x] [[nodiscard]] -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x] {{\[\[}}nodiscard]] (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_multiple_front_attrs_no_parens() {
+  int x = 42;
+  [&x] [[nodiscard]] [[deprecated("use something else")]] -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x] {{\[\[}}nodiscard]] {{\[\[}}deprecated("use 
something else")]] (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_template_with_front_attr() {
+  int x = 42;
+  [&x]<typename T> [[nodiscard]] (T a) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T> {{\[\[}}nodiscard]] (this auto, T 
a) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_gnu_attr_no_parens() {
+  int x = 42;
+  [&x] __attribute__((noinline)) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x] __attribute__((noinline)) (this auto) -> task 
{{{$}}
+    co_return;
+  };
+}
+
+void test_template_with_multiple_front_attrs_no_parens() {
+  int x = 42;
+  [&x]<typename T> [[nodiscard]] [[deprecated("bad")]] -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T> {{\[\[}}nodiscard]] 
{{\[\[}}deprecated("bad")]] (this auto) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_mixed_captures_default_ref() {
+  int x = 42, y = 0;
+  [&, x]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&, x](this auto) -> task {{{$}}
+    (void)y;
+    co_return;
+  };
+}
+
+void test_mixed_captures_default_copy() {
+  int x = 42, y = 0;
+  [=, &x]() -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [=, &x](this auto) -> task {{{$}}
+    (void)y;
+    co_return;
+  };
+}
+
+void test_variadic_template_params() {
+  int x = 42;
+  [&x]<typename... Ts>(Ts... args) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename... Ts>(this auto, Ts... args) -> task 
{{{$}}
+    co_return;
+  };
+}
+
+void test_param_pack() {
+  int x = 42;
+  [&x](auto&&... args) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto, auto&&... args) -> task {{{$}}
+    co_return;
+  };
+}
+
+template<typename T>
+concept Integral = requires(T t) { t + 1; };
+
+void test_template_requires_clause() {
+  int x = 42;
+  [&x]<typename T> requires Integral<T> (T a) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T> requires Integral<T> (this auto, T 
a) -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_template_requires_no_parens() {
+  int x = 42;
+  [&x]<typename T> requires Integral<T> -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x]<typename T> requires Integral<T> (this auto) 
-> task {{{$}}
+    co_return;
+  };
+}
+
+void test_trailing_requires() {
+  int x = 42;
+  [&x](auto a) -> task requires Integral<decltype(a)> {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto, auto a) -> task requires 
Integral<decltype(a)> {{{$}}
+    co_return;
+  };
+}
+
+void test_mutable_noexcept() {
+  int x = 42;
+  [x]() mutable noexcept -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [x](this auto) mutable noexcept -> task {{{$}}
+    co_return;
+  };
+}
+
+void test_noexcept_expr() {
+  int x = 42;
+  [&x]() noexcept(true) -> task {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: coroutine lambda with captures 
may cause use-after-free
+    // CHECK-FIXES: {{^}}  [&x](this auto) noexcept(true) -> task {{{$}}
+    co_return;
+  };
+}
+
+// --- Cases that should NOT trigger the warning ---
+
+void test_no_captures_no_coroutine() {
+  []() { return; };
+}
+
+void test_no_captures_coroutine() {
+  []() -> task { co_return; };
+}
+
+void test_deducing_this_coroutine() {
+  int x = 42;
+  [&x](this auto) -> task { co_return; };
+}
+
+void test_deducing_this_with_params() {
+  int x = 42;
+  [&x](this auto, int a) -> task { co_return; };
+}
+
+void test_deducing_this_with_template() {
+  int x = 42;
+  [&x]<typename T>(this auto, T a) -> task { co_return; };
+}
+
+void test_captures_not_coroutine() {
+  int x = 42;
+  [&x]() { (void)x; };
+}
+
+void test_no_captures_template_coroutine() {
+  []<typename T>(T a) -> task { co_return; };
+}
+
+void test_deducing_this_ref_qualified() {
+  int x = 42;
+  [&x](this auto&&) -> task { co_return; };
+}
+
+void test_deducing_this_with_requires() {
+  int x = 42;
+  [&x]<typename T>(this auto, T a) -> task requires Integral<T> { co_return; };
+}

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

Reply via email to