From 515045254f5dbdea5208035a0352acc12c381088 Mon Sep 17 00:00:00 2001 From: Nathaniel Shead Date: Wed, 15 Oct 2025 18:13:38 +1100 Subject: [PATCH] c++/modules: Import purview using-directives in the same module [PR122279] [namespace.qual] p1 says that a namespace nominated by a using-directive is searched if the using-directive precedes that point. [basic.lookup.general] p2 says that a declaration in a different TU within a module purview is visible if either the declaration is exported, or the other TU is part of the same module as the point of lookup. This patch implements the second half of that. PR c++/122279 gcc/cp/ChangeLog: * module.cc (depset::hash::add_namespace_entities): Seed any purview using-decls. (module_state::write_using_directives): Stream if the udir was exported or not. (module_state::read_using_directives): Add the using-directive if it's either exported or part of this module. gcc/testsuite/ChangeLog: * g++.dg/modules/namespace-13_b.C: Adjust expected results. * g++.dg/modules/namespace-13_c.C: Test non-exported using-directive is not used. * g++.dg/modules/namespace-14_a.C: New test. * g++.dg/modules/namespace-14_b.C: New test. * g++.dg/modules/namespace-14_c.C: New test. * g++.dg/modules/namespace-14_d.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Patrick Palka Reviewed-by: Jason Merrill --- gcc/cp/module.cc | 13 +++++++++---- gcc/testsuite/g++.dg/modules/namespace-13_b.C | 4 +++- gcc/testsuite/g++.dg/modules/namespace-13_c.C | 3 +++ gcc/testsuite/g++.dg/modules/namespace-14_a.C | 11 +++++++++++ gcc/testsuite/g++.dg/modules/namespace-14_b.C | 12 ++++++++++++ gcc/testsuite/g++.dg/modules/namespace-14_c.C | 7 +++++++ gcc/testsuite/g++.dg/modules/namespace-14_d.C | 10 ++++++++++ 7 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/namespace-14_a.C create mode 100644 gcc/testsuite/g++.dg/modules/namespace-14_b.C create mode 100644 gcc/testsuite/g++.dg/modules/namespace-14_c.C create mode 100644 gcc/testsuite/g++.dg/modules/namespace-14_d.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index bdc7e6af8748..ed0d69cead45 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -14761,10 +14761,11 @@ depset::hash::add_namespace_entities (tree ns, bitmap partitions) /* Seed any using-directives so that we emit the relevant namespaces. */ for (tree udir : NAMESPACE_LEVEL (ns)->using_directives) - if (TREE_CODE (udir) == USING_DECL && DECL_MODULE_EXPORT_P (udir)) + if (TREE_CODE (udir) == USING_DECL && DECL_MODULE_PURVIEW_P (udir)) { make_dependency (USING_DECL_DECLS (udir), depset::EK_NAMESPACE); - count++; + if (DECL_MODULE_EXPORT_P (udir)) + count++; } if (count) @@ -17397,14 +17398,16 @@ module_state::write_using_directives (elf_out *to, depset::hash &table, tree parent = parent_dep->get_entity (); for (auto udir : NAMESPACE_LEVEL (parent)->using_directives) { - if (TREE_CODE (udir) != USING_DECL || !DECL_MODULE_EXPORT_P (udir)) + if (TREE_CODE (udir) != USING_DECL || !DECL_MODULE_PURVIEW_P (udir)) continue; + bool exported = DECL_MODULE_EXPORT_P (udir); tree target = USING_DECL_DECLS (udir); depset *target_dep = table.find_dependency (target); gcc_checking_assert (target_dep); dump () && dump ("Writing using-directive in %N for %N", parent, target); + sec.u (exported); write_namespace (sec, parent_dep); write_namespace (sec, target_dep); ++num; @@ -17441,13 +17444,15 @@ module_state::read_using_directives (unsigned num) for (unsigned ix = 0; ix != num; ++ix) { + bool exported = sec.u (); tree parent = read_namespace (sec); tree target = read_namespace (sec); if (sec.get_overrun ()) break; dump () && dump ("Read using-directive in %N for %N", parent, target); - add_using_namespace (parent, target); + if (exported || is_module () || is_partition ()) + add_using_namespace (parent, target); } dump.outdent (); diff --git a/gcc/testsuite/g++.dg/modules/namespace-13_b.C b/gcc/testsuite/g++.dg/modules/namespace-13_b.C index 1b309617814a..4c2a7d9d12c7 100644 --- a/gcc/testsuite/g++.dg/modules/namespace-13_b.C +++ b/gcc/testsuite/g++.dg/modules/namespace-13_b.C @@ -6,6 +6,7 @@ module; namespace gmf::blah {} namespace gmf::other {} +using namespace gmf::other; // not emitted export module b; export import a; @@ -21,7 +22,7 @@ namespace c { using namespace a; } -// { dg-final { scan-lang-dump {Using-directives 3} module } } +// { dg-final { scan-lang-dump {Using-directives 4} module } } // { dg-final { scan-lang-dump {Writing using-directive in '::b' for '::a'} module } } // { dg-final { scan-lang-dump {Writing using-directive in '::b' for '::gmf::blah'} module } } @@ -30,3 +31,4 @@ namespace c { // { dg-final { scan-lang-dump {Writing namespace:[0-9]* '::gmf::blah', public} module } } // { dg-final { scan-lang-dump-not {Writing namespace:[0-9]* '::gmf::other'} module } } +// { dg-final { scan-lang-dump-not {Writing using-directive in '::' for '::gmf::other'} module } } diff --git a/gcc/testsuite/g++.dg/modules/namespace-13_c.C b/gcc/testsuite/g++.dg/modules/namespace-13_c.C index d04ef37cdbf5..51f4dfc47a23 100644 --- a/gcc/testsuite/g++.dg/modules/namespace-13_c.C +++ b/gcc/testsuite/g++.dg/modules/namespace-13_c.C @@ -15,3 +15,6 @@ static_assert(b::f() == 42); static_assert(b::g() == 123); static_assert(c::other::h() == 99); static_assert(y::i() == 5); + +// unexported 'using namespace a'; should not be visible in 'c' +int result = c::f(); // { dg-error "'f' is not a member of 'c'" } diff --git a/gcc/testsuite/g++.dg/modules/namespace-14_a.C b/gcc/testsuite/g++.dg/modules/namespace-14_a.C new file mode 100644 index 000000000000..c26964e25383 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/namespace-14_a.C @@ -0,0 +1,11 @@ +// PR c++/122279 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi M:part } + +module M:part; +namespace foo { + void go(); +} +namespace bar { + using namespace foo; +} diff --git a/gcc/testsuite/g++.dg/modules/namespace-14_b.C b/gcc/testsuite/g++.dg/modules/namespace-14_b.C new file mode 100644 index 000000000000..987c76883b18 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/namespace-14_b.C @@ -0,0 +1,12 @@ +// PR c++/122279 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi M } + +export module M; +import :part; +namespace qux { + using namespace bar; +} +void test1() { + bar::go(); +} diff --git a/gcc/testsuite/g++.dg/modules/namespace-14_c.C b/gcc/testsuite/g++.dg/modules/namespace-14_c.C new file mode 100644 index 000000000000..08966091525e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/namespace-14_c.C @@ -0,0 +1,7 @@ +// PR c++/122279 +// { dg-additional-options "-fmodules" } + +module M; +void test2() { + qux::go(); +} diff --git a/gcc/testsuite/g++.dg/modules/namespace-14_d.C b/gcc/testsuite/g++.dg/modules/namespace-14_d.C new file mode 100644 index 000000000000..e5a55ed95241 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/namespace-14_d.C @@ -0,0 +1,10 @@ +// PR c++/122279 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi M:other_part } + +module M:other_part; +import :part; + +void test3() { + bar::go(); +}