[ms-cxxabi] Emit linkonce complete dtors in TUs that need them
Based on Peter Collingbourne's destructor patches. Prior to this change, clang was considering ?1 to be the complete destructor and the base destructor, which was wrong. This lead to crashes when clang tried to emit two LLVM functions with the same name. In this ABI, TUs with non-inline dtors might not emit a complete destructor. They are emitted as inline thunks in TUs that need them, and they always delegate to the base dtors of the complete class and its virtual bases. This change uses the DeferredDecls machinery to emit complete dtors as needed. Currently in clang try body destructors can catch exceptions thrown by virtual base destructors. In the Microsoft C++ ABI, clang may not have the destructor definition, in which case clang won't wrap the virtual virtual base destructor calls in a try-catch. Diagnosing this in user code is TODO. Finally, for classes that don't use virtual inheritance, MSVC always calls the base destructor (?1) directly. This is a useful code size optimization that avoids emitting lots of extra thunks or aliases. Implementing it also means our existing tests continue to pass, and is consistent with MSVC's output. We can do the same for Itanium by tweaking GetAddrOfCXXDestructor, but it will require further testing. Reviewers: rjmccall CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1066 llvm-svn: 186828
This commit is contained in:
@@ -228,22 +228,6 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
|
||||
/*ForVTable=*/false));
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
|
||||
// The destructor in a virtual table is always a 'deleting'
|
||||
// destructor, which calls the complete destructor and then uses the
|
||||
// appropriate operator delete.
|
||||
if (D->isVirtual())
|
||||
EmitGlobal(GlobalDecl(D, Dtor_Deleting));
|
||||
|
||||
// The destructor used for destructing this as a most-derived class;
|
||||
// call the base destructor and then destructs any virtual bases.
|
||||
EmitGlobal(GlobalDecl(D, Dtor_Complete));
|
||||
|
||||
// The destructor used for destructing this as a base class; ignores
|
||||
// virtual bases.
|
||||
EmitGlobal(GlobalDecl(D, Dtor_Base));
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
|
||||
CXXDtorType dtorType) {
|
||||
// The complete destructor is equivalent to the base destructor for
|
||||
@@ -277,16 +261,27 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
|
||||
llvm::GlobalValue *
|
||||
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
|
||||
CXXDtorType dtorType,
|
||||
const CGFunctionInfo *fnInfo) {
|
||||
const CGFunctionInfo *fnInfo,
|
||||
llvm::FunctionType *fnType) {
|
||||
// If the class has no virtual bases, then the complete and base destructors
|
||||
// are equivalent, for all C++ ABIs supported by clang. We can save on code
|
||||
// size by calling the base dtor directly, especially if we'd have to emit a
|
||||
// thunk otherwise.
|
||||
// FIXME: We should do this for Itanium, after verifying that nothing breaks.
|
||||
if (dtorType == Dtor_Complete && dtor->getParent()->getNumVBases() == 0 &&
|
||||
getCXXABI().useThunkForDtorVariant(dtor, Dtor_Complete))
|
||||
dtorType = Dtor_Base;
|
||||
|
||||
GlobalDecl GD(dtor, dtorType);
|
||||
|
||||
StringRef name = getMangledName(GD);
|
||||
if (llvm::GlobalValue *existing = GetGlobalValue(name))
|
||||
return existing;
|
||||
|
||||
if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
|
||||
|
||||
llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
|
||||
if (!fnType) {
|
||||
if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
|
||||
fnType = getTypes().GetFunctionType(*fnInfo);
|
||||
}
|
||||
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
|
||||
/*ForVTable=*/false));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user