Consider this example
// translation C
export module M:C;
// translation U
export module M:B;
import :C;
// translation unit T
export module M;
export import :B; // #1 imports `M:B` and `M:C`
[module.unit] says
All module partitions of a module that are module interface units shall be directly or indirectly exported by the primary module interface unit ([module.import]). No diagnostic is required for a violation of these rules.
[module.import] p7 says
When a module-import-declaration imports a translation unit T, it also imports all translation units imported by exported module-import-declarations in T; such translation units are said to be exported by T. 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. These rules can in turn lead to the importation of yet more translation units.
The first part says T
exports the translation units if an exported module-import-declaration in T
imports them.
Since there is a non-exported module-import-declaration import :C;
in U
, and the module-import-declaration at #1
in the primary module unit of M
imports another module unit U
of M
, therefore the module-import-declaration at #1
also imports C
, according to the part after "Additionally".
Again, since the module-import-declaration at #1
in T
is exported, it directly imports M:B
and indirectly imports M:C
, therefore M:B
and M:C
are exported by T
.
So, all partition module interface units are exported by the primary module interface unit. However, when compiling the example with GCC: g++ -std=c++20 -fmodules-ts c.cpp u.cpp t.cpp
, it reports the error:
interface partition is not exported
Is it a bug of GCC or the partition C
is indeed not exported by T
and the rule is not clear here?
Update:
// file c
export module C;
export int fun(){return 0;}
// file b
export module M:B;
import C;
// file a
export module M;
export import :B; // #1
int d = fun(); // #2
// file main
import M;
int main(){}
#2
in this example is well-formed. The reason is the exported module-import-declaration at #1
not only imports M:B
but also imports C
such that the function fun
can be found at #2
. So, why don't we agree that TU C
imported by the exported module-import-declaration at #1
in TU a
is exported by a
, which is exactly said in the below?
all translation units imported by exported module-import-declarations in T; such translation units are said to be exported by T.
This is the part the standard is ambiguous here even though GCC implements the right things which cannot be read from the rule.