]> granicus.if.org Git - clang/commitdiff
Patch to build list of inherited virtual base classes
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 10 Jul 2009 20:13:23 +0000 (20:13 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 10 Jul 2009 20:13:23 +0000 (20:13 +0000)
in their order of construction for each class and use it
to to check on propery order of base class construction
under -Wreorder option.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75270 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/warn-reorder-ctor-initialization.cpp

index 90c86b17d2880384c3fdb35aa16a8b9fd8cedf9d..ff0dd676aa715c9d066ffc5960be2870f3c1e0b4 100644 (file)
@@ -310,6 +310,12 @@ class CXXRecordDecl : public RecordDecl {
   /// NumBases - The number of base class specifiers in Bases.
   unsigned NumBases;
 
+  /// VBases - direct and indirect virtual base classes of this class.
+  CXXBaseSpecifier *VBases;
+  
+  /// NumVBases - The number of virtual base class specifiers in VBases.
+  unsigned NumVBases;
+  
   /// Conversions - Overload set containing the conversion functions
   /// of this C++ class (but not its inherited conversion
   /// functions). Each of the entries in this overload set is a
@@ -361,6 +367,15 @@ public:
   base_class_const_iterator bases_begin() const { return Bases; }
   base_class_iterator       bases_end()         { return Bases + NumBases; }
   base_class_const_iterator bases_end()   const { return Bases + NumBases; }
+  
+  /// getNumVBases - Retrieves the number of virtual base classes of this
+  /// class.
+  unsigned getNumVBases() const { return NumVBases; }
+  
+  base_class_iterator       vbases_begin()       { return VBases; }
+  base_class_const_iterator vbases_begin() const { return VBases; }
+  base_class_iterator       vbases_end()         { return VBases + NumVBases; }
+  base_class_const_iterator vbases_end()   const { return VBases + NumVBases; }
 
   /// hasConstCopyConstructor - Determines whether this class has a
   /// copy constructor that accepts a const-qualified argument.
index f525667ad0a644f0cc799bddaa48e4bf42475311..b7051f8d2c53f5119ae5da1b330505570392f810 100644 (file)
@@ -30,7 +30,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
     HasTrivialConstructor(true), HasTrivialDestructor(true),
-    Bases(0), NumBases(0), Conversions(DC, DeclarationName()),
+    Bases(0), NumBases(0), VBases(0), NumVBases(0),
+    Conversions(DC, DeclarationName()),
     TemplateOrInstantiation() { }
 
 CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -62,11 +63,76 @@ CXXRecordDecl::setBases(ASTContext &C,
 
   if (this->Bases)
     C.Deallocate(this->Bases);
-
+  
+  int vbaseCount = 0;
+  llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
+  bool hasDirectVirtualBase = false;
+  
   this->Bases = new(C) CXXBaseSpecifier [NumBases];
   this->NumBases = NumBases;
-  for (unsigned i = 0; i < NumBases; ++i)
+  for (unsigned i = 0; i < NumBases; ++i) {
     this->Bases[i] = *Bases[i];
+    // Keep track of inherited vbases for this base class.
+    const CXXBaseSpecifier *Base = Bases[i];
+    QualType BaseType = Base->getType();
+    // Skip template types. 
+    // FIXME. This means that this list must be rebuilt during template
+    // instantiation.
+    if (BaseType->isDependentType())
+      continue;
+    CXXRecordDecl *BaseClassDecl
+      = cast<CXXRecordDecl>(BaseType->getAsRecordType()->getDecl());
+    if (Base->isVirtual())
+      hasDirectVirtualBase = true;
+    for (CXXRecordDecl::base_class_iterator VBase = 
+          BaseClassDecl->vbases_begin(),
+         E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
+      // Add this vbase to the array of vbases for current class if it is 
+      // not already in the list.
+      // FIXME. Note that we do a linear search as number of such classes are
+      // very few.
+      int i;
+      for (i = 0; i < vbaseCount; ++i)
+        if (UniqueVbases[i]->getType() == VBase->getType())
+          break;
+      if (i == vbaseCount) {
+        UniqueVbases.push_back(VBase);
+        ++vbaseCount;
+      }
+    }
+  }
+  if (hasDirectVirtualBase) {
+    // Iterate one more time through the direct bases and add the virtual
+    // base to the list of vritual bases for current class.
+    for (unsigned i = 0; i < NumBases; ++i) {
+      const CXXBaseSpecifier *VBase = Bases[i];
+      if (!VBase->isVirtual())
+        continue;
+      int i;
+      for (i = 0; i < vbaseCount; ++i)
+        if (UniqueVbases[i]->getType() == VBase->getType())
+          break;
+      if (i == vbaseCount) {
+        UniqueVbases.push_back(VBase);
+        ++vbaseCount;
+      }
+    }
+  }
+  if (vbaseCount > 0) {
+    // build AST for inhireted, direct or indirect, virtual bases.
+    this->VBases = new(C) CXXBaseSpecifier [vbaseCount];
+    this->NumVBases = vbaseCount;
+    for (int i = 0; i < vbaseCount; i++) {
+      QualType QT = UniqueVbases[i]->getType();
+      CXXRecordDecl *VBaseClassDecl
+        = cast<CXXRecordDecl>(QT->getAsRecordType()->getDecl());
+      this->VBases[i] = 
+        *new CXXBaseSpecifier(
+                          VBaseClassDecl->getSourceRange(), true,
+                          VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+                          UniqueVbases[i]->getAccessSpecifier(), QT);
+    }
+  }
 }
 
 bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
index b942c9c2750be302b119118a138523e4273cdf47..17726c64f04cfb3230b096542b0f594609a5f6d0 100644 (file)
@@ -825,14 +825,24 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
                     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());
+    // Push virtual bases before others.
+    for (CXXRecordDecl::base_class_iterator VBase =
+         ClassDecl->vbases_begin(),
+         E = ClassDecl->vbases_end(); VBase != E; ++VBase)
+      AllBaseOrMembers.push_back(VBase->getType()->getAsRecordType());
+      
     for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
-         E = ClassDecl->bases_end(); Base != E; ++Base)
+         E = ClassDecl->bases_end(); Base != E; ++Base) {
+      // Virtuals are alread in the virtual base list and are constructed
+      // first.
+      if (Base->isVirtual())
+        continue;
       AllBaseOrMembers.push_back(Base->getType()->getAsRecordType());
+    }
     
     for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
          E = ClassDecl->field_end(); Field != E; ++Field)
index 83b671010c3334b1199df3225e8e7977a39154b3..107c89355e6738a882c7ca0ea1add5261dd499e8 100644 (file)
@@ -1,18 +1,76 @@
 // RUN: clang-cc  -fsyntax-only -Wreorder -verify %s
 
-struct B {};
+struct BB {};
 
-struct B1 {};
+struct BB1 {};
 
-class complex : public BB1 { 
+class complex : public BB, BB1 { 
 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'}}
+              BB1(),   // expected-note {{base 'struct BB1'}}  \
+                      // expected-warning {{base class 'struct BB1' will be initialized after}}
+              BB() {}  // expected-note {{base 'struct BB'}}
   int s1;
   int s2;
   int s3;
 }; 
+
+
+// testing virtual bases.
+
+
+struct V { 
+  V();
+};
+
+struct A : public virtual V { 
+  A(); 
+};
+
+struct B : public virtual V {
+  B(); 
+};
+
+struct Diamond : public A, public B {
+  Diamond() : A(), B() {}
+};
+
+
+struct C : public A, public B, private virtual V { 
+  C() { }
+};
+
+
+struct D : public A, public B { 
+  D()  : A(), V() {   } // expected-warning {{base class 'struct A' will be initialized after}} \
+                        // expected-note {{base 'struct V'}}
+};
+
+
+struct E : public A, public B, private virtual V { 
+  E()  : A(), V() {  } // expected-warning {{base class 'struct A' will be initialized after}} \
+                       // expected-note {{base 'struct V'}}
+};
+
+
+struct A1  { 
+  A1(); 
+};
+
+struct B1 {
+  B1();
+};
+
+struct F : public A1, public B1, private virtual V { 
+  F()  : A1(), V() {  }        // expected-warning {{base class 'struct A1' will be initialized after}} \
+                       // expected-note {{base 'struct V'}}
+};
+
+struct X : public virtual A, virtual V, public virtual B {
+  X(): A(), V(), B() {}        // expected-warning {{base class 'struct A' will be initialized after}} \
+                       // expected-note {{base 'struct V'}}
+};
+
+