On 12/1/25 6:09 PM, Nathaniel Shead wrote:
Bootstrapped and regtested (so far just modules.exp) on
x86_64-pc-linux-gnu, OK for trunk if full regtest passes?

OK.
-- >8 --

The crash in the PR is caused because we are attempting to write a
using-directive that we never made a dep for.  This should only happen
for imported using-directives, where if we never opened the relevant
namespace in the module purview we don't think there's anything
interesting to discover and so never walk it.

There's actually no reason we need to emit imported using-directives at
all, however, unless they came from a partition, because importers will
be able to get that directive directly from the originating module if it
was going to be visible anyway.  And we will always walk and create a
dependency (marked !import_p) for partition decls.  So this patch fixes
the ICE by just skipping such cases.

To help validate this the patch also starts setting DECL_MODULE_IMPORT_P
correctly for using-directives.

        PR c++/122915

gcc/cp/ChangeLog:

        * module.cc (module_state::write_using_directives): Don't emit
        imported using-directives.
        (module_state::read_using_directives): Rename
        add_using_namespace to add_imported_using_namespace.
        * name-lookup.cc (add_using_namespace): Handle imported
        using-directives.
        (add_imported_using_namespace): Rename to match new
        functionality.
        * name-lookup.h (add_using_namespace): Rename to...
        (add_imported_using_namespace): ...this.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/namespace-16_a.C: New test.
        * g++.dg/modules/namespace-16_b.C: New test.
        * g++.dg/modules/namespace-16_c.C: New test.
        * g++.dg/modules/namespace-16_d.C: New test.

Signed-off-by: Nathaniel Shead <[email protected]>
---
  gcc/cp/module.cc                              | 13 +++++++++++--
  gcc/cp/name-lookup.cc                         | 15 ++++++++++-----
  gcc/cp/name-lookup.h                          |  2 +-
  gcc/testsuite/g++.dg/modules/namespace-16_a.C |  9 +++++++++
  gcc/testsuite/g++.dg/modules/namespace-16_b.C |  9 +++++++++
  gcc/testsuite/g++.dg/modules/namespace-16_c.C | 12 ++++++++++++
  gcc/testsuite/g++.dg/modules/namespace-16_d.C | 10 ++++++++++
  7 files changed, 62 insertions(+), 8 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/namespace-16_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/namespace-16_b.C
  create mode 100644 gcc/testsuite/g++.dg/modules/namespace-16_c.C
  create mode 100644 gcc/testsuite/g++.dg/modules/namespace-16_d.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 993594fafc3..e5668be4786 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -17637,7 +17637,16 @@ module_state::write_using_directives (elf_out *to, 
depset::hash &table,
          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);
+
+         /* An using-directive imported from a different module might not
+            have been walked earlier (PR c++/122915).  But importers will
+            be able to just refer to the decl in that module unless it was
+            a partition anyway, so we don't have anything to do here.  */
+         if (!target_dep || target_dep->is_import ())
+           {
+             gcc_checking_assert (DECL_MODULE_IMPORT_P (udir));
+             continue;
+           }
dump () && dump ("Writing using-directive in %N for %N",
                           parent, target);
@@ -17686,7 +17695,7 @@ module_state::read_using_directives (unsigned num)
dump () && dump ("Read using-directive in %N for %N", parent, target);
        if (exported || is_module () || is_partition ())
-       add_using_namespace (parent, target);
+       add_imported_using_namespace (parent, target);
      }
dump.outdent ();
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 682f2ed49e7..4c07fd40f64 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -9015,7 +9015,8 @@ pop_nested_namespace (tree ns)
     unqualified search.  */
static void
-add_using_namespace (vec<tree, va_gc> *&usings, tree target)
+add_using_namespace (vec<tree, va_gc> *&usings, tree target,
+                    bool imported = false)
  {
    /* Find if this using already exists.  */
    tree old = NULL_TREE;
@@ -9032,15 +9033,18 @@ add_using_namespace (vec<tree, va_gc> *&usings, tree 
target)
      {
        decl = build_lang_decl (USING_DECL, NULL_TREE, NULL_TREE);
        USING_DECL_DECLS (decl) = target;
+      DECL_MODULE_IMPORT_P (decl) = imported;
      }
- /* Update purviewness and exportedness in case that has changed. */
+  /* Update module flags in case that has changed.  */
    if (modules_p ())
      {
        if (module_purview_p ())
        DECL_MODULE_PURVIEW_P (decl) = true;
        if (module_exporting_p ())
        DECL_MODULE_EXPORT_P (decl) = true;
+      if (!imported)
+       DECL_MODULE_IMPORT_P (decl) = false;
      }
if (!old)
@@ -9048,13 +9052,14 @@ add_using_namespace (vec<tree, va_gc> *&usings, tree 
target)
  }
/* Convenience overload for the above, taking the user as its first
-   parameter.  */
+   parameter, for use when importing a using-directive.  */
void
-add_using_namespace (tree ns, tree target)
+add_imported_using_namespace (tree ns, tree target)
  {
    add_using_namespace (NAMESPACE_LEVEL (ns)->using_directives,
-                      ORIGINAL_NAMESPACE (target));
+                      ORIGINAL_NAMESPACE (target),
+                      /*imported=*/true);
  }
/* Tell the debug system of a using directive. */
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 859186a2f2c..da277c49b1a 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -477,7 +477,6 @@ extern cxx_binding *outer_binding (tree, cxx_binding *, 
bool);
  extern void cp_emit_debug_info_for_using (tree, tree);
extern void finish_nonmember_using_decl (tree scope, tree name);
-extern void add_using_namespace (tree, tree);
  extern void finish_using_directive (tree target, tree attribs);
  void push_local_extern_decl_alias (tree decl);
  extern tree pushdecl (tree, bool hiding = false);
@@ -508,6 +507,7 @@ extern bool set_module_binding (tree ctx, tree name, 
unsigned mod,
                                tree value, tree type, tree visible,
                                tree internal);
  extern void add_module_namespace_decl (tree ns, tree decl);
+extern void add_imported_using_namespace (tree, tree);
enum WMB_Flags
  {
diff --git a/gcc/testsuite/g++.dg/modules/namespace-16_a.C 
b/gcc/testsuite/g++.dg/modules/namespace-16_a.C
new file mode 100644
index 00000000000..8475ca0e8f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-16_a.C
@@ -0,0 +1,9 @@
+// PR c++/122915
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi imagine }
+
+export module imagine;
+namespace ns {}
+export namespace ig {
+  using namespace ns;
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-16_b.C 
b/gcc/testsuite/g++.dg/modules/namespace-16_b.C
new file mode 100644
index 00000000000..aed3e8a3e00
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-16_b.C
@@ -0,0 +1,9 @@
+// PR c++/122915
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi tests:part }
+
+export module tests:part;
+namespace abc {}
+namespace part {
+  export using namespace abc;
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-16_c.C 
b/gcc/testsuite/g++.dg/modules/namespace-16_c.C
new file mode 100644
index 00000000000..0638e35be44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-16_c.C
@@ -0,0 +1,12 @@
+// PR c++/122915
+// { dg-additional-options "-fmodules -fdump-lang-module" }
+// { dg-module-cmi tests }
+
+export module tests;
+export import :part;
+import imagine;
+using namespace ig;
+
+// { dg-final { scan-lang-dump {Writing using-directive in '::' for '::ig'} 
module } }
+// { dg-final { scan-lang-dump {Writing using-directive in '::part' for 
'::abc'} module } }
+// { dg-final { scan-lang-dump-not {Writing using-directive in '::ig' for 
'::ns'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/namespace-16_d.C 
b/gcc/testsuite/g++.dg/modules/namespace-16_d.C
new file mode 100644
index 00000000000..f126d411b4b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-16_d.C
@@ -0,0 +1,10 @@
+// PR c++/122915
+// { dg-additional-options "-fmodules" }
+
+module tests;
+
+namespace ns { using T = int; };
+T x = 123;
+
+namespace abc { using U = double; };
+part::U y = 3.14;

Reply via email to