aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-04-15 00:00:53 +0000
committerDouglas Gregor <dgregor@apple.com>2010-04-15 00:00:53 +0000
commit325e593a83b20d9bce3628aa78fda983b554814e (patch)
tree915e4d1855478062a96d3ab96e87ab8e41d62d21
parent1a8cf73a825ef35917eede448817237b5fd47b05 (diff)
Warn about non-aggregate classes with no user-declared constructors
that have reference or const scalar members, since those members can never be initializer or modified. Fixes <rdar://problem/7804350>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101316 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--lib/Sema/SemaDeclCXX.cpp24
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp6
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp6
-rw-r--r--test/SemaCXX/references.cpp4
-rw-r--r--test/SemaCXX/value-initialization.cpp6
6 files changed, 43 insertions, 9 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 231031829f..cb45f66cd8 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -598,6 +598,7 @@ def err_covariant_return_type_class_type_more_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
+
// C++ constructors
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
@@ -607,6 +608,11 @@ def err_constructor_return_type : Error<
def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
def err_constructor_byvalue_arg : Error<
"copy constructor must pass its first argument by reference">;
+def warn_no_constructor_for_refconst : Warning<
+ "%select{struct|union|class|enum}0 %1 does not declare any constructor to "
+ "initialize its non-modifiable members">;
+def note_refconst_member_not_initialized : Note<
+ "%select{const|reference}0 member %1 will never be initialized">;
// C++ destructors
def err_destructor_not_member : Error<
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 24695f35cc..72f38b43cd 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2218,6 +2218,30 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
+
+ // If this is not an aggregate type and has no user-declared constructor,
+ // complain about any non-static data members of reference or const scalar
+ // type, since they will never get initializers.
+ if (!Record->isInvalidDecl() && !Record->isDependentType() &&
+ !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) {
+ bool Complained = false;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F) {
+ if (F->getType()->isReferenceType() ||
+ F->getType().isConstQualified() && F->getType()->isScalarType()) {
+ if (!Complained) {
+ Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst)
+ << Record->getTagKind() << Record;
+ Complained = true;
+ }
+
+ Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
+ << F->getType()->isReferenceType()
+ << F->getDeclName();
+ }
+ }
+ }
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
index 17fd712910..aaf7451424 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
@@ -9,10 +9,10 @@
typedef int &intref;
typedef intref &intrefref;
-template <class T> class RefMem {
+template <class T> class RefMem { // expected-warning{{class 'RefMem<int &>' does not declare any constructor to initialize its non-modifiable members}}
T
&
- member;
+ member; // expected-note{{ reference member 'member' will never be initialized}}
};
struct RefRef {
@@ -34,7 +34,7 @@ struct RefRef {
int
&
>
- refref3; // collapses
+ refref3; // collapses expected-note{{in instantiation of template class 'RefMem<int &>' requested here}}
};
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index baae03cf13..d9cb6fc8e5 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}}
- int &ref; // expected-note {{declared at}}
+class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}} \
+ // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}}
+ int &ref; // expected-note {{declared at}} \
+ // expected-note{{reference member 'ref' will never be initialized}}
};
class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index f1f4ab9f95..e40ea01a9b 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -66,8 +66,8 @@ int& test6(int& x) {
int& not_initialized_error; // expected-error{{declaration of reference variable 'not_initialized_error' requires an initializer}}
extern int& not_initialized_okay;
-class Test6 {
- int& okay;
+class Test6 { // expected-warning{{class 'Test6' does not declare any constructor to initialize its non-modifiable members}}
+ int& okay; // expected-note{{reference member 'okay' will never be initialized}}
};
struct C : B, A { };
diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp
index 16a7a1d0c9..00bd1aaa40 100644
--- a/test/SemaCXX/value-initialization.cpp
+++ b/test/SemaCXX/value-initialization.cpp
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
-struct A { // expected-error {{implicit default constructor for 'A' must explicitly initialize the const member 'i'}}
- const int i; // expected-note {{declared at}}
+struct A { // expected-error {{implicit default constructor for 'A' must explicitly initialize the const member 'i'}} \
+ // expected-warning{{struct 'A' does not declare any constructor to initialize its non-modifiable members}}
+ const int i; // expected-note {{declared at}} \
+ // expected-note{{const member 'i' will never be initialized}}
virtual void f() { }
};