Index: clang/include/clang/Basic/Module.h =================================================================== --- clang/include/clang/Basic/Module.h +++ clang/include/clang/Basic/Module.h @@ -534,13 +534,13 @@ return Kind == ModuleInterfaceUnit || isModulePartition(); } + static StringRef getPrimaryModuleInterfaceName(StringRef Name) { + return Name.split(':').first; + } + /// Get the primary module interface name from a partition. StringRef getPrimaryModuleInterfaceName() const { - if (isModulePartition()) { - auto pos = Name.find(':'); - return StringRef(Name.data(), pos); - } - return Name; + return getPrimaryModuleInterfaceName(getTopLevelModuleName()); } /// Retrieve the full name of this module, including the path from Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -1561,12 +1561,11 @@ static bool isInCurrentModule(const Module *M, const LangOptions &LangOpts) { // If M is the global module fragment of a module that we've not yet finished // parsing, then it must be part of the current module. - // If it's a partition, then it must be visible to an importer (since only - // another partition or the named module can import it). - return M->getTopLevelModuleName() == LangOpts.CurrentModule || - (M->Kind == Module::GlobalModuleFragment && !M->Parent) || - M->Kind == Module::ModulePartitionInterface || - M->Kind == Module::ModulePartitionImplementation; + if (M->isGlobalModule() && !M->Parent) + return true; + + return M->getPrimaryModuleInterfaceName() == + Module::getPrimaryModuleInterfaceName(LangOpts.CurrentModule); } bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { Index: clang/test/CXX/module/module.import/p2.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.import/p2.cpp @@ -0,0 +1,21 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -std=c++20 %t/impl.cppm -emit-module-interface -o %t/M-impl.pcm +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fprebuilt-module-path=%t -verify -fsyntax-only + +//--- impl.cppm +module M : impl; +class A {}; + +//--- M.cppm +export module M; +import : impl; +export A f(); + +//--- Use.cpp +import M; +void test() { + A a; // expected-error {{unknown type name 'A'}} +} Index: clang/test/Modules/cxx20-10-1-ex2.cpp =================================================================== --- clang/test/Modules/cxx20-10-1-ex2.cpp +++ clang/test/Modules/cxx20-10-1-ex2.cpp @@ -56,7 +56,14 @@ int &c = n; // expected-error {{use of undeclared identifier}} //--- std10-1-ex2-tu7.cpp +// expected-no-diagnostics module B:X3; // does not implicitly import B -import :X2; // X2 is an implementation so exports nothing. - // error: n not visible here. -int &c = n; // expected-error {{use of undeclared identifier }} +import : X2; // X2 is an implementation unit import B. +// According to [module.import]p7: +// Additionally, when a module-import-declaration in a module unit of some +// module M imports another module unit U of M, it also imports all +// translation units imported by non-exported module-import-declarations in +// the module unit purview of U. +// +// So B is imported in B:X3 due to B:X2 imported B. So n is visible here. +int &c = n;