From adf5dc340db3ea99de5fe3f6c42cfee1807d445e Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 15 May 2011 17:36:21 +0000 Subject: [PATCH] Re-enable the fix for PR9181 now that all the edge cases are handled. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131385 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGClass.cpp | 88 +++++++++++++++---- test/CodeGenCXX/mangle-subst-std.cpp | 2 +- .../skip-vtable-pointer-initialization.cpp | 83 ++++++++++++++++- 3 files changed, 152 insertions(+), 21 deletions(-) diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 73dfc9fe7d..8b4684cb38 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -741,14 +741,78 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args); } +static bool +FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field); + +static bool +HasTrivialDestructorBody(ASTContext &Context, + const CXXRecordDecl *BaseClassDecl, + const CXXRecordDecl *MostDerivedClassDecl) +{ + // If the destructor is trivial we don't have to check anything else. + if (BaseClassDecl->hasTrivialDestructor()) + return true; + + if (!BaseClassDecl->getDestructor()->hasTrivialBody()) + return false; + + // Check fields. + for (CXXRecordDecl::field_iterator I = BaseClassDecl->field_begin(), + E = BaseClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + if (!FieldHasTrivialDestructorBody(Context, Field)) + return false; + } + + // Check non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + BaseClassDecl->bases_begin(), E = BaseClassDecl->bases_end(); + I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *NonVirtualBase = + cast(I->getType()->castAs()->getDecl()); + if (!HasTrivialDestructorBody(Context, NonVirtualBase, + MostDerivedClassDecl)) + return false; + } + + if (BaseClassDecl == MostDerivedClassDecl) { + // Check virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); + I != E; ++I) { + const CXXRecordDecl *VirtualBase = + cast(I->getType()->castAs()->getDecl()); + if (!HasTrivialDestructorBody(Context, VirtualBase, + MostDerivedClassDecl)) + return false; + } + } + + return true; +} + +static bool +FieldHasTrivialDestructorBody(ASTContext &Context, + const FieldDecl *Field) +{ + QualType FieldBaseElementType = Context.getBaseElementType(Field->getType()); + + const RecordType *RT = FieldBaseElementType->getAs(); + if (!RT) + return true; + + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl); +} + /// CanSkipVTablePointerInitialization - Check whether we need to initialize /// any vtable pointers before calling this destructor. static bool CanSkipVTablePointerInitialization(ASTContext &Context, const CXXDestructorDecl *Dtor) { - // FIXME: We need to check dtors of bases of members too. - // Re-enable once this has been fixed. - return false; - if (!Dtor->hasTrivialBody()) return false; @@ -757,21 +821,9 @@ static bool CanSkipVTablePointerInitialization(ASTContext &Context, for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { const FieldDecl *Field = *I; - - QualType FieldBaseElementType = - Context.getBaseElementType(Field->getType()); - const RecordType *RT = FieldBaseElementType->getAs(); - if (!RT) - continue; - - CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) - continue; - if (FieldClassDecl->getDestructor()->hasTrivialBody()) - continue; - - return false; + if (!FieldHasTrivialDestructorBody(Context, Field)) + return false; } return true; diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index fea3582d32..c54d3e5297 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -8,8 +8,8 @@ // CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant // CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant -// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant // CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant namespace std { struct A { A(); }; diff --git a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp index 3b70ec03a3..3520b912cf 100644 --- a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp +++ b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -// XFAIL: * namespace Test1 { @@ -104,4 +103,84 @@ A::~A() { } -} \ No newline at end of file +} + +namespace Test6 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a member +// variable with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field { + NonTrivialDestructorBody nonTrivialDestructorBody; +}; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test61AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test7 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a base +// class with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field : NonTrivialDestructorBody { }; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test71AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test8 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a virtual base +// class with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field : virtual NonTrivialDestructorBody { }; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test81AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} -- 2.40.0