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:#️⃣: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 <nathanieloshead@gmail.com>
Reviewed-by: Patrick Palka <ppalka@redhat.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
Nathaniel Shead 2025-10-15 18:13:38 +11:00
parent 75fb400d29
commit 515045254f
7 changed files with 55 additions and 5 deletions

View File

@ -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 ();

View File

@ -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 } }

View File

@ -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'" }

View File

@ -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;
}

View File

@ -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();
}

View File

@ -0,0 +1,7 @@
// PR c++/122279
// { dg-additional-options "-fmodules" }
module M;
void test2() {
qux::go();
}

View File

@ -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();
}