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

Reply via email to