Author: Ilya Biryukov Date: 2022-08-09T12:17:41+02:00 New Revision: 07529996d92b9fc0cc760f4e98d88b607f66e747
URL: https://github.com/llvm/llvm-project/commit/07529996d92b9fc0cc760f4e98d88b607f66e747 DIFF: https://github.com/llvm/llvm-project/commit/07529996d92b9fc0cc760f4e98d88b607f66e747.diff LOG: [Sema] Merge variable template specializations Clang used to produce redefinition errors, see tests for examples. Reviewed By: ChuanqiXu Differential Revision: https://reviews.llvm.org/D131258 Added: clang/test/Modules/merge-var-template-spec-cxx-modules.cppm clang/test/Modules/merge-var-template-spec.cpp Modified: clang/lib/Sema/SemaDecl.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04f01dd0de64d..605e4bf0abaeb 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4739,6 +4739,7 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { if (!hasVisibleDefinition(Old) && (New->getFormalLinkage() == InternalLinkage || New->isInline() || + isa<VarTemplateSpecializationDecl>(New) || New->getDescribedVarTemplate() || New->getNumTemplateParameterLists() || New->getDeclContext()->isDependentContext())) { diff --git a/clang/test/Modules/merge-var-template-spec-cxx-modules.cppm b/clang/test/Modules/merge-var-template-spec-cxx-modules.cppm new file mode 100644 index 0000000000000..a451bfe7804d3 --- /dev/null +++ b/clang/test/Modules/merge-var-template-spec-cxx-modules.cppm @@ -0,0 +1,44 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/var_def.cppm -o %t/var_def.pcm +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/reexport1.cppm -o %t/reexport1.pcm +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/reexport2.cppm -o %t/reexport2.pcm +// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/use.cppm -fsyntax-only -verify + +//--- use.cppm +import reexport1; +import reexport2; + +auto foo = zero<Int>; +auto bar = zero<int*>; +auto baz = zero<int>; + +template <class T> constexpr T zero = 0; // expected-error-re {{declaration{{.*}}in the global module follows declaration in module var_def}} + // expected-note@* {{previous}} +template <> constexpr Int zero<Int> = {0}; // expected-error-re {{declaration{{.*}}in the global module follows declaration in module var_def}} + // expected-note@* {{previous}} +template <class T> constexpr T* zero<T*> = nullptr; // expected-error-re {{declaration{{.*}}in the global module follows declaration in module var_def}} + // expected-note@* {{previous}} + +template <> constexpr int** zero<int**> = nullptr; // ok, new specialization. +template <class T> constexpr T** zero<T**> = nullptr; // ok, new partial specilization. + +//--- var_def.cppm +export module var_def; + +export template <class T> constexpr T zero = 0; +export struct Int { + int value; +}; +export template <> constexpr Int zero<Int> = {0}; +export template <class T> constexpr T* zero<T*> = nullptr; + +//--- reexport1.cppm +export module reexport1; +export import var_def; + +//--- reexport2.cppm +export module reexport2; +export import var_def; diff --git a/clang/test/Modules/merge-var-template-spec.cpp b/clang/test/Modules/merge-var-template-spec.cpp new file mode 100644 index 0000000000000..01448f34e6338 --- /dev/null +++ b/clang/test/Modules/merge-var-template-spec.cpp @@ -0,0 +1,70 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// We need '-fmodules-local-submodule-visibility' to properly test merging when building a module from multiple +// headers inside the same TU. C++20 mode would imply this flag, but we need it to set it explicitly for C++14. +// +// RUN: %clang_cc1 -xc++ -std=c++14 -fmodules -fmodules-local-submodule-visibility -fmodule-name=library \ +// RUN: -emit-module %t/modules.map \ +// RUN: -o %t/module.pcm +// +// +// RUN: %clang_cc1 -xc++ -std=c++14 -fmodules -fmodules-local-submodule-visibility -fmodule-file=%t/module.pcm \ +// RUN: -fmodule-map-file=%t/modules.map \ +// RUN: -fsyntax-only -verify %t/use.cpp +// +//--- use.cpp + +#include "var1.h" +#include "var2.h" + +auto foo = zero<Int>; +auto bar = zero<int*>; +auto baz = zero<int>; + +template <class T> constexpr T zero = 0; // expected-error {{redefinition}} expected-note@* {{previous}} +template <> constexpr Int zero<Int> = {0}; // expected-error {{redefinition}} expected-note@* {{previous}} +template <class T> constexpr T* zero<T*> = nullptr; // expected-error {{redefinition}} expected-note@* {{previous}} + +template <> constexpr int** zero<int**> = nullptr; // ok, new specialization. +template <class T> constexpr T** zero<T**> = nullptr; // ok, new partial specilization. + +//--- modules.map +module "library" { + export * + module "var1" { + export * + header "var1.h" + } + module "var2" { + export * + header "var2.h" + } +} + +//--- var1.h +#ifndef VAR1_H +#define VAR1_H + +template <class T> constexpr T zero = 0; +struct Int { + int value; +}; +template <> constexpr int zero<Int> = {0}; +template <class T> constexpr T* zero<T*> = nullptr; + +#endif // VAR1_H + +//--- var2.h +#ifndef VAR2_H +#define VAR2_H + +template <class T> constexpr T zero = 0; +struct Int { + int value; +}; +template <> constexpr int zero<Int> = {0}; +template <class T> constexpr T* zero<T*> = nullptr; + +#endif // VAR2_H _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits