Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -846,14 +846,25 @@ GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (isa(D) && - getCXXABI().useThunkForDtorVariant(cast(D), - GD.getDtorType())) { - // Destructor variants in the Microsoft C++ ABI are always internal or - // linkonce_odr thunks emitted on an as-needed basis. - return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage - : llvm::GlobalValue::LinkOnceODRLinkage; + Context.getTargetInfo().getCXXABI().isMicrosoft()) { + switch (GD.getDtorType()) { + case CXXDtorType::Dtor_Base: + break; + case CXXDtorType::Dtor_Comdat: + case CXXDtorType::Dtor_Complete: + if (D->hasAttr() && + (cast(D)->getParent()->getNumVBases() || + (Linkage == GVA_AvailableExternally || + Linkage == GVA_StrongExternal))) + return llvm::Function::AvailableExternallyLinkage; + else + return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage + : llvm::GlobalValue::LinkOnceODRLinkage; + case CXXDtorType::Dtor_Deleting: + return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage + : llvm::GlobalValue::LinkOnceODRLinkage; + } } - if (isa(D) && cast(D)->isInheritingConstructor() && Context.getTargetInfo().getCXXABI().isMicrosoft()) { @@ -869,12 +880,25 @@ void CodeGenModule::setFunctionDLLStorageClass(GlobalDecl GD, llvm::Function *F) { const auto *FD = cast(GD.getDecl()); - if (const auto *Dtor = dyn_cast_or_null(FD)) { - if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) { + if (dyn_cast_or_null(FD)) { + switch (GD.getDtorType()) { + case CXXDtorType::Dtor_Comdat: + case CXXDtorType::Dtor_Deleting: { // Don't dllexport/import destructor thunks. F->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); return; } + case CXXDtorType::Dtor_Complete: + if (FD->hasAttr()) + F->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); + else if (FD->hasAttr()) + F->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + else + F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); + return; + case CXXDtorType::Dtor_Base: + break; + } } if (FD->hasAttr()) Index: test/CodeGenCXX/dllimport-dtor-thunks.cpp =================================================================== --- test/CodeGenCXX/dllimport-dtor-thunks.cpp +++ test/CodeGenCXX/dllimport-dtor-thunks.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -mconstructor-aliases %s -triple x86_64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -mconstructor-aliases %s -triple x86_64-windows-msvc -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck --check-prefix=MO1 %s // FIXME: We should really consider removing -mconstructor-aliases for MS C++ // ABI. The risk of bugs introducing ABI incompatibility under @@ -23,9 +24,7 @@ virtual ~ImportOverrideVDtor() {} }; -// Virtually inherits from a non-dllimport base class. This time we need to call -// the complete destructor and emit it inline. It's not exported from the DLL, -// and it must be emitted. +// Virtually inherits from a non-dllimport base class. Emit the vbase destructor. struct __declspec(dllimport) ImportVBaseOverrideVDtor : public virtual BaseClass { virtual ~ImportVBaseOverrideVDtor() {} @@ -41,9 +40,11 @@ // needs the complete destructor (_D). // CHECK-LABEL: define void @testit() // CHECK: call void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"(%struct.ImportVBaseOverrideVDtor* %{{.*}}) -// CHECK: call void @"\01??1ImportOverrideVDtor@@UEAA@XZ"(%struct.ImportOverrideVDtor* %{{.*}}) -// CHECK: call void @"\01??1ImportIntroVDtor@@UEAA@XZ"(%struct.ImportIntroVDtor* %{{.*}}) +// CHECK: call void @"\01??_DImportOverrideVDtor@@QEAAXXZ"(%struct.ImportOverrideVDtor* %{{.*}}) +// CHECK: call void @"\01??_DImportIntroVDtor@@QEAAXXZ"(%struct.ImportIntroVDtor* %{{.*}}) -// CHECK-LABEL: define linkonce_odr void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ" -// CHECK-LABEL: declare dllimport void @"\01??1ImportOverrideVDtor@@UEAA@XZ" -// CHECK-LABEL: declare dllimport void @"\01??1ImportIntroVDtor@@UEAA@XZ" +// CHECK-LABEL: declare dllimport void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"(%struct.ImportVBaseOverrideVDtor*) +// CHECK-LABEL: declare dllimport void @"\01??_DImportOverrideVDtor@@QEAAXXZ"(%struct.ImportOverrideVDtor*) +// CHECK-LABEL: declare dllimport void @"\01??_DImportIntroVDtor@@QEAAXXZ"(%struct.ImportIntroVDtor*) + +// MO1-DAG: define available_externally dllimport void @"\01??_DImportIntroVDtor@@QEAAXXZ" Index: test/CodeGenCXX/dllimport-members.cpp =================================================================== --- test/CodeGenCXX/dllimport-members.cpp +++ test/CodeGenCXX/dllimport-members.cpp @@ -414,8 +414,7 @@ // G64-DAG: declare dllimport void @_ZN14ImportSpecialsC1Ev(%struct.ImportSpecials*) __declspec(dllimport) ImportSpecials(); - // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportSpecials@@QAE@XZ"(%struct.ImportSpecials*) - // M64-DAG: declare dllimport void @"\01??1ImportSpecials@@QEAA@XZ"(%struct.ImportSpecials*) + // M32-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportSpecials@@QAEXXZ"(%struct.ImportSpecials*) // G32-DAG: declare dllimport x86_thiscallcc void @_ZN14ImportSpecialsD1Ev(%struct.ImportSpecials*) // G64-DAG: declare dllimport void @_ZN14ImportSpecialsD1Ev(%struct.ImportSpecials*) __declspec(dllimport) ~ImportSpecials(); @@ -457,8 +456,7 @@ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1Ev( __declspec(dllimport) ImportInlineSpecials() {} - // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"(%struct.ImportInlineSpecials*) - // M64-DAG: declare dllimport void @"\01??1ImportInlineSpecials@@QEAA@XZ"(%struct.ImportInlineSpecials*) + // M32-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportInlineSpecials@@QAEXXZ"(%struct.ImportInlineSpecials*) // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this) // G64-DAG: define linkonce_odr void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this) // MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"( @@ -512,8 +510,7 @@ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted* %this) __declspec(dllimport) ImportDefaulted() = default; - // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted*) - // M64-DAG: declare dllimport void @"\01??1ImportDefaulted@@QEAA@XZ"(%struct.ImportDefaulted*) + // M32-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportDefaulted@@QAEXXZ"(%struct.ImportDefaulted*) // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this) // G64-DAG: define linkonce_odr void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this) // MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* %this) @@ -578,8 +575,7 @@ #ifdef MSABI // For MinGW, the function will not be dllimport, and we cannot add the attribute now. -// M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportDefaultedDefs@@QAE@XZ"(%struct.ImportDefaultedDefs*) -// M64-DAG: declare dllimport void @"\01??1ImportDefaultedDefs@@QEAA@XZ"(%struct.ImportDefaultedDefs*) +// M32-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportDefaulted@@QAEXXZ"(%struct.ImportDefaulted*) __declspec(dllimport) ImportDefaultedDefs::~ImportDefaultedDefs() = default; #endif Index: test/CodeGenCXX/dllimport-virtual-base.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/dllimport-virtual-base.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -triple i386-pc-windows -emit-llvm -fms-compatibility %s -x c++ -o - | FileCheck %s + +namespace test1 { +struct BaseClass { + ~BaseClass(); +}; + +struct __declspec(dllimport) Concrete : virtual BaseClass { +}; + +Concrete c; + +// CHECK-LABEL: declare dllimport x86_thiscallcc %"struct.test1::Concrete"* @"\01??0Concrete@test1@@QAE@XZ" +// CHECK-LABEL: declare dllimport x86_thiscallcc void @"\01??_DConcrete@test1@@QAEXXZ"(%"struct.test1::Concrete"*) unnamed_addr #2 + +} // namespace test1 + +namespace test2 { +class BaseClass { +public: + virtual ~BaseClass(){}; +}; + +class __declspec(dllimport) VirtualClass : public virtual BaseClass { +public: + virtual ~VirtualClass(){}; +}; + +int main() { + VirtualClass c; + return 0; +} + +// CHECK-LABEL: declare dllimport x86_thiscallcc %"class.test2::VirtualClass"* @"\01??0VirtualClass@test2@@QAE@XZ" +// CHECK-LABEL: declare dllimport x86_thiscallcc void @"\01??_DVirtualClass@test2@@QAEXXZ"(%"class.test2::VirtualClass"*) + +} // namespace test2 + +namespace test3 { +class IVirtualBase { +public: + virtual ~IVirtualBase(){}; + virtual void speak() = 0; +}; + +class VirtualClass : public virtual IVirtualBase { +public: + virtual ~VirtualClass(){}; + virtual void eat() = 0; +}; + +class __declspec(dllimport) ConcreteClass : public VirtualClass { +public: + ConcreteClass(int nn); + void speak(); + void eat(); + virtual ~ConcreteClass(); + +private: + int n; +}; + +int main() { + ConcreteClass c(10); + c.speak(); + c.eat(); + return 0; +} + +// CHECK-LABEL: declare dllimport x86_thiscallcc %"class.test3::ConcreteClass"* @"\01??0ConcreteClass@test3@@QAE@H@Z" +// CHECK-LABEL: declare dllimport x86_thiscallcc void @"\01??_DConcreteClass@test3@@QAEXXZ"(%"class.test3::ConcreteClass"*) + +} // namespace test3 Index: test/CodeGenCXX/dllimport.cpp =================================================================== --- test/CodeGenCXX/dllimport.cpp +++ test/CodeGenCXX/dllimport.cpp @@ -362,8 +362,8 @@ struct __declspec(dllimport) ClassWithNonDllImportBase : public ClassWithDtor { }; USECLASS(ClassWithNonDllImportField); USECLASS(ClassWithNonDllImportBase); -// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??1ClassWithNonDllImportBase@@QAE@XZ"(%struct.ClassWithNonDllImportBase*) -// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??1ClassWithNonDllImportField@@QAE@XZ"(%struct.ClassWithNonDllImportField*) +// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DClassWithNonDllImportBase@@QAEXXZ"(%struct.ClassWithNonDllImportBase*) +// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DClassWithNonDllImportField@@QAEXXZ"(%struct.ClassWithNonDllImportField*) struct ClassWithCtor { ClassWithCtor() {} }; struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; }; USECLASS(ClassWithNonDllImportFieldWithCtor); Index: test/CodeGenCXX/external-linkage.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/external-linkage.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -fms-compatibility-version=18.00 -emit-llvm -std=c++1y -O1 -disable-llvm-passes -o - %s -DMSABI -w | FileCheck --check-prefix=MO1 --check-prefix=MO2 %s + +// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -fno-threadsafe-statics -fms-extensions -fms-compatibility-version=18.00 -emit-llvm -std=c++1y -o - %s -DMSABI -w | FileCheck --check-prefix=MO3 --check-prefix=MO4 %s + +// MO1-DAG:@"\01??_8B@@7B@" = available_externally dllimport unnamed_addr constant [2 x i32] [i32 0, i32 4] +// MO2-DAG: define available_externally dllimport x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ" + +struct __declspec(dllimport) A { + virtual ~A(); +}; +struct __declspec(dllimport) B : virtual A { + virtual ~B(); +}; +void f() { B b; } + +// MO3-DAG: declare dllimport x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ" +// MO4-DAG: declare dllimport x86_thiscallcc void @"\01??_DB@@QAEXXZ"