From 367e618fd605353ad77bb78f884c758948f0d573 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Tue, 3 Jan 2023 14:37:56 +0800 Subject: [PATCH] [C++20] [Modules] Emit full specialization of variable template as available externally in importers Closes https://github.com/llvm/llvm-project/issues/59780. In this issue report, when we use full specialization of variable templates in modules, we will meet the multiple definition errors. The root cause of the problem is that when we see the full specialization of the variable template in the importers, we will find if it is already defined in the external sources and we failed to find such definitions from external sources. So we generate the definition in the current TU. We failed to find the definition in the external sources because we restricted to not write it during writing. However, we don't know why we restricted it and it doesn't make a lot sense to do such restriction. Then no test fails after we remove such limitations. So let's remove it now and add it back later if we found it is necessary then we can add the corresponding test that time. Note that the code is only applied to named modules and PCHWithObjectFiles. So it won't affect the normal clang modules and header units. --- clang/lib/Serialization/ASTWriterDecl.cpp | 3 +- clang/test/Modules/pr59780.cppm | 46 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 clang/test/Modules/pr59780.cppm diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 353a585..c117a29 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1037,8 +1037,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { if (D->getStorageDuration() == SD_Static) { bool ModulesCodegen = false; if (Writer.WritingModule && - !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && - !isa(D)) { + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo()) { // When building a C++20 module interface unit or a partition unit, a // strong definition in the module interface is provided by the // compilation of that unit, not by its users. (Inline variables are still diff --git a/clang/test/Modules/pr59780.cppm b/clang/test/Modules/pr59780.cppm new file mode 100644 index 0000000..9578325 --- /dev/null +++ b/clang/test/Modules/pr59780.cppm @@ -0,0 +1,46 @@ +// https://github.com/llvm/llvm-project/issues/59780 +// +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -triple %itanium_abi_triple -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t -S \ +// RUN: -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/use.cpp +// RUN: %clang_cc1 -std=c++20 %t/a.pcm -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/a.cppm + +//--- a.cppm +export module a; + +export template +int x = 0; + +export template<> +int x = 0; + +export template +struct Y { + static int value; +}; + +template +int Y::value = 0; + +export template<> +struct Y { + static int value; +}; + +int Y::value = 0; + +// CHECK-NOT: @_ZW1a1xIiE = {{.*}}available_externally{{.*}}global +// CHECK-NOT: @_ZNW1a1YIiE5valueE = {{.*}}available_externally{{.*}}global + +//--- use.cpp +import a; +int foo() { + return x + Y::value; +} + +// CHECK: @_ZW1a1xIiE = {{.*}}available_externally{{.*}}global +// CHECK: @_ZNW1a1YIiE5valueE = {{.*}}available_externally{{.*}}global -- 2.7.4