From 325e593a83b20d9bce3628aa78fda983b554814e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 15 Apr 2010 00:00:53 +0000 Subject: [PATCH] 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101316 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 +++++ lib/Sema/SemaDeclCXX.cpp | 24 ++++++++++++++++++++ test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp | 6 ++--- test/SemaCXX/default-assignment-operator.cpp | 6 +++-- test/SemaCXX/references.cpp | 4 ++-- test/SemaCXX/value-initialization.cpp | 6 +++-- 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 RefMem { +template class RefMem { // expected-warning{{class 'RefMem' 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' 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() { } }; -- 2.40.0