[clang-tools-extra] 54178fc - [clang-tidy] add check for capturing lambda coroutines
Piotr Zegar via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 10 06:07:08 PST 2023
Author: Noah Watkins
Date: 2023-03-10T14:06:50Z
New Revision: 54178fc6161a5856bea608dce0d726787a3b71c3
URL: https://github.com/llvm/llvm-project/commit/54178fc6161a5856bea608dce0d726787a3b71c3
DIFF: https://github.com/llvm/llvm-project/commit/54178fc6161a5856bea608dce0d726787a3b71c3.diff
LOG: [clang-tidy] add check for capturing lambda coroutines
Signed-off-by: Noah Watkins <noah at redpanda.com>
Reviewed By: ChuanqiXu
Differential Revision: https://reviews.llvm.org/D137514
Added:
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
Modified:
clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
new file mode 100644
index 0000000000000..de9c9eaa7f407
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
@@ -0,0 +1,45 @@
+//===--- AvoidCapturingLambdaCoroutinesCheck.cpp - clang-tidy -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidCapturingLambdaCoroutinesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void AvoidCapturingLambdaCoroutinesCheck::registerMatchers(
+ MatchFinder *Finder) {
+ Finder->addMatcher(lambdaExpr().bind("lambda"), this);
+}
+
+void AvoidCapturingLambdaCoroutinesCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+ if (!Lambda) {
+ return;
+ }
+
+ const auto *Body = dyn_cast<CoroutineBodyStmt>(Lambda->getBody());
+ if (!Body) {
+ return;
+ }
+
+ if (Lambda->captures().empty()) {
+ return;
+ }
+
+ diag(Lambda->getBeginLoc(), "found capturing coroutine lambda");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
new file mode 100644
index 0000000000000..63895f3354414
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidCapturingLambdaCoroutinesCheck.h - clang-tidy -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// The normal usage of captures in lambdas are problematic when the lambda is a
+/// coroutine because the captures are destroyed after the first suspension
+/// point. Using the captures after this point is a use-after-free issue.
+///
+/// For the user-facing documentation see:
+/// http://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) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
index bd7a999a71743..4210c3ea03fc8 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyCppCoreGuidelinesModule
AvoidCaptureDefaultWhenCapturingThisCheck.cpp
+ AvoidCapturingLambdaCoroutinesCheck.cpp
AvoidConstOrRefDataMembersCheck.cpp
AvoidDoWhileCheck.cpp
AvoidGotoCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
index ac70fc8eaa24c..ac4b8d7b01d7a 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -15,6 +15,7 @@
#include "../modernize/UseOverrideCheck.h"
#include "../readability/MagicNumbersCheck.h"
#include "AvoidCaptureDefaultWhenCapturingThisCheck.h"
+#include "AvoidCapturingLambdaCoroutinesCheck.h"
#include "AvoidConstOrRefDataMembersCheck.h"
#include "AvoidDoWhileCheck.h"
#include "AvoidGotoCheck.h"
@@ -50,6 +51,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule {
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<AvoidCaptureDefaultWhenCapturingThisCheck>(
"cppcoreguidelines-avoid-capture-default-when-capturing-this");
+ CheckFactories.registerCheck<AvoidCapturingLambdaCoroutinesCheck>(
+ "cppcoreguidelines-avoid-capturing-lambda-coroutines");
CheckFactories.registerCheck<modernize::AvoidCArraysCheck>(
"cppcoreguidelines-avoid-c-arrays");
CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index e8a74f8402460..64908944913fc 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -120,6 +120,13 @@ New checks
Checks that all implicit and explicit inline functions in header files are
tagged with the ``LIBC_INLINE`` macro.
+- New :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines
+ <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>` check.
+
+ Adds check for cpp core guideline: "CP.51: Do not use capturing lambdas that
+ are coroutines."
+
+
New check aliases
^^^^^^^^^^^^^^^^^
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
new file mode 100644
index 0000000000000..c199152edeac3
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
@@ -0,0 +1,31 @@
+.. title:: clang-tidy - cppcoreguidelines-avoid-capturing-lambda-coroutines
+
+cppcoreguidelines-avoid-capturing-lambda-coroutines
+===================================================
+
+Warns if a capturing lambda is a coroutine. For example:
+
+.. code-block:: c++
+
+ int c;
+
+ [c] () -> task { co_return; };
+ [&] () -> task { int y = c; co_return; };
+ [=] () -> task { int y = c; co_return; };
+
+ struct s {
+ void m() {
+ [this] () -> task { co_return; };
+ }
+ };
+
+All of the cases above will trigger the warning. However, implicit captures
+do not trigger the warning unless the body of the lambda uses the capture.
+For example, the following do not trigger the warning.
+
+.. code-block:: c++
+
+ int c;
+
+ [&] () -> task { co_return; };
+ [=] () -> task { co_return; };
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5a2f9c877a961..0eb15a9d382e0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -180,6 +180,7 @@ Clang-Tidy Checks
`concurrency-mt-unsafe <concurrency/mt-unsafe.html>`_,
`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous.html>`_,
`cppcoreguidelines-avoid-capture-default-when-capturing-this <cppcoreguidelines/avoid-capture-default-when-capturing-this.html>`_,
+ `cppcoreguidelines-avoid-capturing-lambda-coroutines <cppcoreguidelines/avoid-capturing-lambda-coroutines.html>`_, "Yes"
`cppcoreguidelines-avoid-const-or-ref-data-members <cppcoreguidelines/avoid-const-or-ref-data-members.html>`_,
`cppcoreguidelines-avoid-do-while <cppcoreguidelines/avoid-do-while.html>`_,
`cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto.html>`_,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
new file mode 100644
index 0000000000000..9a8a88e5d0283
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
@@ -0,0 +1,35 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s cppcoreguidelines-avoid-capturing-lambda-coroutines %t -- -- \
+// RUN: -isystem %S/../readability/Inputs/identifier-naming/system
+
+#include <coroutines.h>
+
+void Caught() {
+ int v;
+
+ [&] () -> task { int y = v; co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ [=] () -> task { int y = v; co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ [v] () -> task { co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ [&v] () -> task { co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ [y=v] () -> task { co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ [y{v}] () -> task { co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+}
+
+struct S {
+ void m() {
+ [this] () -> task { co_return; };
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: found capturing coroutine lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+ }
+};
+
+void Safe() {
+ int v;
+ [] () -> task { co_return; };
+ [&] () -> task { co_return; };
+ [=] () -> task { co_return; };
+}
More information about the cfe-commits
mailing list