-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang-tidy] Add readability-avoid-default-lambda-capture #160150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 46 commits
35df1c6
dbb903f
689f95b
9991b9c
db17a4c
7dcf216
176d195
5f23dff
4c41332
330dbd8
31366e6
70df9df
0418517
0bcdbc4
ac709f4
5d4c2ca
c0b90d1
1172f73
66e6aaa
4bf58b6
a807dd0
8fdc097
ab8f4b9
a4348de
13b5049
043df7c
33af58b
51aa182
dd65b90
a9509f3
e9e0f9a
b2c3cc2
969558e
359fd6c
4e10e78
9765c90
33a79a0
8f21201
e49dd93
840c043
c4870ed
34ab8dd
48416d1
3ff1c7a
6cefb5f
0eadc10
8f374ff
31d0b93
597eb4a
5966f21
5477d2e
b0919ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,67 @@ | ||||||
| //===----------------------------------------------------------------------===// | ||||||
| // | ||||||
| // 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 "AvoidDefaultLambdaCaptureCheck.h" | ||||||
| #include "clang/ASTMatchers/ASTMatchFinder.h" | ||||||
| #include "clang/Basic/Lambda.h" | ||||||
| #include "clang/Lex/Lexer.h" | ||||||
|
|
||||||
| using namespace clang::ast_matchers; | ||||||
|
|
||||||
| namespace clang::tidy::readability { | ||||||
|
|
||||||
| static std::string generateCaptureText(const LambdaCapture &Capture) { | ||||||
| if (Capture.capturesThis()) | ||||||
| return Capture.getCaptureKind() == LCK_StarThis ? "*this" : "this"; | ||||||
|
|
||||||
| std::string Result; | ||||||
| if (Capture.getCaptureKind() == LCK_ByRef) | ||||||
| Result += "&"; | ||||||
|
|
||||||
| Result += Capture.getCapturedVar()->getName().str(); | ||||||
| return Result; | ||||||
| } | ||||||
|
|
||||||
| void AvoidDefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { | ||||||
| Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider excluding system headers.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't clang-tidy have a global option to exclude system headers? |
||||||
| } | ||||||
|
|
||||||
| void AvoidDefaultLambdaCaptureCheck::check( | ||||||
| const MatchFinder::MatchResult &Result) { | ||||||
| const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); | ||||||
| assert(Lambda); | ||||||
|
|
||||||
| const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); | ||||||
| if (DefaultCaptureLoc.isInvalid()) | ||||||
| return; | ||||||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| std::vector<std::string> ImplicitCaptures; | ||||||
| for (const LambdaCapture &Capture : Lambda->implicit_captures()) { | ||||||
| // It is impossible to explicitly capture a VLA in C++, since VLAs don't | ||||||
| // exist in ISO C++ and so the syntax was never created to capture them. | ||||||
| if (Capture.getCaptureKind() == LCK_VLAType) | ||||||
| return; | ||||||
| ImplicitCaptures.push_back(generateCaptureText(Capture)); | ||||||
| } | ||||||
|
|
||||||
| auto Diag = diag(DefaultCaptureLoc, | ||||||
| "lambda default captures are discouraged; " | ||||||
| "prefer to capture specific variables explicitly"); | ||||||
|
||||||
|
|
||||||
| // For template-dependent lambdas, the list of captures hasn't been created | ||||||
| // yet, so the list of implicit captures is empty. | ||||||
| if (ImplicitCaptures.empty() && Lambda->isGenericLambda()) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this condition is quite right. A "generic lambda" is one with a templated call operator, but the capture lists of those are known (see lines 33-34 of this AST: https://godbolt.org/z/M6nYc8c9s). For example, we can provide a fix-it just fine in the following case (and I think the check already does, although it would be good to add a test): void f() {
int a;
int b;
auto l = [&]<template T>(T foo) { return a + b; };
// becomes: [&a, &b]<template T>(T foo) { return a + b; };
}As far as I can tell, it's only when the lambda's type is dependent that the capture list isn't known and we can't provide a fix-it, so I think the condition should be something like:
Suggested change
|
||||||
| return; | ||||||
|
|
||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. avoid to fix-it hint in macro.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you elaborate on this comment? I don't really understand it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My best guess is: // no fixes here
#define MY_LAMBDA() [=]() { std::cout << "implicit_captured" << some_var; };
voif foo() { int some_var; MY_LAMBDA };
voif bar() { int some_var; MY_LAMBDA };or should worth testing too: #define CAPTURE_ALL &
[CAPTURE_ALL]() { std::cout << "implicit_captured" << some_var; };
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this would obviously break the linter and I need to figure out how to handle this case.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You could use IsInMacro on lambda location before generating fix-its.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case we could leave as is: #define CAPTURE_ALL &
[CAPTURE_ALL]() { std::cout << "implicit_captured" << some_var; }; |
||||||
| const std::string ReplacementText = llvm::join(ImplicitCaptures, ", "); | ||||||
|
|
||||||
| Diag << FixItHint::CreateReplacement(Lambda->getCaptureDefaultLoc(), | ||||||
| ReplacementText); | ||||||
| } | ||||||
|
|
||||||
| } // namespace clang::tidy::readability | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H | ||
| #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H | ||
|
|
||
| #include "../ClangTidyCheck.h" | ||
|
|
||
| namespace clang::tidy::readability { | ||
|
|
||
| /// Flags lambdas that use default capture modes | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here should be the same as the first section in doc |
||
| /// | ||
| /// For the user-facing documentation see: | ||
| /// https://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-default-lambda-capture.html | ||
| class AvoidDefaultLambdaCaptureCheck : public ClangTidyCheck { | ||
| public: | ||
| AvoidDefaultLambdaCaptureCheck(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; | ||
| } | ||
| bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||
| return LangOpts.CPlusPlus11; | ||
| } | ||
| }; | ||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| } // namespace clang::tidy::readability | ||
|
|
||
| #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| .. title:: clang-tidy - readability-avoid-default-lambda-capture | ||
|
|
||
| readability-avoid-default-lambda-capture | ||
| ======================================== | ||
|
|
||
| Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``). | ||
localspook marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mention somewere that check provide autofixes |
||
| Captures can lead to subtle bugs including dangling references and unnecessary | ||
| copies. Writing out the name of the variables being captured reminds programmers | ||
| and reviewers about what is being captured. | ||
|
|
||
| This check does not warn on variable-length array (VLA) captures. VLAs are not | ||
| ISO C++, and it is impossible to explicitly capture them as the syntax for doing | ||
| so does not exist. | ||
|
|
||
| Coding guidelines that recommend against defaulted lambda captures include: | ||
|
|
||
| * Item 31 of Effective Modern C++ by Scott Meyers | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing punctuation? |
||
|
|
||
| Example | ||
| ------- | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| #include <iostream> | ||
|
|
||
| class Widget { | ||
| std::vector<std::function<void(int)>> callbacks; | ||
| int widgetId; | ||
| void addCallback(int factoryId) { | ||
| callbacks.emplace_back( | ||
| [&](){ | ||
| std::cout << "Widget " << widgetId << " made in factory " << factoryId; | ||
| } | ||
| ); | ||
| } | ||
| } | ||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| When ``callbacks`` is executed, ``factoryId`` will dangle. Writing the name of | ||
| ``factoryId`` in the capture list reminds the reader that it is being captured, | ||
| which will hopefully lead to the bug being fixed during code review. | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| #include <iostream> | ||
|
|
||
| class Widget { | ||
| std::vector<std::function<void(int)>> callbacks; | ||
| int widgetId; | ||
| void addCallback(int factoryId) { | ||
| callbacks.emplace_back( | ||
| [&factoryId, &widgetId](){ // Why isn't factoryId captured by value?? | ||
| std::cout << "Widget " << widgetId << " made in factory " << factoryId; | ||
| } | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||||
| // RUN: %check_clang_tidy %s readability-avoid-default-lambda-capture %t -- -- -Wno-vla-extension -std=c++20 | ||||||||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
|
|
||||||||
| void test_default_captures() { | ||||||||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| int value = 42; | ||||||||
| int another = 10; | ||||||||
|
|
||||||||
| auto lambda1 = [=](int x) { return value + x; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda1 = [value](int x) { return value + x; }; | ||||||||
|
|
||||||||
| auto lambda2 = [&](int x) { return value + x; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda2 = [&value](int x) { return value + x; }; | ||||||||
|
|
||||||||
| auto lambda3 = [=, &another](int x) { return value + another + x; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda3 = [value, &another](int x) { return value + another + x; }; | ||||||||
|
|
||||||||
| auto lambda4 = [&, value](int x) { return value + another + x; }; | ||||||||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda4 = [&another, value](int x) { return value + another + x; }; | ||||||||
| } | ||||||||
|
|
||||||||
| template<typename... Args> | ||||||||
| void test_pack_expansion_captures(Args... args) { | ||||||||
| int local = 5; | ||||||||
|
|
||||||||
| auto lambda1 = [=]() { return (args + ...); }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
|
|
||||||||
| auto lambda2 = [&]() { return (args + ...); }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
|
|
||||||||
| auto lambda3 = [=]() { return (args + ...) + local; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
|
|
||||||||
| auto lambda4 = [&]() { return (args + ...) + local; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
|
|
||||||||
| auto lambda5 = [=, ...copied = args]() { return (copied + ...); }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
|
|
||||||||
| auto lambda6 = [&, ...refs = args]() { return (refs + ...); }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| } | ||||||||
|
|
||||||||
| void instantiate_pack_expansion_tests() { | ||||||||
| test_pack_expansion_captures(1, 2, 3); | ||||||||
| test_pack_expansion_captures(1.0, 2.0, 3.0); | ||||||||
| } | ||||||||
|
|
||||||||
| void test_acceptable_captures() { | ||||||||
vbvictor marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| 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 default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto outer = [outer_var, middle_var, inner_var]() { | ||||||||
|
|
||||||||
| auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto inner = [&outer_var, &middle_var, &inner_var](int x) { return outer_var + middle_var + inner_var + x; }; | ||||||||
|
|
||||||||
| 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 default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto create_adder = [](int x) { | ||||||||
| return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture | ||||||||
| }; | ||||||||
|
|
||||||||
| auto func1 = [&]() { return a; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto func1 = [&a]() { return a; }; | ||||||||
|
|
||||||||
| auto func2 = [=]() { return b; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto func2 = [b]() { return b; }; | ||||||||
| } | ||||||||
|
|
||||||||
| 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 default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda1 = [this, local]() { return member + local; }; | ||||||||
|
|
||||||||
| auto lambda2 = [&]() { return member + local; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: auto lambda2 = [this, &local]() { return member + local; }; | ||||||||
|
|
||||||||
| auto lambda3 = [this, local]() { return member + local; }; | ||||||||
| auto lambda4 = [this, &local]() { return member + local; }; | ||||||||
| } | ||||||||
| }; | ||||||||
|
|
||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These cases are contrived, but could we test that we suggest deleting default captures that don't capture anything? auto lambda1 = [&]() {};
// CHECK-FIXES: auto lambda1 = []() {};
auto lambda2 = [=]() {};
// CHECK-FIXES: auto lambda2 = []() {};
// If I'm right about the isGenericLambda condition being incorrect, I think
// the check currently doesn't provide a fix-it in this case, even though it could:
auto lambda3 = [&](auto) {};
// CHECK-FIXES auto lambda3 = [](auto) {}; |
||||||||
| // Lambda captures dependent on a template parameter don't have a fix it | ||||||||
| template<typename T> | ||||||||
| void test_template_lambdas() { | ||||||||
| T value{}; | ||||||||
|
|
||||||||
| auto lambda = [=](T x) { return value + x; }; | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| } | ||||||||
|
|
||||||||
| void instantiate_templates() { | ||||||||
| test_template_lambdas<int>(); | ||||||||
| test_template_lambdas<double>(); | ||||||||
| } | ||||||||
|
|
||||||||
| void test_init_captures() { | ||||||||
| int x = 3; | ||||||||
| int nx = 5; | ||||||||
|
|
||||||||
| int y1 = [&, z = x + 5]() -> int { | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: int y1 = [&nx, z = x + 5]() -> int { | ||||||||
| return z * z + nx; | ||||||||
| }(); | ||||||||
|
|
||||||||
| int y2 = [=, &ref = x]() { | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: int y2 = [nx, &ref = x]() { | ||||||||
| ref += 1; | ||||||||
| return nx - ref; | ||||||||
| }(); | ||||||||
|
|
||||||||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| int y3 = [=, &ref = x, z = x + 5]() { | ||||||||
| // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||||||||
| // CHECK-FIXES: int y3 = [nx, &ref = x, z = x + 5]() { | ||||||||
| ref += 2; | ||||||||
| return nx + z - ref; | ||||||||
| }(); | ||||||||
|
|
||||||||
| (void)y1; | ||||||||
| (void)y2; | ||||||||
| (void)y3; | ||||||||
| } | ||||||||
|
|
||||||||
| void test_vla_no_crash() { | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine the test is named
Suggested change
|
||||||||
| // VLAs create implicit VLA bound captures that cannot be written explicitly. | ||||||||
| // No warning should be issued. | ||||||||
| int n = 5; | ||||||||
| int vla[n]; | ||||||||
| for (int i = 0; i < n; ++i) { | ||||||||
| vla[i] = i * 10; | ||||||||
| } | ||||||||
|
Comment on lines
+177
to
+179
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This loop seems unnecessary; I don't think it exercises any part of the check:
Suggested change
|
||||||||
|
|
||||||||
| auto lambda = [&]() { return vla[0]; }; | ||||||||
| } | ||||||||
Uh oh!
There was an error while loading. Please reload this page.