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