}
}
+// [basic.link]/p10:
+// If two declarations of an entity are attached to different modules,
+// the program is ill-formed;
+static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
+ Decl *Previous) {
+ Module *M = Previous->getOwningModule();
+
+ // We only care about the case in named modules.
+ if (!M || !M->isNamedModule())
+ return;
+
+ // If it is previous implcitly introduced, it is not meaningful to
+ // diagnose it.
+ if (Previous->isImplicit())
+ return;
+
+ // FIXME: Get rid of the enumeration of decl types once we have an appropriate
+ // abstract for decls of an entity. e.g., the namespace decl and using decl
+ // doesn't introduce an entity.
+ if (!isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous))
+ return;
+
+ // Skip implicit instantiations since it may give false positive diagnostic
+ // messages.
+ // FIXME: Maybe this shows the implicit instantiations may have incorrect
+ // module owner ships. But given we've finished the compilation of a module,
+ // how can we add new entities to that module?
+ if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Previous);
+ VTSD && !VTSD->isExplicitSpecialization())
+ return;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Previous);
+ CTSD && !CTSD->isExplicitSpecialization())
+ return;
+ if (auto *Func = dyn_cast<FunctionDecl>(Previous))
+ if (auto *FTSI = Func->getTemplateSpecializationInfo();
+ FTSI && !FTSI->isExplicitSpecialization())
+ return;
+
+ // It is fine if they are in the same module.
+ if (Reader.getContext().isInSameModule(M, D->getOwningModule()))
+ return;
+
+ Reader.Diag(Previous->getLocation(),
+ diag::err_multiple_decl_in_different_modules)
+ << cast<NamedDecl>(Previous) << M->Name;
+ Reader.Diag(D->getLocation(), diag::note_also_found);
+}
+
void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
Decl *Previous, Decl *Canon) {
assert(D && Previous);
#include "clang/AST/DeclNodes.inc"
}
- // [basic.link]/p10:
- // If two declarations of an entity are attached to different modules,
- // the program is ill-formed;
- //
- // FIXME: Get rid of the enumeration of decl types once we have an appropriate
- // abstract for decls of an entity. e.g., the namespace decl and using decl
- // doesn't introduce an entity.
- if (Module *M = Previous->getOwningModule();
- M && M->isNamedModule() &&
- isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous) &&
- !Reader.getContext().isInSameModule(M, D->getOwningModule())) {
- Reader.Diag(Previous->getLocation(),
- diag::err_multiple_decl_in_different_modules)
- << cast<NamedDecl>(Previous) << M->Name;
- Reader.Diag(D->getLocation(), diag::note_also_found);
- }
+ checkMultipleDefinitionInNamedModules(Reader, D, Previous);
// If the declaration was visible in one module, a redeclaration of it in
// another module remains visible even if it wouldn't be visible by itself.
--- /dev/null
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
+// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
+// RUN: -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
+// RUN: -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \
+// RUN: -fprebuilt-module-path=%t
+
+//--- a.cppm
+export module a;
+
+export template<typename>
+struct a;
+
+template<typename>
+struct a {
+};
+
+export template<typename T>
+constexpr auto aa = a<T>();
+
+//--- b.cppm
+export module b;
+
+import a;
+
+static void b() {
+ static_cast<void>(a<void>());
+}
+
+//--- c.cppm
+export module c;
+
+import a;
+
+static void c() {
+ static_cast<void>(aa<void>);
+}
+
+//--- d.cpp
+// expected-no-diagnostics
+import a;
+import b;
+import c;
+
+static void d() {
+ static_cast<void>(a<void>());
+}
--- /dev/null
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
+// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
+// RUN: -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
+// RUN: -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \
+// RUN: -fprebuilt-module-path=%t
+
+//--- a.cppm
+export module a;
+
+template<typename>
+constexpr auto impl = true;
+
+export template<typename T>
+void a() {
+}
+
+export template<typename T> requires impl<T>
+void a() {
+}
+
+//--- b.cppm
+export module b;
+
+import a;
+
+static void b() {
+ a<void>();
+}
+
+//--- c.cppm
+export module c;
+
+import a;
+
+static void c() {
+ a<void>();
+}
+
+//--- d.cpp
+// expected-no-diagnostics
+import a;
+import b;
+import c;
+
+static void d() {
+ a<void>();
+}