diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2009-07-09 19:59:47 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2009-07-09 19:59:47 +0000 |
commit | eb96e1275206b888eee484aac8b1b693417c6521 (patch) | |
tree | 862203bc0f1c4657305fde281dafd3e2ced35a3a | |
parent | 5e09d4c96dc2846cc1fc75f80f5632612247354b (diff) |
Sema check on out of order object initialization of
class object's base and members under -Wreorder flag.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75168 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 69 | ||||
-rw-r--r-- | test/SemaCXX/constructor-initializer.cpp | 10 | ||||
-rw-r--r-- | test/SemaCXX/warn-reorder-ctor-initialization.cpp | 18 |
5 files changed, 103 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 2896f7988c..ee23269c74 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -94,6 +94,7 @@ def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedValue : DiagGroup<"unused-value">; def UnusedVariable : DiagGroup<"unused-variable">; def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">; +def Reorder : DiagGroup<"reorder">; def UndeclaredSelector : DiagGroup<"undeclared-selector">; def : DiagGroup<"variadic-macros">; def VectorConversions : DiagGroup<"vector-conversions">; // clang specific @@ -135,6 +136,7 @@ def Most : DiagGroup<"most", [ VectorConversions, VolatileRegisterVar, ReadOnlySetterAttrs, + Reorder, UndeclaredSelector ]>; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7b38b25c80..7078530dc6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1620,6 +1620,15 @@ def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; +def warn_field_initialized : Warning< + "member '%0' will be initialized after">, + InGroup<Reorder>, DefaultIgnore; +def warn_base_initialized : Warning< + "base class %0 will be initialized after">, + InGroup<Reorder>, DefaultIgnore; +def note_fieldorbase_initialized_here : Note< + "%select{field|base}0 %1">; + def err_base_init_does_not_name_class : Error< "constructor initializer %0 does not name a class">; def err_base_init_direct_and_virtual : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e27b822337..b942c9c275 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -819,10 +819,77 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, << 0; err = true; } - if (!err) + if (!err) { Constructor->setBaseOrMemberInitializers(Context, reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), NumMemInits); + // Also issue warning if order of ctor-initializer list does not match order + // of 1) base class declarations and 2) order of non-static data members. + // FIXME. proper handling in the presense of virtual base class. + llvm::SmallVector<const void*, 32> AllBaseOrMembers; + + CXXRecordDecl *ClassDecl + = cast<CXXRecordDecl>(Constructor->getDeclContext()); + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) + AllBaseOrMembers.push_back(Base->getType()->getAsRecordType()); + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + E = ClassDecl->field_end(); Field != E; ++Field) + AllBaseOrMembers.push_back(*Field); + + int Last = AllBaseOrMembers.size(); + int curIndex = 0; + CXXBaseOrMemberInitializer *PrevMember = 0; + for (unsigned i = 0; i < NumMemInits; i++) { + CXXBaseOrMemberInitializer *Member = + static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]); + void *MemberInCtorList; + if (Member->isBaseInitializer()) + MemberInCtorList = Member->getBaseClass(); + else + MemberInCtorList = Member->getMember(); + + int j; + for (j = curIndex; j < Last; j++) + if (MemberInCtorList == AllBaseOrMembers[j]) + break; + if (j == Last) { + if (!PrevMember) + continue; + // Initializer as specified in ctor-initializer list is out of order. + // Issue a warning diagnostic. + if (PrevMember->isBaseInitializer()) { + // Diagnostics is for an initialized base class. + Type *BaseClass = PrevMember->getBaseClass(); + Diag(PrevMember->getSourceLocation(), + diag::warn_base_initialized) + << BaseClass->getDesugaredType(true); + } + else { + FieldDecl *Field = PrevMember->getMember(); + Diag(PrevMember->getSourceLocation(), + diag::warn_field_initialized) + << Field->getNameAsString(); + } + // Also the note! + if (FieldDecl *Field = Member->getMember()) + Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 0 + << Field->getNameAsString(); + else { + Type *BaseClass = Member->getBaseClass(); + Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 1 + << BaseClass->getDesugaredType(true); + } + } + PrevMember = Member; + for (curIndex=0; curIndex < Last; curIndex++) + if (MemberInCtorList == AllBaseOrMembers[curIndex]) + break; + } + } } namespace { diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp index a180d907f1..206d5d2ae7 100644 --- a/test/SemaCXX/constructor-initializer.cpp +++ b/test/SemaCXX/constructor-initializer.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -Wreorder -fsyntax-only -verify %s class A { int m; A() : A::m(17) { } // expected-error {{member initializer 'm' does not name a non-static data member or base class}} @@ -64,7 +64,7 @@ struct S : Y, virtual X { }; struct Z : S { - Z() : S(), X(), E() {} // expected-error {{type 'class E' is not a direct or virtual base of 'Z'}} + Z() : X(), S(), E() {} // expected-error {{type 'class E' is not a direct or virtual base of 'Z'}} }; class U { @@ -85,10 +85,12 @@ struct Derived : Base, Base1, virtual V { struct Current : Derived { int Derived; - Current() : Derived(1), ::Derived(), + Current() : Derived(1), ::Derived(), // expected-warning {{member 'Derived' will be initialized after}} \ + // expected-note {{base '::Derived'}} \ + // expected-warning {{base class '::Derived' will be initialized after}} ::Derived::Base(), // expected-error {{type '::Derived::Base' is not a direct or virtual base of 'Current'}} Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}} - Derived::V(), + Derived::V(), // expected-note {{base 'Derived::V'}} ::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}} INT::NonExisting() {} // expected-error {{expected a class or namespace}} \ // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}} diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp new file mode 100644 index 0000000000..83b671010c --- /dev/null +++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -Wreorder -verify %s + +struct B {}; + +struct B1 {}; + +class complex : public B, B1 { +public: + complex() : s2(1), // expected-warning {{member 's2' will be initialized after}} + s1(1) , // expected-note {{field s1}} + s3(3), // expected-warning {{member 's3' will be initialized after}} + B1(), // expected-note {{base 'struct B1'}} \ + // expected-warning {{base class 'struct B1' will be initialized after}} + B() {} // expected-note {{base 'struct B'}} + int s1; + int s2; + int s3; +}; |