r291905 - [Sema] Add warning for unused lambda captures

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 15 16:42:40 PST 2017


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).

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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170215/54074b06/attachment-0001.html>


More information about the cfe-commits mailing list