diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1cadaf54b7bdd..1a470c7dd3b0e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6551,6 +6551,8 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { return; } + TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr->isInherited()) { // Diagnose dll attributes on members of class with dll attribute. @@ -6561,6 +6563,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (!MemberAttr || MemberAttr->isInherited() || Member->isInvalidDecl()) continue; + if ((TSK == TSK_ExplicitInstantiationDeclaration || + TSK == TSK_ExplicitInstantiationDefinition) && + Member->hasAttr()) + continue; + Diag(MemberAttr->getLocation(), diag::err_attribute_dll_member_of_dll_class) << MemberAttr << ClassAttr; @@ -6583,8 +6590,6 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { !ClassExported && cast(ClassAttr)->wasPropagatedToBaseTemplate(); - TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); - // Ignore explicit dllexport on explicit class template instantiation // declarations, except in MinGW mode. if (ClassExported && !ClassAttr->isInherited() && @@ -6601,6 +6606,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // seem to be true in practice? for (Decl *Member : Class->decls()) { + if ((TSK == TSK_ExplicitInstantiationDeclaration || + TSK == TSK_ExplicitInstantiationDefinition) && + Member->hasAttr()) + continue; + VarDecl *VD = dyn_cast(Member); CXXMethodDecl *MD = dyn_cast(Member); @@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() { } } - if (IsExplicitInstantiationDeclaration) + if (IsExplicitInstantiationDeclaration && + llvm::none_of(Class->decls(), [](Decl *decl) { + // If the class has a virtual member function declared with + // `__attribute__((exclude_from_explicit_instantiation))`, the + // explicit instantiation declaration shouldn't suppress emitting + // the vtable to ensure that the excluded member function is + // accessible through the vtable. + auto *Method = dyn_cast(decl); + return Method && Method->isVirtual() && + Method->hasAttr(); + })) DefineVTable = false; } diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp new file mode 100644 index 0000000000000..c955c932a3619 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -0,0 +1,180 @@ +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllexport +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllexport + +// Test that __declspec(dllexport) doesn't instantiate entities marked with +// the exclude_from_explicit_instantiation attribute unless marked as dllexport explicitly. + +// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp +// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp +// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp +// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp + +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation)) + +template +struct C { + // This will be instantiated explicitly as an exported function because it + // inherits dllexport from the class instantiation. + void to_be_exported(); + + // This will be instantiated implicitly as an exported function because it is + // marked as dllexport explicitly. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void to_be_exported_explicitly(); + + // This will be instantiated implicitly but won't be exported. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported(); + + // This won't be instantiated. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated(); +}; + +template void C::to_be_exported() {} +template void C::to_be_exported_explicitly() {} +template void C::not_to_be_exported() {} +template void C::not_to_be_instantiated() {} + +// Attach the attribute to class template declaration instead of instantiation declaration. +template +struct __declspec(dllexport) D { + // This will be exported if and only if no explicit instantiations are provided. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_exported_iff_no_explicit_instantiation(); +}; + +template void D::to_be_exported_iff_no_explicit_instantiation() {} + +// Interaction with VTables. +template +struct E { + // This will be instanciated by the explicit template instantiation definition. + virtual void to_be_exported(); + + // This will be instantiated by the VTable definition, regardless of + // `exclude_from_explicit_instantiation`. + // The dllexport attribute won't be inherited. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated(); + + // This too, but will be exported by the member attribute. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void to_be_exported_explicitly(); +}; + +template void E::to_be_exported() {} +template void E::to_be_instantiated() {} +template void E::to_be_exported_explicitly() {} + +// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any +// MSC: $"?to_be_exported@?$E@H@@UEAAXXZ" = comdat any +// MSC: $"?to_be_exported@?$E@I@@UEAAXXZ" = comdat any +// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any +// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any +// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = comdat any +// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" = comdat any +// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any +// MSC: $"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" = comdat any +// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any +// MSC: $"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" = comdat any +// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any +// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any +// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any +// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any +// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any +// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any +// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any +// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any +// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any +// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any +// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any + +// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@H@@6B@") +// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@") +// MSC: @"??_7?$E@H@@6B@" = dllexport unnamed_addr +// MSC: @"??_7?$E@I@@6B@" = unnamed_addr +// GNU:@_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant {{.*}}, comdat +// GNU:@_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat + +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C@H@@QEAAAEAU0@AEBU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$C@H@@QEAAAEAU0@$$QEAU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$C@H@@QEAAXXZ" +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSERKS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1CIiEaSEOS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE14to_be_exportedEv +template struct __declspec(dllexport) C; + +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D@H@@QEAAAEAU0@AEBU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D@H@@QEAAAEAU0@$$QEAU0@@Z" +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSERKS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1DIiEaSEOS0_ +template struct D; // No dllexport here. +// Don't provide explicit instantiation for D. + +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E@H@@QEAAAEAU0@AEBU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$E@H@@QEAAAEAU0@$$QEAU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E@H@@QEAA@XZ" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E@H@@QEAA@AEBU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??0?$E@H@@QEAA@$$QEAU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported@?$E@H@@UEAAXXZ" +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSERKS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} ptr @_ZN1EIiEaSEOS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2Ev +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1Ev +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2ERKS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1ERKS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC2EOS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiEC1EOS0_ +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1EIiE14to_be_exportedEv +template struct __declspec(dllexport) E; + +// MSC: define weak_odr dso_local{{.*}} void @"?to_be_exported@?$E@I@@UEAAXXZ" +// GNU: define weak_odr dso_local{{.*}} void @_ZN1EIjE14to_be_exportedEv +template struct E; + +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D@I@@QEAAAEAU0@AEBU0@@Z" +// MSC: define weak_odr dso_local dllexport{{.*}} ptr @"??4?$D@I@@QEAAAEAU0@$$QEAU0@@Z" + +void use() { + C c; + + // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" + // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv + c.to_be_exported_explicitly(); // implicitly instantiated here + + // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ" + // GNU: call void @_ZN1CIiE18not_to_be_exportedEv + c.not_to_be_exported(); // implicitly instantiated here + + D di; + + // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" + // GNU: call void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv + di.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here + + D dj; + + // MSC: call void @"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" + // GNU: call void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv + dj.to_be_exported_iff_no_explicit_instantiation(); // implicitly instantiated here +} + +// MSC: define weak_odr dso_local dllexport{{.*}} void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" +// GNU: define weak_odr dso_local dllexport{{.*}} void @_ZN1CIiE25to_be_exported_explicitlyEv + +// MSC: define linkonce_odr dso_local void @"?not_to_be_exported@?$C@H@@QEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_exportedEv + +// MSC: define linkonce_odr dso_local void @"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" +// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv +// GNU: define weak_odr dso_local dllexport void @_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv + +// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E@H@@UEAAXXZ" +// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1EIiE18to_be_instantiatedEv +// GNU: define weak_odr dso_local dllexport void @_ZN1EIiE25to_be_exported_explicitlyEv + +// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E@I@@UEAAXXZ" +// MSC: define weak_odr dso_local dllexport void @"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1EIjE18to_be_instantiatedEv +// GNU: define weak_odr dso_local dllexport void @_ZN1EIjE25to_be_exported_explicitlyEv diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp new file mode 100644 index 0000000000000..492a83767c7e5 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -0,0 +1,169 @@ +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ --implicit-check-not=dllimport +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ --implicit-check-not=dllimport + +// Test that __declspec(dllimport) doesn't instantiate entities marked with +// the exclude_from_explicit_instantiation attribute unless marked as dllimport explicitly. + +// MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp +// MSC: source_filename = {{.*}}exclude_from_dllimport.cpp +// GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp +// GNU: source_filename = {{.*}}exclude_from_dllimport.cpp + +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation)) + +template +struct C { + // This will be instantiated explicitly as an imported function because it + // inherits dllimport from the class instantiation. + void to_be_imported(); + + // This will be instantiated implicitly as an imported function because it is + // marked as dllimport explicitly. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void to_be_imported_explicitly(); + + // This will be instantiated implicitly but won't be imported. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported(); + + // This won't be instantiated. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated(); +}; + +template void C::to_be_imported() {} +template void C::not_to_be_imported() {} +template void C::not_to_be_instantiated() {} + +// Attach the attribute to class template declaration instead of instantiation declaration. +template +struct __declspec(dllimport) D { + // This will be imported if and only if no explicit instantiations are provided. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION void to_be_imported_iff_no_explicit_instantiation(); +}; + +template void D::to_be_imported_iff_no_explicit_instantiation() {} + +// Interaction with VTables. +template +struct E { + // For the MSVC ABI: this constructor causes implicit instantiation of + // the VTable, which triggers instantiating all virtual member + // functions regardless `exclude_from_explicit_instantiation`. + // For the Itanium ABI: Emitting the VTable is suppressed by implicit + // instantiation declaration so virtual member functions won't be instantiated. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int); + + // This constructor doesn't trigger the instantiation of the VTable. + // In this case, declaration of virtual member functions are absent too. + explicit E(long); + + // The body of this shouldn't be emitted since instantiation is suppressed + // by the explicit instantiation declaration. + virtual void to_be_imported(); + + // The body of this should be emitted if the VTable is instantiated, even if + // the instantiation of this class template is declared with dllimport. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated(); + + // The body of this shouldn't be emitted since that comes from an external DLL. + EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void to_be_imported_explicitly(); + +}; + +template E::E(int) {} +template E::E(long) {} +template void E::to_be_imported() {} +template void E::to_be_instantiated() {} + +// MSC: $"?not_to_be_imported@?$C@H@@QEAAXXZ" = comdat any +// MSC: $"?to_be_imported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = comdat any +// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any +// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any +// GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any +// GNU: $_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv = comdat any +// GNU: @_ZTV1EIiE = external dllimport unnamed_addr +// GNU: @_ZTV1EIjE = external unnamed_addr + +// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$E@H@@6B@") +// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@") +// MSC: @"??_S?$E@H@@6B@" = +// MSC: @"??_7?$E@I@@6B@" = + +extern template struct __declspec(dllimport) C; + +extern template struct D; // No dllimport here. +// Don't provide explicit instantiation for D. + +extern template struct __declspec(dllimport) E; // $E@H, 1EIiE +extern template struct E; // $E@I, 1EIjE +extern template struct __declspec(dllimport) E; // $E@J, 1EIlE +extern template struct E; // $E@K, 1EImE + +void use() { + C c; + + // MSC: call void @"?to_be_imported@?$C@H@@QEAAXXZ" + // GNU: call void @_ZN1CIiE14to_be_importedEv + c.to_be_imported(); + + // MSC: call void @"?to_be_imported_explicitly@?$C@H@@QEAAXXZ" + // GNU: call void @_ZN1CIiE25to_be_imported_explicitlyEv + c.to_be_imported_explicitly(); // implicitly instantiated here + + // MSC: call void @"?not_to_be_imported@?$C@H@@QEAAXXZ" + // GNU: call void @_ZN1CIiE18not_to_be_importedEv + c.not_to_be_imported(); // implicitly instantiated here + + D di; + + // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" + // GNU: call void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv + di.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here + + D dj; + + // MSC: call void @"?to_be_imported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" + // GNU: call void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv + dj.to_be_imported_iff_no_explicit_instantiation(); // implicitly instantiated here + + E ei{1}; + + E ej{1}; + + E el{1L}; + + E em{1L}; +} + +// MSC: declare dllimport void @"?to_be_imported@?$C@H@@QEAAXXZ" +// GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv + +// MSC: declare dllimport void @"?to_be_imported_explicitly@?$C@H@@QEAAXXZ" +// GNU: declare dllimport void @_ZN1CIiE25to_be_imported_explicitlyEv + +// MSC: define linkonce_odr dso_local void @"?not_to_be_imported@?$C@H@@QEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv + +// MSC: define linkonce_odr dso_local void @"?to_be_imported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" +// MSC: declare dllimport void @"?to_be_imported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" +// GNU: define linkonce_odr dso_local void @_ZN1DIiE44to_be_imported_iff_no_explicit_instantiationEv +// GNU: declare dllimport void @_ZN1DIjE44to_be_imported_iff_no_explicit_instantiationEv + +// MSC: declare dllimport noundef ptr @"??0?$E@J@@QEAA@J@Z" +// MSC: declare dso_local noundef ptr @"??0?$E@K@@QEAA@J@Z" +// GNU: define linkonce_odr dso_local void @_ZN1EIiEC1Ei +// GNU: define linkonce_odr dso_local void @_ZN1EIjEC1Ei +// GNU: declare dllimport void @_ZN1EIlEC1El +// GNU: declare dso_local void @_ZN1EImEC1El +// GNU: define linkonce_odr dso_local void @_ZN1EIiEC2Ei +// GNU: define linkonce_odr dso_local void @_ZN1EIjEC2Ei + +// MSC: declare dllimport void @"?to_be_imported@?$E@H@@UEAAXXZ" +// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E@H@@UEAAXXZ" +// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E@H@@UEAAXXZ" + +// MSC: declare dso_local void @"?to_be_imported@?$E@I@@UEAAXXZ" +// MSC: define linkonce_odr dso_local void @"?to_be_instantiated@?$E@I@@UEAAXXZ" +// MSC: declare dllimport void @"?to_be_imported_explicitly@?$E@I@@UEAAXXZ"