Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -785,11 +785,29 @@ void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV, GlobalDecl GD) const { const auto *D = dyn_cast(GD.getDecl()); - if (const auto *Dtor = dyn_cast_or_null(D)) { - if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) { + if (dyn_cast_or_null(D)) { + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { // Don't dllexport/import destructor thunks. - GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); - return; + //GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); + switch (GD.getDtorType()) { + case CXXDtorType::Dtor_Base: + case CXXDtorType::Dtor_Deleting: { + // Don't dllexport/import destructor thunks. + GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); + break; + } + case CXXDtorType::Dtor_Comdat: + case CXXDtorType::Dtor_Complete: { + const auto *FD = cast(GD.getDecl()); + if (FD->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); + else if (FD->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + else + GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); + break; + } + } } } setDLLImportDLLExport(GV, D); @@ -1074,12 +1092,28 @@ GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (isa(D) && - getCXXABI().useThunkForDtorVariant(cast(D), - GD.getDtorType())) { + Context.getTargetInfo().getCXXABI().isMicrosoft()) { // 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; + 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) && + D->isVirtualAsWritten()) + 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) && Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -3842,6 +3842,12 @@ if (dtorType == StructorType::Base && !CGM.TryEmitBaseDestructorAsAlias(dtor)) return; + // Don't emit vbase destructor if dtor is complete and class has + // dllimport attribute. + if (dtorType == StructorType::Complete && + dtor->hasAttr()) + return; + llvm::Function *Fn = CGM.codegenCXXStructor(dtor, dtorType); if (Fn->isWeakForLinker()) Fn->setComdat(CGM.getModule().getOrInsertComdat(Fn->getName())); Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -615,7 +615,7 @@ struct __declspec(dllexport) Z { virtual ~Z() {} }; // The scalar deleting dtor does not get exported: -// M32-DAG: define linkonce_odr dso_local x86_thiscallcc i8* @"\01??_GZ@@UAEPAXI@Z" +// M32-DAG: define linkonce_odr dso_local dllexport x86_thiscallcc i8* @"\01??_GZ@@UAEPAXI@Z" // The user-defined dtor does get exported: @@ -627,14 +627,14 @@ A::~A() { } B::~B() { } // Emit a alias definition of B's constructor. - // M32-DAG: @"\01??1B@UseDtorAlias@@QAE@XZ" = dso_local dllexport alias {{.*}} @"\01??1A@UseDtorAlias@@QAE@XZ" + // M32-DAG: define dso_local dllexport x86_thiscallcc void @"\01??1A@UseDtorAlias@@QAE@XZ" } struct __declspec(dllexport) DefaultedCtorsDtors { DefaultedCtorsDtors() = default; // M32MSVC2013-DAG: define weak_odr dso_local dllexport x86_thiscallcc %struct.DefaultedCtorsDtors* @"\01??0DefaultedCtorsDtors@@QAE@XZ" ~DefaultedCtorsDtors() = default; - // M32MSVC2013-DAG: define weak_odr dso_local dllexport x86_thiscallcc void @"\01??1DefaultedCtorsDtors@@QAE@XZ" + // M32MSVC2013-DAG: define weak_odr dso_local dllexport x86_thiscallcc %struct.DefaultedCtorsDtors* @"\01??0DefaultedCtorsDtors@@QAE@XZ" }; // Export defaulted member function definitions declared inside class. @@ -720,7 +720,7 @@ NonExportedBaseClass::~NonExportedBaseClass() {} struct __declspec(dllexport) ExportedDerivedClass : NonExportedBaseClass {}; -// M32-DAG: weak_odr dso_local dllexport x86_thiscallcc void @"\01??1ExportedDerivedClass@@UAE@XZ" +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %struct.ExportedDerivedClass* @"\01??0ExportedDerivedClass@@QAE@ABU0@@Z" // Do not assert about generating code for constexpr functions twice during explicit instantiation (PR21718). template struct ExplicitInstConstexprMembers { 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 %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() {} @@ -40,10 +39,6 @@ // The destructors are called in reverse order of construction. Only the third // needs the complete destructor (_D). // CHECK-LABEL: define dso_local 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??_DImportVBaseOverrideVDtor@@QEAAXXZ"(%struct.ImportVBaseOverrideVDtor* %t3) +// CHECK-LABEL: declare dllimport void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"(%struct.ImportVBaseOverrideVDtor*) -// CHECK-LABEL: define linkonce_odr dso_local void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ" -// CHECK-LABEL: declare dllimport void @"\01??1ImportOverrideVDtor@@UEAA@XZ" -// CHECK-LABEL: declare dllimport void @"\01??1ImportIntroVDtor@@UEAA@XZ" 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,11 +456,10 @@ // GO1-DAG: define linkonce_odr dso_local 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 dso_local x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this) // G64-DAG: define linkonce_odr dso_local void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this) - // MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"( + // MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportSpecials@@QAEXXZ"(%struct.ImportSpecials*) // GO1-DAG: define linkonce_odr dso_local x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev( __declspec(dllimport) ~ImportInlineSpecials() {} @@ -512,11 +510,10 @@ // GO1-DAG: define linkonce_odr dso_local 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 dso_local x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this) // G64-DAG: define linkonce_odr dso_local void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this) - // MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* %this) + // MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DImportDefaulted@@QAEXXZ"(%struct.ImportDefaulted*) // GO1-DAG: define linkonce_odr dso_local x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this) __declspec(dllimport) ~ImportDefaulted() = default; @@ -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"*) + +} // 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,7 @@ 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 %struct.ClassWithNonDllImportFieldWithCtor* @"\01??0ClassWithNonDllImportFieldWithCtor@@QAE@XZ"(%struct.ClassWithNonDllImportFieldWithCtor* returned) struct ClassWithCtor { ClassWithCtor() {} }; struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; }; USECLASS(ClassWithNonDllImportFieldWithCtor); @@ -679,7 +678,7 @@ struct __declspec(dllimport) Z { virtual ~Z() {} }; USECLASS(Z) // User-defined dtor: -// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1Z@@UAE@XZ" +// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DZ@@QAEXXZ"(%struct.Z*) namespace DontUseDtorAlias { struct __declspec(dllimport) A { ~A(); }; @@ -687,7 +686,7 @@ inline A::~A() { } inline B::~B() { } // Emit a real definition of B's constructor; don't alias it to A's. - // MO1-DAG: available_externally dllimport x86_thiscallcc void @"\01??1B@DontUseDtorAlias@@QAE@XZ" + // MO1-DAG: declare dllimport x86_thiscallcc void @"\01??_DB@DontUseDtorAlias@@QAEXXZ"(%"struct.DontUseDtorAlias::B"*) USECLASS(B) } Index: test/CodeGenCXX/dllimport_1.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/dllimport_1.cpp @@ -0,0 +1,18 @@ +// 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 + +struct __declspec(dllimport) Foo { + Foo() {} + ~Foo() {} + + Foo(const Foo &) = delete; + Foo &operator=(const Foo &) = delete; +}; +// MO2-DAG: declare dllimport x86_thiscallcc void @"\01??_DFoo@@QAEXXZ" +// MO2-DAG: define available_externally dllimport x86_thiscallcc %struct.Foo* @"\01??0Foo@@QAE@XZ" + +// MO3-DAG: declare dllimport x86_thiscallcc %struct.Foo* @"\01??0Foo@@QAE@XZ" +// MO4-DAG: declare dllimport x86_thiscallcc void @"\01??_DFoo@@QAEXXZ" + +void f() { Foo obj; } Index: test/CodeGenCXX/external-linkage.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/external-linkage.cpp @@ -0,0 +1,18 @@ +// 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" +