]> granicus.if.org Git - clang/commitdiff
Sema check on out of order object initialization of
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 9 Jul 2009 19:59:47 +0000 (19:59 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 9 Jul 2009 19:59:47 +0000 (19:59 +0000)
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

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/constructor-initializer.cpp
test/SemaCXX/warn-reorder-ctor-initialization.cpp [new file with mode: 0644]

index 2896f7988c016cc86661073761992e3ba8a85d5b..ee23269c74b84bb131d7b8c8999b9ed7eacf8862 100644 (file)
@@ -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
  ]>;
 
index 7b38b25c803dbc1469f818ca1db2eb86448e01fe..7078530dc6f396176b32bd9f3f3e3a7dcb7210ce 100644 (file)
@@ -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<
index e27b822337afb9309f6f95be9a49801ec4abc594..b942c9c2750be302b119118a138523e4273cdf47 100644 (file)
@@ -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 {
index a180d907f1b7669a1fd1315d9c8b20529ca6bfb7..206d5d2ae77c42b872d782f56a2edf54cefc1410 100644 (file)
@@ -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 (file)
index 0000000..83b6710
--- /dev/null
@@ -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;
+};