https://github.com/jjmarr-amd updated https://github.com/llvm/llvm-project/pull/160150
>From 35df1c6ea3af8dbaea2d7049ae79b14ce39f0774 Mon Sep 17 00:00:00 2001 From: JJ Marr <jj.m...@amd.com> Date: Fri, 11 Jul 2025 14:40:57 -0400 Subject: [PATCH 01/11] Bugprone-default-lambda-capture on-behalf-of: @AMD <jj.m...@amd.com> --- .../bugprone/BugproneTidyModule.cpp | 3 + .../clang-tidy/bugprone/CMakeLists.txt | 1 + .../bugprone/DefaultLambdaCaptureCheck.cpp | 35 +++++++ .../bugprone/DefaultLambdaCaptureCheck.h | 26 +++++ clang-tools-extra/docs/ReleaseNotes.rst | 9 ++ .../bugprone/default-lambda-capture.rst | 42 ++++++++ .../docs/clang-tidy/checks/list.rst | 1 + .../bugprone/default-lambda-capture.cpp | 98 +++++++++++++++++++ 8 files changed, 215 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 491de6acea2b7..db99d57c511b8 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -23,6 +23,7 @@ #include "CopyConstructorInitCheck.h" #include "CrtpConstructorAccessibilityCheck.h" #include "DanglingHandleCheck.h" +#include "DefaultLambdaCaptureCheck.h" #include "DynamicStaticInitializersCheck.h" #include "EasilySwappableParametersCheck.h" #include "EmptyCatchCheck.h" @@ -134,6 +135,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-copy-constructor-init"); CheckFactories.registerCheck<DanglingHandleCheck>( "bugprone-dangling-handle"); + CheckFactories.registerCheck<DefaultLambdaCaptureCheck>( + "bugprone-default-lambda-capture"); CheckFactories.registerCheck<DynamicStaticInitializersCheck>( "bugprone-dynamic-static-initializers"); CheckFactories.registerCheck<EasilySwappableParametersCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index 46bc8efd44bc5..66125c9d22c1c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -19,6 +19,7 @@ add_clang_library(clangTidyBugproneModule STATIC CopyConstructorInitCheck.cpp CrtpConstructorAccessibilityCheck.cpp DanglingHandleCheck.cpp + DefaultLambdaCaptureCheck.cpp DynamicStaticInitializersCheck.cpp EasilySwappableParametersCheck.cpp EmptyCatchCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp new file mode 100644 index 0000000000000..6c95fbc984c5a --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -0,0 +1,35 @@ +#include "DefaultLambdaCaptureCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { + // Match any lambda expression + Finder->addMatcher(lambdaExpr().bind("lambda"), this); +} + +void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); + if (!Lambda) + return; + + // Check if lambda has a default capture + if (Lambda->getCaptureDefault() == LCD_None) + return; + + SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); + if (DefaultCaptureLoc.isInvalid()) + return; + + const char *CaptureKind = + (Lambda->getCaptureDefault() == LCD_ByCopy) ? "by-copy" : "by-reference"; + + diag(DefaultCaptureLoc, "lambda %0 default capture is discouraged; " + "prefer to capture specific variables explicitly") + << CaptureKind; +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h new file mode 100644 index 0000000000000..ac47c866cfccd --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h @@ -0,0 +1,26 @@ +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/** Flags lambdas that use default capture modes + * + * For the user-facing documentation see: + * http://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html + */ +class DefaultLambdaCaptureCheck : public ClangTidyCheck { +public: + DefaultLambdaCaptureCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 7cdff86beeec6..30d0bffb78f39 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -194,6 +194,15 @@ New checks Finds virtual function overrides with different visibility than the function in the base class. +- New :doc:`bugprone-default-lambda-capture + <clang-tidy/checks/bugprone/default-lambda-capture>` check. + + Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``) + and suggests using explicit captures instead. Default captures can lead to + subtle bugs including dangling references with ``[&]``, unnecessary copies + with ``[=]``, and make code less maintainable by hiding which variables are + actually being captured. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst new file mode 100644 index 0000000000000..026acf9f1894b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst @@ -0,0 +1,42 @@ +.. title:: clang-tidy - bugprone-default-lambda-capture + +bugprone-default-lambda-capture +=============================== + +Warns when lambda expressions use default capture modes (``[=]`` or ``[&]``) +instead of explicitly capturing specific variables. Default captures can make +code less readable and more error-prone by making it unclear which variables +are being captured and how. + +Implements Item 31 of Effective Modern C++ by Scott Meyers. + +Example +------- + +.. code-block:: c++ + + void example() { + int x = 1; + int y = 2; + + // Bad - default capture by copy + auto lambda1 = [=]() { return x + y; }; + + // Bad - default capture by reference + auto lambda2 = [&]() { return x + y; }; + + // Good - explicit captures + auto lambda3 = [x, y]() { return x + y; }; + auto lambda4 = [&x, &y]() { return x + y; }; + } + +The check will warn on: + +- Default capture by copy: ``[=]`` +- Default capture by reference: ``[&]`` +- Mixed captures with defaults: ``[=, &x]`` or ``[&, x]`` + +The check will not warn on: + +- Explicit captures: ``[x]``, ``[&x]``, ``[x, y]``, ``[this]`` +- Empty capture lists: ``[]`` diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index c490d2ece2e0a..cb6254ee36f42 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -91,6 +91,7 @@ Clang-Tidy Checks :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes" :doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes" :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`, + :doc:`bugprone-default-lambda-capture <bugprone/default-lambda-capture>`, :doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`, :doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`, :doc:`bugprone-empty-catch <bugprone/empty-catch>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp new file mode 100644 index 0000000000000..f820b4c9b8a0e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp @@ -0,0 +1,98 @@ +// RUN: %check_clang_tidy %s bugprone-default-lambda-capture %t + +void test_default_captures() { + int value = 42; + int another = 10; + + auto lambda1 = [=](int x) { return value + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto lambda2 = [&](int x) { return value + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto lambda3 = [=, &another](int x) { return value + another + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto lambda4 = [&, value](int x) { return value + another + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] +} + +void test_acceptable_captures() { + int value = 42; + int another = 10; + + auto lambda1 = [value](int x) { return value + x; }; + auto lambda2 = [&value](int x) { return value + x; }; + auto lambda3 = [value, another](int x) { return value + another + x; }; + auto lambda4 = [&value, &another](int x) { return value + another + x; }; + + auto lambda5 = [](int x, int y) { return x + y; }; + + struct S { + int member = 5; + void foo() { + auto lambda = [this]() { return member; }; + } + }; +} + +void test_nested_lambdas() { + int outer_var = 1; + int middle_var = 2; + int inner_var = 3; + + auto outer = [=]() { + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + return inner(10); + }; +} + +void test_lambda_returns() { + int a = 1, b = 2, c = 3; + + auto create_adder = [=](int x) { + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture + }; + + auto func1 = [&]() { return a; }; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto func2 = [=]() { return b; }; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] +} + +class TestClass { + int member = 42; + +public: + void test_member_function_lambdas() { + int local = 10; + + auto lambda1 = [=]() { return member + local; }; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto lambda2 = [&]() { return member + local; }; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + + auto lambda3 = [this, local]() { return member + local; }; + auto lambda4 = [this, &local]() { return member + local; }; + } +}; + +template<typename T> +void test_template_lambdas() { + T value{}; + + auto lambda = [=](T x) { return value + x; }; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] +} + +void instantiate_templates() { + test_template_lambdas<int>(); + test_template_lambdas<double>(); +} >From 689f95b2ba46d6ca319e0735b5f5474bfc14f999 Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 09:58:59 -0400 Subject: [PATCH 02/11] Fix headers on-behalf-of: @amd <jj.m...@amd.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 8 ++++++++ .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 6c95fbc984c5a..0ee65df4b9860 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// +// 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 "DefaultLambdaCaptureCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h index ac47c866cfccd..9af861aaf2e93 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// +// 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_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H >From 9991b9ceda13c036e78c0e95978fe16f0bde5959 Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 10:21:44 -0400 Subject: [PATCH 03/11] remove superfluous comments. on-behalf-of: @amd <jj.m...@amd.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 0ee65df4b9860..6db5cc8fc10bb 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -15,7 +15,6 @@ using namespace clang::ast_matchers; namespace clang::tidy::bugprone { void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { - // Match any lambda expression Finder->addMatcher(lambdaExpr().bind("lambda"), this); } @@ -24,7 +23,6 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { if (!Lambda) return; - // Check if lambda has a default capture if (Lambda->getCaptureDefault() == LCD_None) return; >From db17a4c5a29faa47c69ddb48edb2b0316287c5bc Mon Sep 17 00:00:00 2001 From: "Marr, J J" <jj.m...@amd.com> Date: Mon, 22 Sep 2025 10:37:30 -0400 Subject: [PATCH 04/11] add new matcher on-behalf-of: @AMD <jj.m...@amd.com> --- .../bugprone/DefaultLambdaCaptureCheck.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 6db5cc8fc10bb..7fc3e571db220 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -14,8 +14,15 @@ using namespace clang::ast_matchers; namespace clang::tidy::bugprone { +namespace { +AST_MATCHER(LambdaExpr, hasDefaultCapture) { + return Node.getCaptureDefault() != LCD_None; +} + +} // namespace + void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(lambdaExpr().bind("lambda"), this); + Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this); } void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { @@ -23,8 +30,8 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { if (!Lambda) return; - if (Lambda->getCaptureDefault() == LCD_None) - return; + // No need to check getCaptureDefault() != LCD_None since our custom matcher + // hasDefaultCapture() already ensures this condition SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); if (DefaultCaptureLoc.isInvalid()) >From 7dcf2162c2a6df4057585e2898bc8feb4536a67c Mon Sep 17 00:00:00 2001 From: "Marr, J J" <jj.m...@amd.com> Date: Mon, 22 Sep 2025 11:51:27 -0400 Subject: [PATCH 05/11] Replace if with assert on-behalf-of: @amd <jj.m...@amd.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 7fc3e571db220..4db95101025cc 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -27,11 +27,7 @@ void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); - if (!Lambda) - return; - - // No need to check getCaptureDefault() != LCD_None since our custom matcher - // hasDefaultCapture() already ensures this condition + assert(Lambda); SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); if (DefaultCaptureLoc.isInvalid()) >From 176d195cc753b3c95b9a82305e1fe1267e181cfa Mon Sep 17 00:00:00 2001 From: "Marr, J J" <jj.m...@amd.com> Date: Mon, 22 Sep 2025 11:52:40 -0400 Subject: [PATCH 06/11] Remove specific warning type on-behalf-of: @amd <jj.m...@amd.com> --- .../bugprone/DefaultLambdaCaptureCheck.cpp | 8 ++----- .../bugprone/default-lambda-capture.cpp | 24 +++++++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 4db95101025cc..288feb7853e0b 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -33,12 +33,8 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { if (DefaultCaptureLoc.isInvalid()) return; - const char *CaptureKind = - (Lambda->getCaptureDefault() == LCD_ByCopy) ? "by-copy" : "by-reference"; - - diag(DefaultCaptureLoc, "lambda %0 default capture is discouraged; " - "prefer to capture specific variables explicitly") - << CaptureKind; + diag(DefaultCaptureLoc, "lambda default captures are discouraged; " + "prefer to capture specific variables explicitly"); } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp index f820b4c9b8a0e..010edf11f0a2b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp @@ -5,16 +5,16 @@ void test_default_captures() { int another = 10; auto lambda1 = [=](int x) { return value + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto lambda2 = [&](int x) { return value + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto lambda3 = [=, &another](int x) { return value + another + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto lambda4 = [&, value](int x) { return value + another + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] } void test_acceptable_captures() { @@ -42,10 +42,10 @@ void test_nested_lambdas() { int inner_var = 3; auto outer = [=]() { - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] return inner(10); }; @@ -55,15 +55,15 @@ void test_lambda_returns() { int a = 1, b = 2, c = 3; auto create_adder = [=](int x) { - // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture }; auto func1 = [&]() { return a; }; - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto func2 = [=]() { return b; }; - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] } class TestClass { @@ -74,10 +74,10 @@ class TestClass { int local = 10; auto lambda1 = [=]() { return member + local; }; - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto lambda2 = [&]() { return member + local; }; - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] auto lambda3 = [this, local]() { return member + local; }; auto lambda4 = [this, &local]() { return member + local; }; @@ -89,7 +89,7 @@ void test_template_lambdas() { T value{}; auto lambda = [=](T x) { return value + x; }; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture] } void instantiate_templates() { >From 5f23dfff1a8368ebca7c2da691201ea1277ad128 Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 12:25:50 -0400 Subject: [PATCH 07/11] Sync documentation to release notes on-behalf-of: @amd <jj.m...@amd.com> --- .../checks/bugprone/default-lambda-capture.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst index 026acf9f1894b..f1fcf3ec52948 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst @@ -3,10 +3,11 @@ bugprone-default-lambda-capture =============================== -Warns when lambda expressions use default capture modes (``[=]`` or ``[&]``) -instead of explicitly capturing specific variables. Default captures can make -code less readable and more error-prone by making it unclear which variables -are being captured and how. + Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``) + and suggests using explicit captures instead. Default captures can lead to + subtle bugs including dangling references with ``[&]``, unnecessary copies + with ``[=]``, and make code less maintainable by hiding which variables are + actually being captured. Implements Item 31 of Effective Modern C++ by Scott Meyers. >From 4c413327a64669d5254f0d6e343ca5c394701611 Mon Sep 17 00:00:00 2001 From: JJ Marr <jjmar...@amd.com> Date: Mon, 22 Sep 2025 13:00:22 -0400 Subject: [PATCH 08/11] Update clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h Co-authored-by: EugeneZelenko <eugene.zele...@gmail.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h index 9af861aaf2e93..ad48316708b1b 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h @@ -16,7 +16,7 @@ namespace clang::tidy::bugprone { /** Flags lambdas that use default capture modes * * For the user-facing documentation see: - * http://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html + * https://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html */ class DefaultLambdaCaptureCheck : public ClangTidyCheck { public: >From 330dbd8ca5eeed45d63d1a44c15eeb5357a8a4ef Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 13:01:23 -0400 Subject: [PATCH 09/11] Remove superfluous include on-behalf-of: @amd <jj.m...@amd.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 288feb7853e0b..8f52aeb59ead6 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DefaultLambdaCaptureCheck.h" -#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; >From 31366e6b34dce3ab7e5f24d07f81ad10ecd9b875 Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 13:09:55 -0400 Subject: [PATCH 10/11] Fix doc and release notes on-behalf-of: @amd <jj.m...@amd.com> --- clang-tools-extra/docs/ReleaseNotes.rst | 14 +++++--------- .../checks/bugprone/default-lambda-capture.rst | 10 +++++----- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 780cf41373128..9d2e8dcad7045 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -167,6 +167,11 @@ New checks Detects default initialization (to 0) of variables with ``enum`` type where the enum has no enumerator with value of 0. +- New :doc:`bugprone-default-lambda-capture + <clang-tidy/checks/bugprone/default-lambda-capture>` check. + + Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``) + - New :doc:`bugprone-derived-method-shadowing-base-method <clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check. @@ -203,15 +208,6 @@ New checks Finds virtual function overrides with different visibility than the function in the base class. -- New :doc:`bugprone-default-lambda-capture - <clang-tidy/checks/bugprone/default-lambda-capture>` check. - - Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``) - and suggests using explicit captures instead. Default captures can lead to - subtle bugs including dangling references with ``[&]``, unnecessary copies - with ``[=]``, and make code less maintainable by hiding which variables are - actually being captured. - New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst index f1fcf3ec52948..9cedc6276e1b3 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst @@ -3,11 +3,11 @@ bugprone-default-lambda-capture =============================== - Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``) - and suggests using explicit captures instead. Default captures can lead to - subtle bugs including dangling references with ``[&]``, unnecessary copies - with ``[=]``, and make code less maintainable by hiding which variables are - actually being captured. +Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``) + +Default captures can lead to subtle bugs including dangling references with +``[&]``, unnecessary copies with ``[=]``, and make code less maintainable by +hiding which variables are actually being captured. Implements Item 31 of Effective Modern C++ by Scott Meyers. >From 70df9dff73c3b3de4dcdfbed8b44186ff2000997 Mon Sep 17 00:00:00 2001 From: jjmarr-amd <jj.m...@amd.com> Date: Mon, 22 Sep 2025 14:43:19 -0400 Subject: [PATCH 11/11] Fix const on-behalf-of: @amd <jj.m...@amd.com> --- .../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp index 8f52aeb59ead6..a7a18ccb30864 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp @@ -28,7 +28,7 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) { const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); assert(Lambda); - SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); + const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); if (DefaultCaptureLoc.isInvalid()) return; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits