// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NO-NS,CHECK-IMPORT-NO-NS --implicit-check-not=unused // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NS,CHECK-IMPORT-NS --implicit-check-not=unused // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused // Check that we behave sensibly when importing a header containing strong and // weak, ordered and unordered global initializers. // // Our behavior is as follows: // // -- for variables with one or more specific points of initialization // (non-template variables, whether or not they are inline or thread_local), // emit them if (and only if) a header containing a point of initialization // is transitively #included / imported. // // -- for variables with unordered initialization (any kind of templated // variable -- excluding explicit specializations), emit them if any part // of any module that triggers an instantiation is imported. // // The intent is to: // // 1) preserve order of initialization guarantees // 2) preserve the behavior of globals with ctors in headers, and specifically // of std::ios_base::Init (do not run the iostreams initializer nor force // linking in the iostreams portion of the static library unless // is included) // 3) behave conservatively-correctly with regard to unordered initializers: we // might run them in cases where a traditional compilation would not, but // will never fail to run them in cases where a traditional compilation // would do so // // Perfect handling of unordered initializers would require tracking all // submodules containing points of instantiation, which is very hard when those // points of instantiation are within definitions that we skip because we // already have a (non-visible) definition for the entity: // // // a.h // template int v = f(); // inline int get() { return v; } // // // b.h // template int v = f(); // inline int get() { return v; } // // If a.h and b.h are built as a module, we will only have a point of // instantiation for v in one of the two headers, because we will only // parse one of the two get() functions. #pragma clang module build m module m { module a { header "foo.h" { size 123 mtime 456789 } } module b {} } #pragma clang module contents #pragma clang module begin m.a inline int non_trivial() { return 3; } #ifdef NS namespace ns { #endif int a = non_trivial(); inline int b = non_trivial(); thread_local int c = non_trivial(); inline thread_local int d = non_trivial(); template int e = non_trivial(); template inline int f = non_trivial(); template thread_local int g = non_trivial(); template inline thread_local int h = non_trivial(); inline int unused = 123; // should not be emitted template struct X { static int a; static inline int b = non_trivial(); static thread_local int c; static inline thread_local int d = non_trivial(); template static int e; template static inline int f = non_trivial(); template static thread_local int g; template static inline thread_local int h = non_trivial(); static inline int unused = 123; // should not be emitted }; template int X::a = non_trivial(); template thread_local int X::c = non_trivial(); template template int X::e = non_trivial(); template template thread_local int X::g = non_trivial(); inline void use(bool b, ...) { if (b) return; use(true, e, f, g, h, X::a, X::b, X::c, X::d, X::e, X::f, X::g, X::h); } #ifdef NS } #endif #pragma clang module end #pragma clang module endbuild #if IMPORT == 1 // Import the module and the m.a submodule; runs the ordered initializers and // the unordered initializers. #pragma clang module import m.a #elif IMPORT == 2 // Import the module but not the m.a submodule; runs only the unordered // initializers. #pragma clang module import m.b #else // Load the module but do not import any submodules; runs only the unordered // initializers. FIXME: Should this skip all of them? #pragma clang module load m #endif // CHECK-IMPORT-NO-NS-DAG: @[[A:a]] ={{.*}} global i32 0, align 4 // CHECK-IMPORT-NO-NS-DAG: @[[B:b]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-IMPORT-NO-NS-DAG: @[[C:c]] ={{.*}} thread_local global i32 0, align 4 // CHECK-IMPORT-NO-NS-DAG: @[[D:d]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-NO-NS-DAG: @[[E:_Z1eIiE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-NO-NS-DAG: @[[F:_Z1fIiE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-NO-NS-DAG: @[[G:_Z1gIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-NO-NS-DAG: @[[H:_Z1hIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-IMPORT-NS-DAG: @[[A:_ZN2ns1aE]] ={{.*}} global i32 0, align 4 // CHECK-IMPORT-NS-DAG: @[[B:_ZN2ns1bE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-IMPORT-NS-DAG: @[[BG:_ZGVN2ns1bE]] = linkonce_odr global i64 0, comdat($[[B]]), align 8 // CHECK-IMPORT-NS-DAG: @[[C:_ZN2ns1cE]] ={{.*}} thread_local global i32 0, align 4 // CHECK-IMPORT-NS-DAG: @[[D:_ZN2ns1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-IMPORT-NS-DAG: @[[DG:_ZGVN2ns1dE]] = linkonce_odr thread_local global i64 0, comdat($[[D]]), align 8 // CHECK-NS-DAG: @[[E:_ZN2ns1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-NS-DAG: @[[F:_ZN2ns1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-NS-DAG: @[[G:_ZN2ns1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-NS-DAG: @[[H:_ZN2ns1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-DAG: @[[XA:_ZN(2ns)?1XIiE1aE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-DAG: @[[XB:_ZN(2ns)?1XIiE1bE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-DAG: @[[XC:_ZN(2ns)?1XIiE1cE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-DAG: @[[XD:_ZN(2ns)?1XIiE1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-DAG: @[[XE:_ZN(2ns)?1XIiE1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-DAG: @[[XF:_ZN(2ns)?1XIiE1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 // CHECK-DAG: @[[XG:_ZN(2ns)?1XIiE1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // CHECK-DAG: @[[XH:_ZN(2ns)?1XIiE1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 // It's OK if the order of the first 6 of these changes. // CHECK: @llvm.global_ctors = appending global // CHECK-SAME: @[[E_INIT:[^,]*]], {{[^@]*}} @[[E]] // CHECK-SAME: @[[F_INIT:[^,]*]], {{[^@]*}} @[[F]] // CHECK-SAME: @[[XA_INIT:[^,]*]], {{[^@]*}} @[[XA]] // CHECK-SAME: @[[XE_INIT:[^,]*]], {{[^@]*}} @[[XE]] // CHECK-SAME: @[[XF_INIT:[^,]*]], {{[^@]*}} @[[XF]] // CHECK-SAME: @[[XB_INIT:[^,]*]], {{[^@]*}} @[[XB]] // CHECK-IMPORT-SAME: @[[TU_INIT:[^,]*]], i8* null }] // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[E_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[E]], // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[F_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[F]], // CHECK: define {{.*}} @[[G_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[G]], // CHECK: define {{.*}} @[[H_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[H]], // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[XA_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XA]], // CHECK: define {{.*}} @[[XC_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XC]], // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[XE_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XE]], // CHECK: define {{.*}} @[[XG_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XG]], // CHECK: define {{.*}} @[[XH_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XH]], // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[XF_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XF]], // CHECK: define {{.*}} @[[XD_INIT:__cxx_global.*]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XD]], // FIXME: Should this use __cxa_guard_acquire? // CHECK: define {{.*}} @[[XB_INIT]]() // CHECK: load {{.*}} (i64* @_ZGV // CHECK: store {{.*}}, i32* @[[XB]], // CHECK-IMPORT: define {{.*}} @[[A_INIT:__cxx_global.*]]() // CHECK-IMPORT: call i32 @_Z11non_trivialv( // CHECK-IMPORT: store {{.*}}, i32* @[[A]], // CHECK-IMPORT: define {{.*}} @[[B_INIT:__cxx_global.*]]() // CHECK-IMPORT: call i32 @__cxa_guard_acquire(i64* @_ZGV // CHECK-IMPORT: store {{.*}}, i32* @[[B]], // CHECK-IMPORT: define {{.*}} @[[C_INIT:__cxx_global.*]]() // CHECK-IMPORT: call i32 @_Z11non_trivialv( // CHECK-IMPORT: store {{.*}}, i32* @[[C]], // CHECK-IMPORT: define {{.*}} @[[D_INIT:__cxx_global.*]]() // CHECK-IMPORT: load {{.*}} (i64* @_ZGV // CHECK-IMPORT: store {{.*}}, i32* @[[D]], // CHECK-IMPORT: define {{.*}} @[[TU_INIT]]() // CHECK-IMPORT: call void @[[A_INIT]]() // CHECK-IMPORT: define {{.*}} @__tls_init() // CHECK-IMPORT: call void @[[C_INIT]]() // CHECK-IMPORT: call void @[[D_INIT]]()