]> granicus.if.org Git - clang/commitdiff
Warn about non-aggregate classes with no user-declared constructors
authorDouglas Gregor <dgregor@apple.com>
Thu, 15 Apr 2010 00:00:53 +0000 (00:00 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 15 Apr 2010 00:00:53 +0000 (00:00 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
test/SemaCXX/default-assignment-operator.cpp
test/SemaCXX/references.cpp
test/SemaCXX/value-initialization.cpp

index 231031829fc0cb4d1434681a718d1a1ba0c2a941..cb45f66cd87ee99135e8890f06d08f32cfb04950 100644 (file)
@@ -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<
index 24695f35cc232539f210b2cebed554e3e0c68d8d..72f38b43cd2c477a83c39bb2a7e0d3eeea023e20 100644 (file)
@@ -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,
index 17fd7129100067c0192615324b1f77af77179335..aaf7451424019ecd2a4401da09de35fa9b6508c6 100644 (file)
@@ -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}}
 };
 
 
index baae03cf13479ebdd0572390cb4daa1946198199..d9cb6fc8e56ca85ce1657812d1bb44bf126ed704 100644 (file)
@@ -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}}
index f1f4ab9f954115ce27b5af97a9678f8cdd1e8918..e40ea01a9b99165be41c7d6bd728c181cb330169 100644 (file)
@@ -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 { };
index 16a7a1d0c9b975621be8ca70526f87bf17f9966f..00bd1aaa40bd6efee572022d9a63f0c85ceff65f 100644 (file)
@@ -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() { } 
 };