Skip to content

Commit 1d1f9af

Browse files
committed
[C++20] [Modules] Treat directly imported internal partition unit as reachable
Close #143788 See the discussion for details.
1 parent 2a27c05 commit 1d1f9af

File tree

3 files changed

+53
-11
lines changed

3 files changed

+53
-11
lines changed

clang/lib/Sema/SemaLookup.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,8 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
19781978
if (D->isModulePrivate())
19791979
return false;
19801980

1981+
Module *DeclTopModule = DeclModule->getTopLevelModule();
1982+
19811983
// [module.reach]/p1
19821984
// A translation unit U is necessarily reachable from a point P if U is a
19831985
// module interface unit on which the translation unit containing P has an
@@ -1996,17 +1998,28 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
19961998
//
19971999
// Here we only check for the first condition. Since we couldn't see
19982000
// DeclModule if it isn't (transitively) imported.
1999-
if (DeclModule->getTopLevelModule()->isModuleInterfaceUnit())
2001+
if (DeclTopModule->isModuleInterfaceUnit())
20002002
return true;
20012003

2002-
// [module.reach]/p2
2004+
// [module.reach]/p1,2
2005+
// A translation unit U is necessarily reachable from a point P if U is a
2006+
// module interface unit on which the translation unit containing P has an
2007+
// interface dependency, or the translation unit containing P imports U, in
2008+
// either case prior to P
2009+
//
20032010
// Additional translation units on
20042011
// which the point within the program has an interface dependency may be
20052012
// considered reachable, but it is unspecified which are and under what
20062013
// circumstances.
2007-
//
2008-
// The decision here is to treat all additional tranditional units as
2009-
// unreachable.
2014+
Module *CurrentM = SemaRef.getCurrentModule();
2015+
2016+
// Directly imported module are necessarily reachable.
2017+
// Since we can't export import a module implementation partition unit, we
2018+
// don't need to count for Exports here.
2019+
if (CurrentM && CurrentM->getTopLevelModule()->Imports.count(DeclTopModule))
2020+
return true;
2021+
2022+
// Then we treat all module implementation partition unit as unreachable.
20102023
return false;
20112024
}
20122025

clang/lib/Sema/SemaModule.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -712,19 +712,20 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
712712
Mod->Kind == Module::ModuleKind::ModulePartitionImplementation) {
713713
Diag(ExportLoc, diag::err_export_partition_impl)
714714
<< SourceRange(ExportLoc, Path.back().getLoc());
715-
} else if (!ModuleScopes.empty() && !currentModuleIsImplementation()) {
715+
} else if (ExportLoc.isValid() &&
716+
(ModuleScopes.empty() || currentModuleIsImplementation())) {
717+
// [module.interface]p1:
718+
// An export-declaration shall inhabit a namespace scope and appear in the
719+
// purview of a module interface unit.
720+
Diag(ExportLoc, diag::err_export_not_in_module_interface);
721+
} else if (!ModuleScopes.empty()) {
716722
// Re-export the module if the imported module is exported.
717723
// Note that we don't need to add re-exported module to Imports field
718724
// since `Exports` implies the module is imported already.
719725
if (ExportLoc.isValid() || getEnclosingExportDecl(Import))
720726
getCurrentModule()->Exports.emplace_back(Mod, false);
721727
else
722728
getCurrentModule()->Imports.insert(Mod);
723-
} else if (ExportLoc.isValid()) {
724-
// [module.interface]p1:
725-
// An export-declaration shall inhabit a namespace scope and appear in the
726-
// purview of a module interface unit.
727-
Diag(ExportLoc, diag::err_export_not_in_module_interface);
728729
}
729730

730731
return Import;

clang/test/Modules/pr143788.cppm

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/P.cppm -emit-module-interface -o %t/P.pcm
7+
// RUN: %clang_cc1 -std=c++20 %t/I.cpp -fmodule-file=M:P=%t/P.pcm -fmodule-file=M=%t/M.pcm -fsyntax-only -verify
8+
9+
//--- H.hpp
10+
struct S{};
11+
12+
//--- M.cppm
13+
export module M;
14+
15+
16+
//--- P.cppm
17+
module;
18+
#include "H.hpp"
19+
module M:P;
20+
21+
using T = S;
22+
23+
//--- I.cpp
24+
// expected-no-diagnostics
25+
module M;
26+
import :P;
27+
28+
T f() { return {}; }

0 commit comments

Comments
 (0)