https://gcc.gnu.org/g:8c45800ed688fc31fccee49fb1c5c51157be8c89

commit r16-8092-g8c45800ed688fc31fccee49fb1c5c51157be8c89
Author: Nathaniel Shead <[email protected]>
Date:   Sat Mar 14 11:25:47 2026 +1100

    c++/modules: Fix crash on implicit redeclaration of ABI class types 
[PR124485]
    
    The crash in the given testcase occurs because the fix for PR122053,
    r16-4228-gfa6544ef5f50a824cabeda4906453d4545fbf66f, added a call to
    lazy_load_pending when doing push_tag, to prevent ICEs at least when
    types are textually redefined in lieu of full PR99000 support.
    
    But this means that we might not have loaded the declarations of the ABI
    types in lookup_elaborated_type to merge them there yet, but still have
    them by the time we get to check_module_override, causing errors, and
    then an ICE because tinfo_base_init is not prepared for xref_tag to
    fail.
    
    It turns out that doing the lazy load in pushtag is too late; we replace
    the decl, but we don't replace the type, and then we end up returning
    the type that we were building anyway rather than the type we were
    hoping to match against.
    
    The reason I'd done it there originally is because that's the earliest
    we have a decl to do lazy_load_pendings with, but it seems that instead
    we should have another interface to lazy_load_pendings that can be used
    if you already know the name and namespace of the entity that you're
    keying too.
    
            PR c++/124485
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (lazy_load_pendings): Declare new overload.
            * module.cc (lazy_load_pendings): Define it.
            * name-lookup.cc (lookup_elaborated_type): Load pending entities
            with given name before doing namespace-scope lookup.
            (pushtag): Remove no-longer-needed pending load.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/class-8_b.C: Adjusted expected behaviour.
            * g++.dg/modules/pr124485_a.C: New test.
            * g++.dg/modules/pr124485_b.C: New test.
    
    Signed-off-by: Nathaniel Shead <[email protected]>
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/cp-tree.h                          |  1 +
 gcc/cp/module.cc                          | 20 +++++++++++++++-----
 gcc/cp/name-lookup.cc                     | 13 +++++++------
 gcc/testsuite/g++.dg/modules/class-8_b.C  |  2 +-
 gcc/testsuite/g++.dg/modules/pr124485_a.C | 13 +++++++++++++
 gcc/testsuite/g++.dg/modules/pr124485_b.C |  7 +++++++
 6 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7444cc83770a..ea3cb049785b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7997,6 +7997,7 @@ extern void mangle_module (int m, bool include_partition);
 extern void mangle_module_fini ();
 extern void lazy_load_binding (unsigned mod, tree ns, tree id,
                               binding_slot *bslot);
+extern void lazy_load_pendings (tree ns, tree name);
 extern void lazy_load_pendings (tree decl);
 extern module_state *preprocess_module (module_state *, location_t,
                                        bool in_purview,
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 2125cc00fbe7..83d24a3267dd 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -22577,19 +22577,19 @@ lazy_load_binding (unsigned mod, tree ns, tree id, 
binding_slot *mslot)
            module->get_flatname ());
 }
 
-/* Load any pending entities keyed to the top-key of DECL.  */
+/* Load any pending entities keyed to NS and NAME.
+   Used to find pending types if we don't yet have a decl built.  */
 
 void
-lazy_load_pendings (tree decl)
+lazy_load_pendings (tree ns, tree name)
 {
   /* Make sure lazy loading from a template context behaves as if
      from a non-template context.  */
   processing_template_decl_sentinel ptds;
 
-  tree key_decl;
   pending_key key;
-  key.ns = find_pending_key (decl, &key_decl);
-  key.id = DECL_NAME (key_decl);
+  key.ns = ns;
+  key.id = name;
 
   auto *pending_vec = pending_table ? pending_table->get (key) : nullptr;
   if (!pending_vec)
@@ -22642,6 +22642,16 @@ lazy_load_pendings (tree decl)
            key.ns, &"::"[key.ns == global_namespace ? 2 : 0], key.id);
 }
 
+/* Load any pending entities keyed to the top-key of DECL.  */
+
+void
+lazy_load_pendings (tree decl)
+{
+  tree key_decl;
+  tree ns = find_pending_key (decl, &key_decl);
+  return lazy_load_pendings (ns, DECL_NAME (key_decl));
+}
+
 static void
 direct_import (module_state *import, cpp_reader *reader)
 {
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index cbf970f30df0..13aafab4e685 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -8490,6 +8490,13 @@ lookup_elaborated_type (tree name, TAG_how how)
 
   /* Look in the innermost namespace.  */
   tree ns = b->this_entity;
+
+  /* If an import is going to provide a definition for this tag,
+     load it now so that we don't get confused later when processing
+     this tag's definition.  */
+  if (modules_p ())
+    lazy_load_pendings (ns, name);
+
   if (tree *slot = find_namespace_slot (ns, name))
     {
       tree bind = *slot;
@@ -8796,12 +8803,6 @@ pushtag (tree name, tree type, TAG_how how)
        }
       else
        {
-         /* If an import is going to provide a definition for this tag,
-            load it now so that we don't get confused later when processing
-            this tag's definition.  */
-         if (modules_p ())
-           lazy_load_pendings (decl);
-
          decl = do_pushdecl_with_scope
            (decl, b, /*hiding=*/(how == TAG_how::HIDDEN_FRIEND));
          if (decl == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/modules/class-8_b.C 
b/gcc/testsuite/g++.dg/modules/class-8_b.C
index 0bb01ac6a33d..dcaa25f72d6e 100644
--- a/gcc/testsuite/g++.dg/modules/class-8_b.C
+++ b/gcc/testsuite/g++.dg/modules/class-8_b.C
@@ -20,4 +20,4 @@ void bob ()
 }
 
 // { dg-final { scan-lang-dump {Lazily binding '::A'@'foo' section:} module } }
-// { dg-final { scan-lang-dump {Lazily binding '::B'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Reading 1 pending entities keyed to '::B'} 
module } }
diff --git a/gcc/testsuite/g++.dg/modules/pr124485_a.C 
b/gcc/testsuite/g++.dg/modules/pr124485_a.C
new file mode 100644
index 000000000000..01f252f99784
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr124485_a.C
@@ -0,0 +1,13 @@
+// PR c++/124485
+// { dg-additional-options "-fmodules -Wno-global-module" }
+// { dg-module-cmi foo }
+
+module;
+namespace __cxxabiv1 {
+  struct __class_type_info {};
+}
+struct type_info {
+  void __do_upcast(__cxxabiv1::__class_type_info);
+};
+export module foo;
+type_info t;
diff --git a/gcc/testsuite/g++.dg/modules/pr124485_b.C 
b/gcc/testsuite/g++.dg/modules/pr124485_b.C
new file mode 100644
index 000000000000..ef85b6a46618
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr124485_b.C
@@ -0,0 +1,7 @@
+// PR c++/124485
+// { dg-additional-options "-fmodules -Wno-global-module" }
+
+import foo;
+struct Type {
+  virtual ~Type() {}
+};

Reply via email to