Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -329,6 +329,9 @@ - Fix sanity check when value initializing an empty union so that it takes into account anonymous structs which is a GNU extension. This fixes `Issue 58800 `_ +- 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 comes from external source. + // If yes, we shouldn't emit the GloablCtor and GlobalDtor for the variable + // since this is the job for its original source. + bool IsDefinitionFromExternalSource = + getContext().GetGVALinkageForVariable(D) == GVA_AvailableExternally; bool NeedsGlobalDtor = + !IsDefinitionFromExternalSource && 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 (!IsDefinitionFromExternalSource) + 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,33 @@ +// 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 + +//--- 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; +int use() { + a.use(); +} + +// CHECK-NOT: @_ZNW1M1AC1Ev +// CHECK-NOT: @_ZNW1M1AD1Ev