Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -331,6 +331,9 @@ `Issue 58800 `_ - Fix an issue that triggers a crash if we instantiate a hidden friend functions. This fixes `Issue 54457 `_ +- Fix issue that the standard C++ modules importee will call global + constructor/destructor for the global varaibles in the importing modules. + This fixes `Issue 59765 `_ Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -4824,7 +4824,13 @@ llvm::TrackingVH Init; bool NeedsGlobalCtor = false; + // Whether the definition of the variable is available externally. + // If yes, we shouldn't emit the GloablCtor and GlobalDtor for the variable + // since this is the job for its original source. + bool IsDefinitionAvailableExternally = + getContext().GetGVALinkageForVariable(D) == GVA_AvailableExternally; bool NeedsGlobalDtor = + !IsDefinitionAvailableExternally && D->needsDestruction(getContext()) == QualType::DK_cxx_destructor; const VarDecl *InitDecl; @@ -4878,7 +4884,9 @@ if (InitDecl->hasFlexibleArrayInit(getContext())) ErrorUnsupported(D, "flexible array initializer"); Init = EmitNullConstant(T); - NeedsGlobalCtor = true; + + if (!IsDefinitionAvailableExternally) + NeedsGlobalCtor = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); Index: clang/test/CodeGenCXX/pr59765-modules-global-ctor-dtor.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/pr59765-modules-global-ctor-dtor.cppm @@ -0,0 +1,58 @@ +// https://github.com/llvm/llvm-project/issues/59765 +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -triple %itanium_abi_triple -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/M.pcm -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/M.cppm +// RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fprebuilt-module-path=%t -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/Use.cpp +// +// Check that the behavior of header units is normal as headers. +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -xc++-user-header %t/foo.h -emit-header-unit -o %t/foo.pcm +// RUN: %clang_cc1 -std=c++20 %t/UseHU.cpp -fmodule-file=%t/foo.pcm -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/UseHU.cpp + +//--- M.cppm +export module M; +export class A { +public: + A(); + ~A(); + void use(); +}; +export A a; + +// CHECK: @_ZW1M1a = {{.*}}global %class.A zeroinitializer +// CHECK: define{{.*}}void @__cxx_global_var_init() +// CHECK-NEXT: entry: +// CHECK-NEXT: call{{.*}}void @_ZNW1M1AC1Ev({{.*}}@_ZW1M1a +// CHECK-NEXT: call{{.*}}i32 @__cxa_atexit(ptr @_ZNW1M1AD1Ev, ptr @_ZW1M1a + +//--- Use.cpp +import M; +void use() { + a.use(); +} + +// CHECK-NOT: @_ZNW1M1AC1Ev +// CHECK-NOT: @_ZNW1M1AD1Ev + +//--- foo.h +class A { +public: + A(); + ~A(); + void use(); +}; +A a; + +//--- UseHU.cpp +import "foo.h"; +void use() { + a.use(); +} + +// CHECK: @a = {{.*}}global %class.A zeroinitializer +// CHECK: define{{.*}}void @__cxx_global_var_init() +// CHECK-NEXT: entry: +// CHECK-NEXT: call{{.*}}void @_ZN1AC1Ev({{.*}}@a +// CHECK-NEXT: call{{.*}}i32 @__cxa_atexit(ptr @_ZN1AD1Ev, ptr @a