<div dir="ltr">This warns about code like<div><br></div><div>  constexpr int foo = 4;</div><div>  [&foo]() { use(foo); }</div><div><br></div><div>That's correct, but removing &foo then makes MSVC complain about this code like "error C3493: 'foo' cannot be implicitly captured because no default capture mode has been specified". A workaround is to make foo static const instead of constexpr.</div><div><br></div><div>This seems like an MSVC bug, but it's still a bit annoying that clang now suggests doing things that won't build in other compilers. Any ideas what to do about this?</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jan 13, 2017 at 10:01 AM, Malcolm Parsons via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: malcolm.parsons<br>
Date: Fri Jan 13 09:01:06 2017<br>
New Revision: 291905<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=291905&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=291905&view=rev</a><br>
Log:<br>
[Sema] Add warning for unused lambda captures<br>
<br>
Summary:<br>
Warn when a lambda explicitly captures something that is not used in its body.<br>
<br>
The warning is part of -Wunused and can be enabled with -Wunused-lambda-capture.<br>
<br>
Reviewers: rsmith, arphaman, jbcoe, aaron.ballman<br>
<br>
Subscribers: Quuxplusone, arphaman, cfe-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D28467" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D28467</a><br>
<br>
Added:<br>
    cfe/trunk/test/SemaCXX/warn-<wbr>unused-lambda-capture.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/<wbr>DiagnosticGroups.td<br>
    cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Sema/<wbr>ScopeInfo.h<br>
    cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
    cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaExprCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaLambda.<wbr>cpp<br>
    cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p12.cpp<br>
    cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p13.cpp<br>
    cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p16.cpp<br>
    cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p18.cpp<br>
    cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p19.cpp<br>
    cfe/trunk/test/SemaCXX/<wbr>uninitialized.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticGroups.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/DiagnosticGroups.<wbr>td?rev=291905&r1=291904&r2=<wbr>291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticGroups.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticGroups.td Fri Jan 13 09:01:06 2017<br>
@@ -480,6 +480,7 @@ def UnusedFunction : DiagGroup<"unused-f<br>
 def UnusedMemberFunction : DiagGroup<"unused-member-<wbr>function",<br>
                                      [UnneededMemberFunction]>;<br>
 def UnusedLabel : DiagGroup<"unused-label">;<br>
+def UnusedLambdaCapture : DiagGroup<"unused-lambda-<wbr>capture">;<br>
 def UnusedParameter : DiagGroup<"unused-parameter">;<br>
 def UnusedResult : DiagGroup<"unused-result">;<br>
 def PotentiallyEvaluatedExpression : DiagGroup<"potentially-<wbr>evaluated-expression">;<br>
@@ -617,8 +618,9 @@ def Unused : DiagGroup<"unused",<br>
                        [UnusedArgument, UnusedFunction, UnusedLabel,<br>
                         // UnusedParameter, (matches GCC's behavior)<br>
                         // UnusedMemberFunction, (clean-up llvm before enabling)<br>
-                        UnusedPrivateField, UnusedLocalTypedef,<br>
-                        UnusedValue, UnusedVariable, UnusedPropertyIvar]>,<br>
+                        UnusedPrivateField, UnusedLambdaCapture,<br>
+                        UnusedLocalTypedef, UnusedValue, UnusedVariable,<br>
+                        UnusedPropertyIvar]>,<br>
                         DiagCategory<"Unused Entity Issue">;<br>
<br>
 // Format settings.<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticSemaKinds.td?rev=<wbr>291905&r1=291904&r2=291905&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td Fri Jan 13 09:01:06 2017<br>
@@ -316,6 +316,9 @@ def warn_unneeded_member_function : Warn<br>
   InGroup<<wbr>UnneededMemberFunction>, DefaultIgnore;<br>
 def warn_unused_private_field: Warning<"private field %0 is not used">,<br>
   InGroup<UnusedPrivateField>, DefaultIgnore;<br>
+def warn_unused_lambda_capture: Warning<"lambda capture %0 is not "<br>
+  "%select{used|required to be captured for use in an unevaluated context}1">,<br>
+  InGroup<UnusedLambdaCapture>, DefaultIgnore;<br>
<br>
 def warn_parameter_size: Warning<<br>
   "%0 is a large (%1 bytes) pass-by-value argument; "<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>ScopeInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/ScopeInfo.h?rev=<wbr>291905&r1=291904&r2=291905&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>ScopeInfo.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>ScopeInfo.h Fri Jan 13 09:01:06 2017<br>
@@ -452,6 +452,14 @@ public:<br>
     /// non-static data member that would hold the capture.<br>
     QualType CaptureType;<br>
<br>
+    /// \brief Whether an explicit capture has been odr-used in the body of the<br>
+    /// lambda.<br>
+    bool ODRUsed;<br>
+<br>
+    /// \brief Whether an explicit capture has been non-odr-used in the body of<br>
+    /// the lambda.<br>
+    bool NonODRUsed;<br>
+<br>
   public:<br>
     Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,<br>
             SourceLocation Loc, SourceLocation EllipsisLoc,<br>
@@ -460,7 +468,8 @@ public:<br>
           InitExprAndCaptureKind(<br>
               Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef<br>
                                                               : Cap_ByCopy),<br>
-          Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}<br>
+          Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),<br>
+          ODRUsed(false), NonODRUsed(false) {}<br>
<br>
     enum IsThisCapture { ThisCapture };<br>
     Capture(IsThisCapture, bool IsNested, SourceLocation Loc,<br>
@@ -468,7 +477,8 @@ public:<br>
         : VarAndNestedAndThis(<br>
               nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture : 0))),<br>
           InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef),<br>
-          Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}<br>
+          Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), ODRUsed(false),<br>
+          NonODRUsed(false) {}<br>
<br>
     bool isThisCapture() const {<br>
       return VarAndNestedAndThis.getInt() & IsThisCaptured;<br>
@@ -491,6 +501,9 @@ public:<br>
     bool isNested() const {<br>
       return VarAndNestedAndThis.getInt() & IsNestedCapture;<br>
     }<br>
+    bool isODRUsed() const { return ODRUsed; }<br>
+    bool isNonODRUsed() const { return NonODRUsed; }<br>
+    void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = true; }<br>
<br>
     VarDecl *getVariable() const {<br>
       return VarAndNestedAndThis.<wbr>getPointer();<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/Sema.h?rev=291905&<wbr>r1=291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>Sema.h Fri Jan 13 09:01:06 2017<br>
@@ -5323,6 +5323,9 @@ public:<br>
   ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,<br>
                              Scope *CurScope);<br>
<br>
+  /// \brief Diagnose if an explicit lambda capture is unused.<br>
+  void DiagnoseUnusedLambdaCapture(<wbr>const sema::LambdaScopeInfo::Capture &From);<br>
+<br>
   /// \brief Complete a lambda-expression having processed and attached the<br>
   /// lambda body.<br>
   ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaExpr.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp Fri Jan 13 09:01:06 2017<br>
@@ -13916,8 +13916,10 @@ bool Sema::tryCaptureVariable(<br>
<br>
     // Check whether we've already captured it.<br>
     if (<wbr>isVariableAlreadyCapturedInSco<wbr>peInfo(CSI, Var, Nested, CaptureType,<br>
-                                             DeclRefType))<br>
+                                             DeclRefType)) {<br>
+      CSI->getCapture(Var).markUsed(<wbr>BuildAndDiagnose);<br>
       break;<br>
+    }<br>
     // If we are instantiating a generic lambda call operator body,<br>
     // we do not want to capture new variables.  What was captured<br>
     // during either a lambdas transformation or initial parsing<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaExprCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaExprCXX.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaExprCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaExprCXX.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1106,6 +1106,7 @@ bool Sema::CheckCXXThisCapture(<wbr>SourceLoc<br>
             dyn_cast<CapturingScopeInfo>(<wbr>FunctionScopes[idx])) {<br>
       if (CSI->CXXThisCaptureIndex != 0) {<br>
         // 'this' is already being captured; there isn't anything more to do.<br>
+        CSI->Captures[CSI-><wbr>CXXThisCaptureIndex - 1].markUsed(BuildAndDiagnose);<br>
         break;<br>
       }<br>
       LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)<wbr>;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaLambda.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaLambda.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaLambda.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaLambda.<wbr>cpp Fri Jan 13 09:01:06 2017<br>
@@ -1384,7 +1384,7 @@ static void addBlockPointerConversion(Se<br>
 }<br>
<br>
 static ExprResult performLambdaVarCaptureInitial<wbr>ization(<br>
-    Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {<br>
+    Sema &S, const LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {<br>
   assert(Capture.<wbr>isVariableCapture() && "not a variable capture");<br>
<br>
   auto *Var = Capture.getVariable();<br>
@@ -1438,6 +1438,21 @@ mapImplicitCaptureStyle(<wbr>CapturingScopeIn<br>
   llvm_unreachable("Unknown implicit capture style");<br>
 }<br>
<br>
+void Sema::<wbr>DiagnoseUnusedLambdaCapture(<wbr>const LambdaScopeInfo::Capture &From) {<br>
+  if (!From.isVLATypeCapture()) {<br>
+    Expr *Init = From.getInitExpr();<br>
+    if (Init && Init->HasSideEffects(Context))<br>
+      return;<br>
+  }<br>
+<br>
+  auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_<wbr>capture);<br>
+  if (From.isThisCapture())<br>
+    diag << "'this'";<br>
+  else<br>
+    diag << From.getVariable();<br>
+  diag << From.isNonODRUsed();<br>
+}<br>
+<br>
 ExprResult Sema::BuildLambdaExpr(<wbr>SourceLocation StartLoc, SourceLocation EndLoc,<br>
                                  LambdaScopeInfo *LSI) {<br>
   // Collect information from the lambda scope.<br>
@@ -1476,10 +1491,14 @@ ExprResult Sema::BuildLambdaExpr(SourceL<br>
     // Translate captures.<br>
     auto CurField = Class->field_begin();<br>
     for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) {<br>
-      LambdaScopeInfo::Capture From = LSI->Captures[I];<br>
+      const LambdaScopeInfo::Capture &From = LSI->Captures[I];<br>
       assert(!From.isBlockCapture() && "Cannot capture __block variables");<br>
       bool IsImplicit = I >= LSI->NumExplicitCaptures;<br>
<br>
+      // Warn about unused explicit captures.<br>
+      if (!CurContext-><wbr>isDependentContext() && !IsImplicit && !From.isODRUsed())<br>
+        DiagnoseUnusedLambdaCapture(<wbr>From);<br>
+<br>
       // Handle 'this' capture.<br>
       if (From.isThisCapture()) {<br>
         Captures.push_back(<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p12.cpp<br>
URL: <a href="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" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>expr/expr.prim/expr.prim.<wbr>lambda/p12.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p12.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p12.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify<br>
<br>
 void odr_used() {<br>
   int i = 17;<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p13.cpp<br>
URL: <a href="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" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>expr/expr.prim/expr.prim.<wbr>lambda/p13.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p13.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p13.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify<br>
<br>
 void f2() {<br>
   int i = 1;<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p16.cpp<br>
URL: <a href="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" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>expr/expr.prim/expr.prim.<wbr>lambda/p16.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p16.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p16.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify<br>
<br>
<br>
 struct X {<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p18.cpp<br>
URL: <a href="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" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>expr/expr.prim/expr.prim.<wbr>lambda/p18.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p18.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p18.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify<br>
 // expected-no-diagnostics<br>
<br>
 template<typename T, typename U><br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p19.cpp<br>
URL: <a href="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" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>expr/expr.prim/expr.prim.<wbr>lambda/p19.cpp?rev=291905&r1=<wbr>291904&r2=291905&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p19.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.<wbr>prim/expr.prim.lambda/p19.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify<br>
<br>
 struct MoveOnly {<br>
   MoveOnly(MoveOnly&&);<br>
<br>
Modified: cfe/trunk/test/SemaCXX/<wbr>uninitialized.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninitialized.cpp?rev=291905&r1=291904&r2=291905&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/uninitialized.cpp?rev=<wbr>291905&r1=291904&r2=291905&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/<wbr>uninitialized.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/<wbr>uninitialized.cpp Fri Jan 13 09:01:06 2017<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -std=c++11 -verify %s<br>
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -Wno-unused-lambda-capture -std=c++11 -verify %s<br>
<br>
 // definitions for std::move<br>
 namespace std {<br>
<br>
Added: cfe/trunk/test/SemaCXX/warn-<wbr>unused-lambda-capture.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp?rev=291905&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/warn-unused-lambda-<wbr>capture.cpp?rev=291905&view=<wbr>auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/warn-<wbr>unused-lambda-capture.cpp (added)<br>
+++ cfe/trunk/test/SemaCXX/warn-<wbr>unused-lambda-capture.cpp Fri Jan 13 09:01:06 2017<br>
@@ -0,0 +1,110 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++14 %s<br>
+<br>
+class NonTrivialConstructor {<br>
+public:<br>
+  NonTrivialConstructor() {}<br>
+};<br>
+<br>
+class NonTrivialDestructor {<br>
+public:<br>
+  ~NonTrivialDestructor() {}<br>
+};<br>
+<br>
+class Trivial {<br>
+public:<br>
+  Trivial() = default;<br>
+  Trivial(int a) {}<br>
+};<br>
+<br>
+int side_effect() {<br>
+  return 42;<br>
+}<br>
+<br>
+void test() {<br>
+  int i = 0;<br>
+<br>
+  auto captures_nothing = [] {};<br>
+<br>
+  auto captures_nothing_by_value = [=] {};<br>
+  auto captures_nothing_by_reference = [&] {};<br>
+<br>
+  auto implicit_by_value = [=]() mutable { i++; };<br>
+  auto implicit_by_reference = [&] { i++; };<br>
+<br>
+  auto explicit_by_value_used = [i] { return i + 1; };<br>
+  auto explicit_by_value_used_void = [i] { (void)i; };<br>
+  auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+  auto explicit_by_value_unused_<wbr>sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for use in an unevaluated context}}<br>
+  auto explicit_by_value_unused_<wbr>decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for use in an unevaluated context}}<br>
+<br>
+  auto explicit_by_reference_used = [&i] { i++; };<br>
+  auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+<br>
+  auto explicit_initialized_<wbr>reference_used = [&j = i] { return j + 1; };<br>
+  auto explicit_initialized_<wbr>reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}<br>
+<br>
+  auto explicit_initialized_value_<wbr>used = [j = 1] { return j + 1; };<br>
+  auto explicit_initialized_value_<wbr>unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}<br>
+  auto explicit_initialized_value_<wbr>non_trivial_constructor = [j = NonTrivialConstructor()]{};<br>
+  auto explicit_initialized_value_<wbr>non_trivial_destructor = [j = NonTrivialDestructor()]{};<br>
+  auto explicit_initialized_value_<wbr>trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}<br>
+  auto explicit_initialized_value_<wbr>non_trivial_init = [j = Trivial(42)]{};<br>
+  auto explicit_initialized_value_<wbr>with_side_effect = [j = side_effect()]{};<br>
+<br>
+  auto nested = [&i] {<br>
+    auto explicit_by_value_used = [i] { return i + 1; };<br>
+    auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+  };<br>
+}<br>
+<br>
+class Foo<br>
+{<br>
+  void test() {<br>
+    auto explicit_this_used = [this] { return i; };<br>
+    auto explicit_this_used_void = [this] { (void)this; };<br>
+    auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}<br>
+  }<br>
+  int i;<br>
+};<br>
+<br>
+template <typename T><br>
+void test_templated() {<br>
+  int i = 0;<br>
+<br>
+  auto captures_nothing = [] {};<br>
+<br>
+  auto captures_nothing_by_value = [=] {};<br>
+  auto captures_nothing_by_reference = [&] {};<br>
+<br>
+  auto implicit_by_value = [=]() mutable { i++; };<br>
+  auto implicit_by_reference = [&] { i++; };<br>
+<br>
+  auto explicit_by_value_used = [i] { return i + 1; };<br>
+  auto explicit_by_value_used_void = [i] { (void)i; };<br>
+  auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+  auto explicit_by_value_unused_<wbr>sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for use in an unevaluated context}}<br>
+  auto explicit_by_value_unused_<wbr>decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}<br>
+<br>
+  auto explicit_by_reference_used = [&i] { i++; };<br>
+  auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+<br>
+  auto explicit_initialized_<wbr>reference_used = [&j = i] { return j + 1; };<br>
+  auto explicit_initialized_<wbr>reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}<br>
+<br>
+  auto explicit_initialized_value_<wbr>used = [j = 1] { return j + 1; };<br>
+  auto explicit_initialized_value_<wbr>unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}<br>
+  auto explicit_initialized_value_<wbr>non_trivial_constructor = [j = NonTrivialConstructor()]{};<br>
+  auto explicit_initialized_value_<wbr>non_trivial_destructor = [j = NonTrivialDestructor()]{};<br>
+  auto explicit_initialized_value_<wbr>trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}<br>
+  auto explicit_initialized_value_<wbr>non_trivial_init = [j = Trivial(42)]{};<br>
+  auto explicit_initialized_value_<wbr>with_side_effect = [j = side_effect()]{};<br>
+<br>
+  auto nested = [&i] {<br>
+    auto explicit_by_value_used = [i] { return i + 1; };<br>
+    auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}<br>
+  };<br>
+}<br>
+<br>
+void test_use_template() {<br>
+  test_templated<int>(); // expected-note{{in instantiation of function template specialization 'test_templated<int>' requested here}}<br>
+}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>