r296602 - [Sema] Improve side effect checking for unused-lambda-capture warning

Malcolm Parsons via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 1 02:23:39 PST 2017


Author: malcolm.parsons
Date: Wed Mar  1 04:23:38 2017
New Revision: 296602

URL: http://llvm.org/viewvc/llvm-project?rev=296602&view=rev
Log:
[Sema] Improve side effect checking for unused-lambda-capture warning

Summary:
Don't warn about unused lambda captures that involve copying a
value of a type that cannot be trivially copied and destroyed.

Fixes PR31977

Reviewers: rsmith, aaron.ballman

Subscribers: cfe-commits

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

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=296602&r1=296601&r2=296602&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar  1 04:23:38 2017
@@ -5340,6 +5340,9 @@ public:
   ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
                              Scope *CurScope);
 
+  /// \brief Does copying/destroying the captured variable have side effects?
+  bool CaptureHasSideEffects(const sema::LambdaScopeInfo::Capture &From);
+
   /// \brief Diagnose if an explicit lambda capture is unused.
   void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture &From);
 

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=296602&r1=296601&r2=296602&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Mar  1 04:23:38 2017
@@ -1438,13 +1438,35 @@ mapImplicitCaptureStyle(CapturingScopeIn
   llvm_unreachable("Unknown implicit capture style");
 }
 
-void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) {
+bool Sema::CaptureHasSideEffects(const LambdaScopeInfo::Capture &From) {
   if (!From.isVLATypeCapture()) {
     Expr *Init = From.getInitExpr();
     if (Init && Init->HasSideEffects(Context))
-      return;
+      return true;
   }
 
+  if (!From.isCopyCapture())
+    return false;
+
+  const QualType T = From.isThisCapture()
+                         ? getCurrentThisType()->getPointeeType()
+                         : From.getCaptureType();
+
+  if (T.isVolatileQualified())
+    return true;
+
+  const Type *BaseT = T->getBaseElementTypeUnsafe();
+  if (const CXXRecordDecl *RD = BaseT->getAsCXXRecordDecl())
+    return !RD->isCompleteDefinition() || !RD->hasTrivialCopyConstructor() ||
+           !RD->hasTrivialDestructor();
+
+  return false;
+}
+
+void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) {
+  if (CaptureHasSideEffects(From))
+    return;
+
   auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture);
   if (From.isThisCapture())
     diag << "'this'";

Modified: 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=296602&r1=296601&r2=296602&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp Wed Mar  1 04:23:38 2017
@@ -1,10 +1,16 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++1z %s
 
 class NonTrivialConstructor {
 public:
   NonTrivialConstructor() {}
 };
 
+class NonTrivialCopyConstructor {
+public:
+  NonTrivialCopyConstructor() = default;
+  NonTrivialCopyConstructor(const NonTrivialCopyConstructor &) {}
+};
+
 class NonTrivialDestructor {
 public:
   ~NonTrivialDestructor() {}
@@ -57,14 +63,67 @@ void test() {
     auto explicit_by_value_used = [i] { return i + 1; };
     auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
   };
+
+  Trivial trivial;
+  auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
+
+  NonTrivialConstructor cons;
+  auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
+
+  NonTrivialCopyConstructor copy_cons;
+  auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
+
+  NonTrivialDestructor dest;
+  auto explicit_by_value_non_trivial_destructor = [dest] {};
+
+  volatile int v;
+  auto explicit_by_value_volatile = [v] {};
 }
 
-class Foo
-{
+class TrivialThis : Trivial {
   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}}
+    auto explicit_star_this_used = [*this] { return i; };
+    auto explicit_star_this_used_void = [*this] { (void)this; };
+    auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
+  }
+  int i;
+};
+
+class NonTrivialConstructorThis : NonTrivialConstructor {
+  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}}
+    auto explicit_star_this_used = [*this] { return i; };
+    auto explicit_star_this_used_void = [*this] { (void)this; };
+    auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
+  }
+  int i;
+};
+
+class NonTrivialCopyConstructorThis : NonTrivialCopyConstructor {
+  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}}
+    auto explicit_star_this_used = [*this] { return i; };
+    auto explicit_star_this_used_void = [*this] { (void)this; };
+    auto explicit_star_this_unused = [*this] {};
+  }
+  int i;
+};
+
+class NonTrivialDestructorThis : NonTrivialDestructor {
+  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}}
+    auto explicit_star_this_used = [*this] { return i; };
+    auto explicit_star_this_used_void = [*this] { (void)this; };
+    auto explicit_star_this_unused = [*this] {};
   }
   int i;
 };
@@ -107,6 +166,21 @@ void test_templated() {
     auto explicit_by_value_used = [i] { return i + 1; };
     auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
   };
+
+  Trivial trivial;
+  auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
+
+  NonTrivialConstructor cons;
+  auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
+
+  NonTrivialCopyConstructor copy_cons;
+  auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
+
+  NonTrivialDestructor dest;
+  auto explicit_by_value_non_trivial_destructor = [dest] {};
+
+  volatile int v;
+  auto explicit_by_value_volatile = [v] {};
 }
 
 void test_use_template() {




More information about the cfe-commits mailing list