]> granicus.if.org Git - clang/commitdiff
Fix spurious Wunused-lambda-capture warning
authorYi Kong <yikong@google.com>
Tue, 13 Jun 2017 18:38:31 +0000 (18:38 +0000)
committerYi Kong <yikong@google.com>
Tue, 13 Jun 2017 18:38:31 +0000 (18:38 +0000)
Summary:
Clang emits unused-lambda-capture warning for captures in generic lambdas even though they are actually used.

Fixes PR31815.

Reviewers: malcolm.parsons, aaron.ballman, rsmith

Reviewed By: malcolm.parsons

Subscribers: ahatanak, cfe-commits

Differential Revision: https://reviews.llvm.org/D33526

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@305315 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaLambda.cpp
test/SemaCXX/warn-unused-lambda-capture.cpp

index a6239283b47beae596624aa5648db1cc4db15c53..d6b70610d461c3f5ae908d29e1dd5caceb46edce 100644 (file)
@@ -1492,6 +1492,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
   bool ExplicitResultType;
   CleanupInfo LambdaCleanup;
   bool ContainsUnexpandedParameterPack;
+  bool IsGenericLambda;
   {
     CallOperator = LSI->CallOperator;
     Class = LSI->Lambda;
@@ -1500,7 +1501,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
     ExplicitResultType = !LSI->HasImplicitReturnType;
     LambdaCleanup = LSI->Cleanup;
     ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
-    
+    IsGenericLambda = Class->isGenericLambda();
+
     CallOperator->setLexicalDeclContext(Class);
     Decl *TemplateOrNonTemplateCallOperatorDecl = 
         CallOperator->getDescribedFunctionTemplate()  
@@ -1520,8 +1522,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
       bool IsImplicit = I >= LSI->NumExplicitCaptures;
 
       // Warn about unused explicit captures.
-      if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed())
-        DiagnoseUnusedLambdaCapture(From);
+      if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+        // Initialized captures that are non-ODR used may not be eliminated.
+        bool NonODRUsedInitCapture =
+            IsGenericLambda && From.isNonODRUsed() && From.getInitExpr();
+        if (!NonODRUsedInitCapture)
+          DiagnoseUnusedLambdaCapture(From);
+      }
 
       // Handle 'this' capture.
       if (From.isThisCapture()) {
@@ -1568,8 +1575,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
     //   same parameter and return types as the closure type's function call
     //   operator.
     // FIXME: Fix generic lambda to block conversions.
-    if (getLangOpts().Blocks && getLangOpts().ObjC1 && 
-                                              !Class->isGenericLambda())
+    if (getLangOpts().Blocks && getLangOpts().ObjC1 && !IsGenericLambda)
       addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
     
     // Finalize the lambda class.
index 48f8bfea7e9a7a425275b90b232e2039d4a31c43..6ad8e26604a453fac0943f3c5a5474569d5dddb5 100644 (file)
@@ -142,11 +142,14 @@ void test_templated() {
   auto implicit_by_reference = [&] { i++; };
 
   auto explicit_by_value_used = [i] { return i + 1; };
+  auto explicit_by_value_used_generic = [i](auto c) { 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 this use}}
   auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
   auto explicit_by_value_unused_const = [k] { return k + 1; };         // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+  auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
 
   auto explicit_by_reference_used = [&i] { i++; };
   auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
@@ -161,6 +164,8 @@ void test_templated() {
   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 explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
+  auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}
 
   auto nested = [&i] {
     auto explicit_by_value_used = [i] { return i + 1; };