diff options
Diffstat (limited to 'clang')
-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'}} +}; + + |