ChuanqiXu created this revision. ChuanqiXu added reviewers: rsmith, iains, urnathan, dblaikie. ChuanqiXu added a project: clang. ChuanqiXu requested review of this revision. Herald added a subscriber: cfe-commits.
This fixes issue51873 <https://github.com/llvm/llvm-project/issues/51873>. The issue reports that we couldn't run hello world example in C++20 module. Then I found that the reason is that libstdc++ uses static variable to initialize resources for streams like std::cout. And it would be good if we use libc++. So the key point here is that wether or not the definition of static variables should be remained in module interface. First I thought the reduction makes sense. Since static variable shouldn't be able to be referred outside the module. Then @rsmith pointed out that this one should be a bug. This patch tries to remain variable's definition in the module interface no matter what the kind it is. This violates ModuleTS. It wouldn't define inline variables in the module. But I think we don't need to keep compatibility for ModuleTS. It would be deprecated someday. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119409 Files: clang/lib/Serialization/ASTWriterDecl.cpp clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp clang/test/CodeGenCXX/static-variable-in-module.cpp Index: clang/test/CodeGenCXX/static-variable-in-module.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/static-variable-in-module.cpp @@ -0,0 +1,24 @@ +// RUN: rm -fr %t +// RUN: mkdir %t +// RUN: echo "struct S { S(); };" >> %t/foo.h +// RUN: echo "static S s = S();" >> %t/foo.h +// RUN: %clang -std=c++20 -I%t %s -S -emit-llvm -o - | FileCheck %s +module; +#include "foo.h" +export module m; +class A { +public: + A(); +}; +static A a = A(); + +// CHECK: @_ZL1s = internal global %struct.S zeroinitializer +// CHECK: @_ZW1mE1a = dso_local global %class.A zeroinitializer +// CHECK: @llvm.global_ctors = appending global{{.*}}@_GLOBAL__sub_I_static_variable_in_module.cpp +// CHECK: define {{.*}}__cxx_global_var_init[[SUFFIX:[^)]*]] +// CHECK: call void @_ZN1SC1Ev +// CHECK: define {{.*}}__cxx_global_var_init[[SUFFIX2:[^)]*]] +// CHECK: call void @_ZW1mEN1AC1Ev +// CHECK: define {{.*}}@_GLOBAL__sub_I_static_variable_in_module.cpp +// CHECK: call void @__cxx_global_var_init[[SUFFIX]] +// CHECK: call void @__cxx_global_var_init[[SUFFIX2]] Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @inline_var_exported = available_externally {{(dso_local )?}}global // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3 import Module; Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -2,11 +2,11 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @inline_var_exported = available_externally {{(dso_local )?}}global // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3, // // CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = available_externally {{(dso_local )?}}global // CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0, // CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3, Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -1022,15 +1022,17 @@ if (Writer.WritingModule && !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && !isa<VarTemplateSpecializationDecl>(D)) { - // When building a C++ Modules TS module interface unit, a strong - // definition in the module interface is provided by the compilation of - // that module interface unit, not by its users. (Inline variables are - // still emitted in module users.) + // [dcl.inline]p7: + // If an inline function or variable that is attached to a named module + // is declared in a definition domain, it shall be defined in that + // domain. + // + // So the variable would be defined in the module unit no matter it is inline. ModulesCodegen = - (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit || + Writer.WritingModule->Kind == Module::ModuleInterfaceUnit || (D->hasAttr<DLLExportAttr>() && - Writer.Context->getLangOpts().BuildingPCHWithObjectFile)) && - Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal; + Writer.Context->getLangOpts().BuildingPCHWithObjectFile && + Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); } Record.push_back(ModulesCodegen); if (ModulesCodegen)
Index: clang/test/CodeGenCXX/static-variable-in-module.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/static-variable-in-module.cpp @@ -0,0 +1,24 @@ +// RUN: rm -fr %t +// RUN: mkdir %t +// RUN: echo "struct S { S(); };" >> %t/foo.h +// RUN: echo "static S s = S();" >> %t/foo.h +// RUN: %clang -std=c++20 -I%t %s -S -emit-llvm -o - | FileCheck %s +module; +#include "foo.h" +export module m; +class A { +public: + A(); +}; +static A a = A(); + +// CHECK: @_ZL1s = internal global %struct.S zeroinitializer +// CHECK: @_ZW1mE1a = dso_local global %class.A zeroinitializer +// CHECK: @llvm.global_ctors = appending global{{.*}}@_GLOBAL__sub_I_static_variable_in_module.cpp +// CHECK: define {{.*}}__cxx_global_var_init[[SUFFIX:[^)]*]] +// CHECK: call void @_ZN1SC1Ev +// CHECK: define {{.*}}__cxx_global_var_init[[SUFFIX2:[^)]*]] +// CHECK: call void @_ZW1mEN1AC1Ev +// CHECK: define {{.*}}@_GLOBAL__sub_I_static_variable_in_module.cpp +// CHECK: call void @__cxx_global_var_init[[SUFFIX]] +// CHECK: call void @__cxx_global_var_init[[SUFFIX2]] Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @inline_var_exported = available_externally {{(dso_local )?}}global // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3 import Module; Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -2,11 +2,11 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @inline_var_exported = available_externally {{(dso_local )?}}global // CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3, // // CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = available_externally {{(dso_local )?}}global // CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0, // CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3, Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -1022,15 +1022,17 @@ if (Writer.WritingModule && !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && !isa<VarTemplateSpecializationDecl>(D)) { - // When building a C++ Modules TS module interface unit, a strong - // definition in the module interface is provided by the compilation of - // that module interface unit, not by its users. (Inline variables are - // still emitted in module users.) + // [dcl.inline]p7: + // If an inline function or variable that is attached to a named module + // is declared in a definition domain, it shall be defined in that + // domain. + // + // So the variable would be defined in the module unit no matter it is inline. ModulesCodegen = - (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit || + Writer.WritingModule->Kind == Module::ModuleInterfaceUnit || (D->hasAttr<DLLExportAttr>() && - Writer.Context->getLangOpts().BuildingPCHWithObjectFile)) && - Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal; + Writer.Context->getLangOpts().BuildingPCHWithObjectFile && + Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); } Record.push_back(ModulesCodegen); if (ModulesCodegen)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits