jyu2 created this revision. jyu2 added reviewers: cfe-commits, rnk, majnemer, erichkeane. Herald added subscribers: llvm-commits, jdoerfert. Herald added a project: LLVM.
A MS only run time problem, because the init function for template static member is not getting called when the template static member is not reference. To be able to evoke the init function, MS put the template static member in the linker directive section, that cause init function gets call. As Rick suggest; add template static data member to llvm.used that cause compiler to emit a similar -include directive into the linker directive section. //bugs.llvm.org/show_bug.cgi?id=40323 Repository: rL LLVM https://reviews.llvm.org/D58160 Files: lib/CodeGen/CGDeclCXX.cpp test/CodeGenCXX/microsoft-abi-template-static-init.cpp Index: test/CodeGenCXX/microsoft-abi-template-static-init.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/microsoft-abi-template-static-init.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=i686-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s + +struct S { + S(); + ~S(); +}; + +template <typename T> struct __declspec(dllexport) ExportedTemplate { + static S s; +}; +template <typename T> S ExportedTemplate<T>::s; +void useExportedTemplate(ExportedTemplate<int> x) { + (void)x.s; +} +int f(); +namespace selectany_init { +// MS don't put selectany static var in the linker directive, init routine +// f() is not getting called if x is not referenced. +int __declspec(selectany) x = f(); +} + +namespace explicit_template_instantiation { +template <typename T> struct A { static int x; }; +template <typename T> int A<T>::x = f(); +template struct A<int>; +} + +namespace implicit_template_instantiation { +template <typename T> struct A { static int x; }; +template <typename T> int A<T>::x = f(); +int g() { return A<int>::x; } +} + + +template <class T> +struct X_ { + static T ioo; + static T init(); +}; +template <class T> T X_<T>::ioo = X_<T>::init(); +template struct X_<int>; + +template <class T> +struct X { + static T ioo; + static T init(); +}; +// template specialized static data don't need in llvm.used, +// the static init routine get call from _GLOBAL__sub_I_ routines. +template <> int X<int>::ioo = X<int>::init(); +template struct X<int>; +// CHECK: @llvm.global_ctors = appending global [6 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @"??__Ex@selectany_init@@YAXXZ", i8* bitcast (i32* @"?x@selectany_init@@3HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@explicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?ioo@?$X_@H@@2HA@@YAXXZ", i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?s@?$ExportedTemplate@H@@2US@@A@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@implicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_template_static_init.cpp, i8* null }] +// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata" + Index: lib/CodeGen/CGDeclCXX.cpp =================================================================== --- lib/CodeGen/CGDeclCXX.cpp +++ lib/CodeGen/CGDeclCXX.cpp @@ -481,6 +481,12 @@ // minor startup time optimization. In the MS C++ ABI, there are no guard // variables, so this COMDAT key is required for correctness. AddGlobalCtor(Fn, 65535, COMDATKey); + if (getTarget().getCXXABI().isMicrosoft()) { + // In The MS C++, MS add template static data member in the linker + // drective. + assert(COMDATKey); + addUsedGlobal(COMDATKey); + } } else if (D->hasAttr<SelectAnyAttr>()) { // SelectAny globals will be comdat-folded. Put the initializer into a // COMDAT group associated with the global, so the initializers get folded
Index: test/CodeGenCXX/microsoft-abi-template-static-init.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/microsoft-abi-template-static-init.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=i686-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s + +struct S { + S(); + ~S(); +}; + +template <typename T> struct __declspec(dllexport) ExportedTemplate { + static S s; +}; +template <typename T> S ExportedTemplate<T>::s; +void useExportedTemplate(ExportedTemplate<int> x) { + (void)x.s; +} +int f(); +namespace selectany_init { +// MS don't put selectany static var in the linker directive, init routine +// f() is not getting called if x is not referenced. +int __declspec(selectany) x = f(); +} + +namespace explicit_template_instantiation { +template <typename T> struct A { static int x; }; +template <typename T> int A<T>::x = f(); +template struct A<int>; +} + +namespace implicit_template_instantiation { +template <typename T> struct A { static int x; }; +template <typename T> int A<T>::x = f(); +int g() { return A<int>::x; } +} + + +template <class T> +struct X_ { + static T ioo; + static T init(); +}; +template <class T> T X_<T>::ioo = X_<T>::init(); +template struct X_<int>; + +template <class T> +struct X { + static T ioo; + static T init(); +}; +// template specialized static data don't need in llvm.used, +// the static init routine get call from _GLOBAL__sub_I_ routines. +template <> int X<int>::ioo = X<int>::init(); +template struct X<int>; +// CHECK: @llvm.global_ctors = appending global [6 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @"??__Ex@selectany_init@@YAXXZ", i8* bitcast (i32* @"?x@selectany_init@@3HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@explicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?ioo@?$X_@H@@2HA@@YAXXZ", i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?s@?$ExportedTemplate@H@@2US@@A@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@implicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_template_static_init.cpp, i8* null }] +// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata" + Index: lib/CodeGen/CGDeclCXX.cpp =================================================================== --- lib/CodeGen/CGDeclCXX.cpp +++ lib/CodeGen/CGDeclCXX.cpp @@ -481,6 +481,12 @@ // minor startup time optimization. In the MS C++ ABI, there are no guard // variables, so this COMDAT key is required for correctness. AddGlobalCtor(Fn, 65535, COMDATKey); + if (getTarget().getCXXABI().isMicrosoft()) { + // In The MS C++, MS add template static data member in the linker + // drective. + assert(COMDATKey); + addUsedGlobal(COMDATKey); + } } else if (D->hasAttr<SelectAnyAttr>()) { // SelectAny globals will be comdat-folded. Put the initializer into a // COMDAT group associated with the global, so the initializers get folded
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits