r291905 - [Sema] Add warning for unused lambda captures
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 16 07:54:31 PST 2017
On Wed, Feb 15, 2017 at 7:42 PM, Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> https://bugs.llvm.org/show_bug.cgi?id=31977 makes the good point that this
> is warning on a certain idiomatic use of capture-by-value to extend the
> lifetime of an RAII object; consider:
>
> shared_ptr<Foo> p = /*...*/;
> int *q = &p->n;
> return [=, p] { return *q++; }
>
> Here, we'll warn that the capture of p is unused, but it's not -- the "use"
> is to hold a reference to keep the Foo object alive.
>
> I'd suggest suppressing the warning for a by-copy capture of a variable with
> a non-trivial destructor (this mirrors what we do for -Wunused-variable).
Thank you for the compelling example -- I agree, that's a good
solution to the issue.
~Aaron
>
> On 13 January 2017 at 07:01, Malcolm Parsons via cfe-commits
> <cfe-commits at lists.llvm.org> wrote:
>>
>> Author: malcolm.parsons
>> Date: Fri Jan 13 09:01:06 2017
>> New Revision: 291905
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=291905&view=rev
>> Log:
>> [Sema] Add warning for unused lambda captures
>>
>> Summary:
>> Warn when a lambda explicitly captures something that is not used in its
>> body.
>>
>> The warning is part of -Wunused and can be enabled with
>> -Wunused-lambda-capture.
>>
>> Reviewers: rsmith, arphaman, jbcoe, aaron.ballman
>>
>> Subscribers: Quuxplusone, arphaman, cfe-commits
>>
>> Differential Revision: https://reviews.llvm.org/D28467
>>
>> Added:
>> cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp
>> Modified:
>> cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> cfe/trunk/include/clang/Sema/ScopeInfo.h
>> cfe/trunk/include/clang/Sema/Sema.h
>> cfe/trunk/lib/Sema/SemaExpr.cpp
>> cfe/trunk/lib/Sema/SemaExprCXX.cpp
>> cfe/trunk/lib/Sema/SemaLambda.cpp
>> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
>> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
>> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
>> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
>> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
>> cfe/trunk/test/SemaCXX/uninitialized.cpp
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Jan 13 09:01:06
>> 2017
>> @@ -480,6 +480,7 @@ def UnusedFunction : DiagGroup<"unused-f
>> def UnusedMemberFunction : DiagGroup<"unused-member-function",
>> [UnneededMemberFunction]>;
>> def UnusedLabel : DiagGroup<"unused-label">;
>> +def UnusedLambdaCapture : DiagGroup<"unused-lambda-capture">;
>> def UnusedParameter : DiagGroup<"unused-parameter">;
>> def UnusedResult : DiagGroup<"unused-result">;
>> def PotentiallyEvaluatedExpression :
>> DiagGroup<"potentially-evaluated-expression">;
>> @@ -617,8 +618,9 @@ def Unused : DiagGroup<"unused",
>> [UnusedArgument, UnusedFunction, UnusedLabel,
>> // UnusedParameter, (matches GCC's behavior)
>> // UnusedMemberFunction, (clean-up llvm before
>> enabling)
>> - UnusedPrivateField, UnusedLocalTypedef,
>> - UnusedValue, UnusedVariable,
>> UnusedPropertyIvar]>,
>> + UnusedPrivateField, UnusedLambdaCapture,
>> + UnusedLocalTypedef, UnusedValue, UnusedVariable,
>> + UnusedPropertyIvar]>,
>> DiagCategory<"Unused Entity Issue">;
>>
>> // Format settings.
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 13
>> 09:01:06 2017
>> @@ -316,6 +316,9 @@ def warn_unneeded_member_function : Warn
>> InGroup<UnneededMemberFunction>, DefaultIgnore;
>> def warn_unused_private_field: Warning<"private field %0 is not used">,
>> InGroup<UnusedPrivateField>, DefaultIgnore;
>> +def warn_unused_lambda_capture: Warning<"lambda capture %0 is not "
>> + "%select{used|required to be captured for use in an unevaluated
>> context}1">,
>> + InGroup<UnusedLambdaCapture>, DefaultIgnore;
>>
>> def warn_parameter_size: Warning<
>> "%0 is a large (%1 bytes) pass-by-value argument; "
>>
>> Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
>> +++ cfe/trunk/include/clang/Sema/ScopeInfo.h Fri Jan 13 09:01:06 2017
>> @@ -452,6 +452,14 @@ public:
>> /// non-static data member that would hold the capture.
>> QualType CaptureType;
>>
>> + /// \brief Whether an explicit capture has been odr-used in the body
>> of the
>> + /// lambda.
>> + bool ODRUsed;
>> +
>> + /// \brief Whether an explicit capture has been non-odr-used in the
>> body of
>> + /// the lambda.
>> + bool NonODRUsed;
>> +
>> public:
>> Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
>> SourceLocation Loc, SourceLocation EllipsisLoc,
>> @@ -460,7 +468,8 @@ public:
>> InitExprAndCaptureKind(
>> Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef
>> :
>> Cap_ByCopy),
>> - Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
>> + Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),
>> + ODRUsed(false), NonODRUsed(false) {}
>>
>> enum IsThisCapture { ThisCapture };
>> Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
>> @@ -468,7 +477,8 @@ public:
>> : VarAndNestedAndThis(
>> nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture :
>> 0))),
>> InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef),
>> - Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
>> + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType),
>> ODRUsed(false),
>> + NonODRUsed(false) {}
>>
>> bool isThisCapture() const {
>> return VarAndNestedAndThis.getInt() & IsThisCaptured;
>> @@ -491,6 +501,9 @@ public:
>> bool isNested() const {
>> return VarAndNestedAndThis.getInt() & IsNestedCapture;
>> }
>> + bool isODRUsed() const { return ODRUsed; }
>> + bool isNonODRUsed() const { return NonODRUsed; }
>> + void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) =
>> true; }
>>
>> VarDecl *getVariable() const {
>> return VarAndNestedAndThis.getPointer();
>>
>> Modified: cfe/trunk/include/clang/Sema/Sema.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/include/clang/Sema/Sema.h (original)
>> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jan 13 09:01:06 2017
>> @@ -5323,6 +5323,9 @@ public:
>> ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
>> Scope *CurScope);
>>
>> + /// \brief Diagnose if an explicit lambda capture is unused.
>> + void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture
>> &From);
>> +
>> /// \brief Complete a lambda-expression having processed and attached
>> the
>> /// lambda body.
>> ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation
>> EndLoc,
>>
>> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jan 13 09:01:06 2017
>> @@ -13916,8 +13916,10 @@ bool Sema::tryCaptureVariable(
>>
>> // Check whether we've already captured it.
>> if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested,
>> CaptureType,
>> - DeclRefType))
>> + DeclRefType)) {
>> + CSI->getCapture(Var).markUsed(BuildAndDiagnose);
>> break;
>> + }
>> // If we are instantiating a generic lambda call operator body,
>> // we do not want to capture new variables. What was captured
>> // during either a lambdas transformation or initial parsing
>>
>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 13 09:01:06 2017
>> @@ -1106,6 +1106,7 @@ bool Sema::CheckCXXThisCapture(SourceLoc
>> dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
>> if (CSI->CXXThisCaptureIndex != 0) {
>> // 'this' is already being captured; there isn't anything more to
>> do.
>> + CSI->Captures[CSI->CXXThisCaptureIndex -
>> 1].markUsed(BuildAndDiagnose);
>> break;
>> }
>> LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);
>>
>> Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaLambda.cpp Fri Jan 13 09:01:06 2017
>> @@ -1384,7 +1384,7 @@ static void addBlockPointerConversion(Se
>> }
>>
>> static ExprResult performLambdaVarCaptureInitialization(
>> - Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {
>> + Sema &S, const LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {
>> assert(Capture.isVariableCapture() && "not a variable capture");
>>
>> auto *Var = Capture.getVariable();
>> @@ -1438,6 +1438,21 @@ mapImplicitCaptureStyle(CapturingScopeIn
>> llvm_unreachable("Unknown implicit capture style");
>> }
>>
>> +void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture
>> &From) {
>> + if (!From.isVLATypeCapture()) {
>> + Expr *Init = From.getInitExpr();
>> + if (Init && Init->HasSideEffects(Context))
>> + return;
>> + }
>> +
>> + auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture);
>> + if (From.isThisCapture())
>> + diag << "'this'";
>> + else
>> + diag << From.getVariable();
>> + diag << From.isNonODRUsed();
>> +}
>> +
>> ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation
>> EndLoc,
>> LambdaScopeInfo *LSI) {
>> // Collect information from the lambda scope.
>> @@ -1476,10 +1491,14 @@ ExprResult Sema::BuildLambdaExpr(SourceL
>> // Translate captures.
>> auto CurField = Class->field_begin();
>> for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I,
>> ++CurField) {
>> - LambdaScopeInfo::Capture From = LSI->Captures[I];
>> + const LambdaScopeInfo::Capture &From = LSI->Captures[I];
>> assert(!From.isBlockCapture() && "Cannot capture __block
>> variables");
>> bool IsImplicit = I >= LSI->NumExplicitCaptures;
>>
>> + // Warn about unused explicit captures.
>> + if (!CurContext->isDependentContext() && !IsImplicit &&
>> !From.isODRUsed())
>> + DiagnoseUnusedLambdaCapture(From);
>> +
>> // Handle 'this' capture.
>> if (From.isThisCapture()) {
>> Captures.push_back(
>>
>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp (original)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
>> +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture
>> -verify
>>
>> void odr_used() {
>> int i = 17;
>>
>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp (original)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
>> +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture
>> -verify
>>
>> void f2() {
>> int i = 1;
>>
>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp (original)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
>> +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture
>> -verify
>>
>>
>> struct X {
>>
>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp (original)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
>> +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture
>> -verify
>> // expected-no-diagnostics
>>
>> template<typename T, typename U>
>>
>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp (original)
>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
>> +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture
>> -verify
>>
>> struct MoveOnly {
>> MoveOnly(MoveOnly&&);
>>
>> Modified: cfe/trunk/test/SemaCXX/uninitialized.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninitialized.cpp?rev=291905&r1=291904&r2=291905&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/test/SemaCXX/uninitialized.cpp (original)
>> +++ cfe/trunk/test/SemaCXX/uninitialized.cpp Fri Jan 13 09:01:06 2017
>> @@ -1,4 +1,4 @@
>> -// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value
>> -std=c++11 -verify %s
>> +// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value
>> -Wno-unused-lambda-capture -std=c++11 -verify %s
>>
>> // definitions for std::move
>> namespace std {
>>
>> Added: cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp?rev=291905&view=auto
>>
>> ==============================================================================
>> --- cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp (added)
>> +++ cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp Fri Jan 13
>> 09:01:06 2017
>> @@ -0,0 +1,110 @@
>> +// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture
>> -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++14 %s
>> +
>> +class NonTrivialConstructor {
>> +public:
>> + NonTrivialConstructor() {}
>> +};
>> +
>> +class NonTrivialDestructor {
>> +public:
>> + ~NonTrivialDestructor() {}
>> +};
>> +
>> +class Trivial {
>> +public:
>> + Trivial() = default;
>> + Trivial(int a) {}
>> +};
>> +
>> +int side_effect() {
>> + return 42;
>> +}
>> +
>> +void test() {
>> + int i = 0;
>> +
>> + auto captures_nothing = [] {};
>> +
>> + auto captures_nothing_by_value = [=] {};
>> + auto captures_nothing_by_reference = [&] {};
>> +
>> + auto implicit_by_value = [=]() mutable { i++; };
>> + auto implicit_by_reference = [&] { i++; };
>> +
>> + auto explicit_by_value_used = [i] { return i + 1; };
>> + auto explicit_by_value_used_void = [i] { (void)i; };
>> + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda
>> capture 'i' is not used}}
>> + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; //
>> expected-warning{{lambda capture 'i' is not required to be captured for use
>> in an unevaluated context}}
>> + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; //
>> expected-warning{{lambda capture 'i' is not required to be captured for use
>> in an unevaluated context}}
>> +
>> + auto explicit_by_reference_used = [&i] { i++; };
>> + auto explicit_by_reference_unused = [&i] {}; //
>> expected-warning{{lambda capture 'i' is not used}}
>> +
>> + auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
>> + auto explicit_initialized_reference_unused = [&j = i]{}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> +
>> + auto explicit_initialized_value_used = [j = 1] { return j + 1; };
>> + auto explicit_initialized_value_unused = [j = 1] {}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> + auto explicit_initialized_value_non_trivial_constructor = [j =
>> NonTrivialConstructor()]{};
>> + auto explicit_initialized_value_non_trivial_destructor = [j =
>> NonTrivialDestructor()]{};
>> + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> + auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
>> + auto explicit_initialized_value_with_side_effect = [j =
>> side_effect()]{};
>> +
>> + auto nested = [&i] {
>> + auto explicit_by_value_used = [i] { return i + 1; };
>> + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda
>> capture 'i' is not used}}
>> + };
>> +}
>> +
>> +class Foo
>> +{
>> + void test() {
>> + auto explicit_this_used = [this] { return i; };
>> + auto explicit_this_used_void = [this] { (void)this; };
>> + auto explicit_this_unused = [this] {}; // expected-warning{{lambda
>> capture 'this' is not used}}
>> + }
>> + int i;
>> +};
>> +
>> +template <typename T>
>> +void test_templated() {
>> + int i = 0;
>> +
>> + auto captures_nothing = [] {};
>> +
>> + auto captures_nothing_by_value = [=] {};
>> + auto captures_nothing_by_reference = [&] {};
>> +
>> + auto implicit_by_value = [=]() mutable { i++; };
>> + auto implicit_by_reference = [&] { i++; };
>> +
>> + auto explicit_by_value_used = [i] { return i + 1; };
>> + auto explicit_by_value_used_void = [i] { (void)i; };
>> + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda
>> capture 'i' is not used}}
>> + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; //
>> expected-warning{{lambda capture 'i' is not required to be captured for use
>> in an unevaluated context}}
>> + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; //
>> expected-warning{{lambda capture 'i' is not used}}
>> +
>> + auto explicit_by_reference_used = [&i] { i++; };
>> + auto explicit_by_reference_unused = [&i] {}; //
>> expected-warning{{lambda capture 'i' is not used}}
>> +
>> + auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
>> + auto explicit_initialized_reference_unused = [&j = i]{}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> +
>> + auto explicit_initialized_value_used = [j = 1] { return j + 1; };
>> + auto explicit_initialized_value_unused = [j = 1] {}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> + auto explicit_initialized_value_non_trivial_constructor = [j =
>> NonTrivialConstructor()]{};
>> + auto explicit_initialized_value_non_trivial_destructor = [j =
>> NonTrivialDestructor()]{};
>> + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; //
>> expected-warning{{lambda capture 'j' is not used}}
>> + auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
>> + auto explicit_initialized_value_with_side_effect = [j =
>> side_effect()]{};
>> +
>> + auto nested = [&i] {
>> + auto explicit_by_value_used = [i] { return i + 1; };
>> + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda
>> capture 'i' is not used}}
>> + };
>> +}
>> +
>> +void test_use_template() {
>> + test_templated<int>(); // expected-note{{in instantiation of function
>> template specialization 'test_templated<int>' requested here}}
>> +}
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
More information about the cfe-commits
mailing list