diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4665,6 +4665,7 @@ if (!hasVisibleDefinition(Old) && (New->getFormalLinkage() == InternalLinkage || New->isInline() || + isa(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 --- /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; +auto bar = zero; +auto baz = zero; + +template 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 = {0}; // expected-error-re {{declaration{{.*}}in the global module follows declaration in module var_def}} + // expected-note@* {{previous}} +template constexpr T* zero = nullptr; // expected-error-re {{declaration{{.*}}in the global module follows declaration in module var_def}} + // expected-note@* {{previous}} + +template <> constexpr int** zero = nullptr; // ok, new specialization. +template constexpr T** zero = nullptr; // ok, new partial specilization. + +//--- var_def.cppm +export module var_def; + +export template constexpr T zero = 0; +export struct Int { + int value; +}; +export template <> constexpr Int zero = {0}; +export template constexpr T* zero = 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 --- /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; +auto bar = zero; +auto baz = zero; + +template constexpr T zero = 0; // expected-error {{redefinition}} expected-note@* {{previous}} +template <> constexpr Int zero = {0}; // expected-error {{redefinition}} expected-note@* {{previous}} +template constexpr T* zero = nullptr; // expected-error {{redefinition}} expected-note@* {{previous}} + +template <> constexpr int** zero = nullptr; // ok, new specialization. +template constexpr T** zero = 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 constexpr T zero = 0; +struct Int { + int value; +}; +template <> constexpr int zero = {0}; +template constexpr T* zero = nullptr; + +#endif // VAR1_H + +//--- var2.h +#ifndef VAR2_H +#define VAR2_H + +template constexpr T zero = 0; +struct Int { + int value; +}; +template <> constexpr int zero = {0}; +template constexpr T* zero = nullptr; + +#endif // VAR2_H