forked from OSchip/llvm-project
[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 llvm-svn: 296602
This commit is contained in:
parent
9b802e4650
commit
ded2306208
|
@ -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);
|
||||
|
||||
|
|
|
@ -1438,13 +1438,35 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
|
|||
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'";
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue