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'";
-// 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() {}
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;
};
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() {