Author: Chuanqi Xu
Date: 2026-08-24T10:10:44Z
New Revision: a37533905af2449ff84ee160d85647c506b8ae99

URL: 
https://github.com/llvm/llvm-project/commit/a37533905af2449ff84ee160d85647c506b8ae99
DIFF: 
https://github.com/llvm/llvm-project/commit/a37533905af2449ff84ee160d85647c506b8ae99.diff

LOG: [C++20] [Modules] Do not generate call to module initialization for const 
init (#218346)

Close https://github.com/llvm/llvm-project/issues/218305

Added: 
    clang/test/CodeGenCXX/module-initializer-elision.cpp

Modified: 
    clang/lib/Sema/Sema.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index f1e328ccba426..21f71d7f8b40e 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1415,8 +1415,18 @@ void Sema::ActOnEndOfTranslationUnit() {
   if (Module *CurrentModule = getCurrentModule();
       CurrentModule && CurrentModule->isInterfaceOrPartition()) {
     auto DoesModNeedInit = [this](Module *M) {
-      if (!getASTContext().getModuleInitializers(M).empty())
-        return true;
+      for (Decl *D : getASTContext().getModuleInitializers(M)) {
+        auto *VD = dyn_cast<VarDecl>(D);
+        // TLS initialization is not handled by the TU's global initializer.
+        if (!VD || VD->getTLSKind() != VarDecl::TLS_None)
+          continue;
+
+        if (const VarDecl *InitDecl = VD->getInitializingDeclaration();
+            (InitDecl && !InitDecl->hasConstantInitialization()) ||
+            VD->needsDestruction(getASTContext()) ==
+                QualType::DK_cxx_destructor)
+          return true;
+      }
       for (auto [Exported, _] : M->Exports)
         if (Exported->isNamedModuleInterfaceHasInit())
           return true;

diff  --git a/clang/test/CodeGenCXX/module-initializer-elision.cpp 
b/clang/test/CodeGenCXX/module-initializer-elision.cpp
new file mode 100644
index 0000000000000..4ad56df802546
--- /dev/null
+++ b/clang/test/CodeGenCXX/module-initializer-elision.cpp
@@ -0,0 +1,94 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 NoInit.cpp \
+// RUN:   -emit-module-interface -o NoInit.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 NoInit.pcm \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefix=NO-INIT-MODULE
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseNoInit.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=NO-INIT
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 HasDtor.cpp \
+// RUN:   -emit-module-interface -o HasDtor.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseHasDtor.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=HAS-DTOR
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 HasDynamic.cpp \
+// RUN:   -emit-module-interface -o HasDynamic.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseHasDynamic.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=HAS-DYNAMIC
+
+// Test again for reduced BMI
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 NoInit.cpp \
+// RUN:   -emit-reduced-module-interface -o NoInit.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 NoInit.pcm \
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefix=NO-INIT-MODULE
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseNoInit.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=NO-INIT
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 HasDtor.cpp \
+// RUN:   -emit-reduced-module-interface -o HasDtor.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseHasDtor.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=HAS-DTOR
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 HasDynamic.cpp \
+// RUN:   -emit-reduced-module-interface -o HasDynamic.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 UseHasDynamic.cpp \
+// RUN:   -fprebuilt-module-path=%t -emit-llvm -o - | \
+// RUN:   FileCheck %s --check-prefix=HAS-DYNAMIC
+
+//--- NoInit.cpp
+export module NoInit;
+
+// Neither constant initialization nor dynamic TLS initialization contributes
+// to the module initializer.
+int a = 43;
+int f();
+thread_local int tls = f();
+
+// NO-INIT-MODULE-LABEL: define void @_ZGIW6NoInit()
+// NO-INIT-MODULE: entry:
+// NO-INIT-MODULE-NEXT: ret void
+
+//--- UseNoInit.cpp
+import NoInit;
+
+// NO-INIT: source_filename = {{.*}}UseNoInit.cpp
+// NO-INIT-NOT: @_ZGIW6NoInit
+// NO-INIT-NOT: @llvm.global_ctors
+
+//--- HasDtor.cpp
+export module HasDtor;
+
+// Constant initialization still needs a module initializer when it registers a
+// destructor.
+struct S {
+  constexpr S() = default;
+  ~S() {}
+};
+constinit S s;
+
+//--- UseHasDtor.cpp
+import HasDtor;
+
+// HAS-DTOR: define internal void @_GLOBAL__sub_I_UseHasDtor.cpp()
+// HAS-DTOR: call void @_ZGIW7HasDtor()
+
+//--- HasDynamic.cpp
+export module HasDynamic;
+
+// Dynamic initialization contributes to the module initializer.
+int f();
+int n = f();
+
+//--- UseHasDynamic.cpp
+import HasDynamic;
+
+// HAS-DYNAMIC: define internal void @_GLOBAL__sub_I_UseHasDynamic.cpp()
+// HAS-DYNAMIC: call void @_ZGIW10HasDynamic()


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to