aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2012-01-06 04:54:01 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2012-01-06 04:54:01 +0000
commit1a5d35539a16f3b2eb2426f3f23a8376b190741c (patch)
tree55702525a9d058dbda2cb65825ef503edae4fa5d
parent906a7e1c0f272f7e539c82dda01f4644031ce637 (diff)
Improvements to the uninitialized variable warning: Check if the constructor
call is elidable or if the constructor is trivial instead of checking if it is user declared. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147652 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaDecl.cpp17
-rw-r--r--test/SemaCXX/uninitialized.cpp1
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp42
3 files changed, 55 insertions, 5 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fecfce4d2d..d1bf3db19c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1107,7 +1107,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
// Types of valid local variables should be complete, so this should succeed.
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// White-list anything with an __attribute__((unused)) type.
QualType Ty = VD->getType();
@@ -1129,11 +1129,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- // FIXME: Checking for the presence of a user-declared constructor
- // isn't completely accurate; we'd prefer to check that the initializer
- // has no side effects.
- if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
+ if (!RD->hasTrivialDestructor())
return false;
+
+ if (const Expr *Init = VD->getInit()) {
+ const CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init);
+ if (Construct && !Construct->isElidable()) {
+ CXXConstructorDecl *CD = Construct->getConstructor();
+ if (!CD->isTrivial())
+ return false;
+ }
+ }
}
}
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index c3a5994af4..ec037cbb78 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -41,6 +41,7 @@ class A {
A(int x) {}
A(int *x) {}
A(A *a) {}
+ ~A();
};
A getA() { return A(); }
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 5ba1f2a5f3..582701957e 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -80,3 +80,45 @@ namespace PR10168 {
f<char>(); // expected-note {{here}}
}
}
+
+namespace PR11550 {
+ struct S1 {
+ S1();
+ };
+ S1 makeS1();
+ void testS1(S1 a) {
+ // This constructor call can be elided.
+ S1 x = makeS1(); // expected-warning {{unused variable 'x'}}
+
+ // This one cannot, so no warning.
+ S1 y;
+
+ // This call cannot, but the constructor is trivial.
+ S1 z = a; // expected-warning {{unused variable 'z'}}
+ }
+
+ // The same is true even when we know thet constructor has side effects.
+ void foo();
+ struct S2 {
+ S2() {
+ foo();
+ }
+ };
+ S2 makeS2();
+ void testS2(S2 a) {
+ S2 x = makeS2(); // expected-warning {{unused variable 'x'}}
+ S2 y;
+ S2 z = a; // expected-warning {{unused variable 'z'}}
+ }
+
+ // Or when the constructor is not declared by the user.
+ struct S3 {
+ S1 m;
+ };
+ S3 makeS3();
+ void testS3(S3 a) {
+ S3 x = makeS3(); // expected-warning {{unused variable 'x'}}
+ S3 y;
+ S3 z = a; // expected-warning {{unused variable 'z'}}
+ }
+}