From 08f957808e5f7e44b11d5e9015925955fe1e9d32 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Mon, 9 Jan 2023 10:43:35 +0800 Subject: [PATCH] [C++20] [Modules] Don't generate global ctors/dtors for variables which are available externally Closes https://github.com/llvm/llvm-project/issues/59765. Currently we will generate the global ctor/dtor for variables in importing modules. It will cause multiple initialization/destructions. It makes no sense. This patch tries to not generate global ctor/dtor for variables which are available externally. Note that the variables in header units and clang modules won't be available externally by default. Reviewed By: iains Differential Revision: https://reviews.llvm.org/D140867 --- clang/docs/ReleaseNotes.rst | 3 ++ clang/lib/CodeGen/CodeGenModule.cpp | 10 +++- .../pr59765-modules-global-ctor-dtor.cppm | 58 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/pr59765-modules-global-ctor-dtor.cppm diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b623d26..8718dea 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -345,6 +345,9 @@ Bug Fixes `Issue 59792 `_ - Fix an issue that makes Clang crash on lambda template parameters. This fixes `Issue 57960 `_ +- Fix issue that the standard C++ modules importer will call global + constructor/destructor for the global varaibles in the importing modules. + This fixes `Issue 59765 `_ Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index fbf7c33..1239147 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4824,7 +4824,13 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, 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 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, 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)); diff --git a/clang/test/CodeGenCXX/pr59765-modules-global-ctor-dtor.cppm b/clang/test/CodeGenCXX/pr59765-modules-global-ctor-dtor.cppm new file mode 100644 index 0000000..c89bce5 --- /dev/null +++ b/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 -- 2.7.4