r291905 - [Sema] Add warning for unused lambda captures

Daniel Jasper via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 15 16:26:52 PST 2017


Sorry, for the noise.
This is probably not the revision that caused this.

On Mon, Jan 16, 2017 at 1:08 AM, Daniel Jasper <djasper at google.com> wrote:

> This patch seems to break on some of our code. Reproducer:
>
> $ cat /tmp/ctor.cc
> template <typename T>
> struct A {
>   A() {}
> };
>
> template <class T>
> class B : T {
>   using T::T;
> };
>
> struct C {
>   B<A<int>> d;
>   C(A<int> b) : d(b) {}
> };
>
> djasper at dj:~/llvm/release$ bin/clang -cc1 -std=c++11 /tmp/ctor.cc
> /tmp/ctor.cc:13:17: error: no matching constructor for initialization of
> 'B<A<int> >'
>   C(A<int> b) : d(b) {}
>                 ^ ~
> /tmp/ctor.cc:7:7: note: candidate constructor (the implicit copy
> constructor) not viable: no known conversion from 'A<int>' to 'const
> B<A<int> >' for 1st argument
> class B : T {
>       ^
> /tmp/ctor.cc:7:7: note: candidate constructor (the implicit move
> constructor) not viable: no known conversion from 'A<int>' to 'B<A<int> >'
> for 1st argument
> class B : T {
>       ^
> /tmp/ctor.cc:7:7: note: candidate constructor (the implicit default
> constructor) not viable: requires 0 arguments, but 1 was provided
> 1 error generated.
>
> As far as I can tell, the copy constructor of class A does not get
> forwarded with the "using T::T". I am not an expert on this parts of the
> language, but this does seem like an unwanted side-effect. It builds find
> with a version of Clang prior to this patch.
>
> On Fri, Jan 13, 2017 at 4:01 PM, 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-evaluat
>> ed-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/SemaE
>> xpr.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/SemaE
>> xprCXX.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/SemaL
>> ambda.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_captu
>> re);
>> +  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
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170116/25e101f5/attachment-0001.html>


More information about the cfe-commits mailing list