diff options
| -rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 15 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 72 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 14 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp | 70 | 
4 files changed, 160 insertions, 11 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 90c86b17d28..ff0dd676aa7 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -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. diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index f525667ad0a..b7051f8d2c5 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -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 { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b942c9c2750..17726c64f04 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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) diff --git a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp index 83b671010c3..107c89355e6 100644 --- a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp +++ b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp @@ -1,18 +1,76 @@  // RUN: clang-cc  -fsyntax-only -Wreorder -verify %s -struct B {}; +struct BB {}; -struct B1 {}; +struct BB1 {}; -class complex : public B, B1 {  +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'}} +}; + +  | 

