jyu2 created this revision. jyu2 added reviewers: rnk, majnemer, erichkeane, cfe-commits. Herald added a project: clang.
MS only run time problem with inline static data member. A inline static data member’s init function gets called multiple time. To fix this, using template static data members initialization method instead. So that inline static data member initialize function can be put into COMDAT group with global being initialized. And also put static data member in the linker directive. So that the function can be called before main, even the that variable is not been referenced. The bug is report in: https://bugs.llvm.org/show_bug.cgi?id=37903 Repository: rC Clang https://reviews.llvm.org/D60912 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,86 @@ +// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -std=c++17 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-win32 -fms-extensions -std=c++17 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=i686-pc-windows-msvc -fms-extensions -std=c++17 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -std=c++17 -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>; +class a { +public: + a(); +}; +// For the static var inside unnamed namespace, the object is local to TU. +// No need to put static var in the linker directive. +// The static init routine is called before main. +namespace { +template <int> class aj { +public: + static a al; +}; +template <int am> a aj<am>::al; +class b : aj<3> { + void c(); +}; +void b::c() { al; } +} + +// C++17, inline static data member also need to use +struct A +{ + A(); + ~A(); +}; + +struct S1 +{ + inline static A aoo; // C++17 inline variable, thus also a definition +}; + +// CHECK: @llvm.used = appending global [5 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.A, %struct.A* @"?aoo@S1@@2UA@@A", i32 0, i32 0), 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 @@ -467,7 +467,10 @@ } else if (auto *IPA = D->getAttr<InitPriorityAttr>()) { OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); - } else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) { + } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || + (getTarget().getCXXABI().isMicrosoft() && + D->isInlineSpecified() && D->isStaticDataMember() && + getLangOpts().CPlusPlus17)) { // C++ [basic.start.init]p2: // Definitions of explicitly specialized class template static data // members have ordered initialization. Other class template static data @@ -481,6 +484,11 @@ // 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() && COMDATKey) { + // In The MS C++, MS add template static data member in the linker + // drective. + 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