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();
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;
+ }
+ }
}
}
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'}}
+ }
+}