From: Nathaniel Shead Date: Sat, 17 May 2025 13:51:07 +0000 (+1000) Subject: c++/modules: Fix ICE on merge of instantiation with partial spec [PR120013] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b0de7297f2b5670386472229ab795a577c288ecf;p=thirdparty%2Fgcc.git c++/modules: Fix ICE on merge of instantiation with partial spec [PR120013] When we import a pending instantiation that matches an existing partial specialisation, we don't find the slot in the entity map because for partial specialisations we register the TEMPLATE_DECL but for normal implicit instantiations we instead register the inner TYPE_DECL. Because the DECL_MODULE_ENTITY_P flag is set we correctly realise that it is in the entity map, but ICE when attempting to use that slot in partition handling. This patch fixes the issue by detecting this case and instead looking for the slot for the TEMPLATE_DECL. It doesn't matter that we never add a slot for the inner decl because we're about to discard it anyway. PR c++/120013 gcc/cp/ChangeLog: * module.cc (trees_in::install_entity): Handle re-registering the inner TYPE_DECL of a partial specialisation. gcc/testsuite/ChangeLog: * g++.dg/modules/partial-8.h: New test. * g++.dg/modules/partial-8_a.C: New test. * g++.dg/modules/partial-8_b.C: New test. * g++.dg/modules/partial-8_c.C: New test. * g++.dg/modules/partial-8_d.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill --- diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 200e1c2deb3..f728275612e 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8083,18 +8083,37 @@ trees_in::install_entity (tree decl) gcc_checking_assert (!existed); slot = ident; } - else if (state->is_partition ()) - { - /* The decl is already in the entity map, but we see it again now from a - partition: we want to overwrite if the original decl wasn't also from - a (possibly different) partition. Otherwise, for things like template - instantiations, make_dependency might not realise that this is also - provided from a partition and should be considered part of this module - (and thus always emitted into the primary interface's CMI). */ + else + { unsigned *slot = entity_map->get (DECL_UID (decl)); - module_state *imp = import_entity_module (*slot); - if (!imp->is_partition ()) - *slot = ident; + + /* The entity must be in the entity map already. However, DECL may + be the DECL_TEMPLATE_RESULT of an existing partial specialisation + if we matched it while streaming another instantiation; in this + case we already registered that TEMPLATE_DECL. */ + if (!slot) + { + tree type = TREE_TYPE (decl); + gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL + && CLASS_TYPE_P (type) + && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)); + slot = entity_map->get (DECL_UID (CLASSTYPE_TI_TEMPLATE (type))); + } + gcc_checking_assert (slot); + + if (state->is_partition ()) + { + /* The decl is already in the entity map, but we see it again now + from a partition: we want to overwrite if the original decl + wasn't also from a (possibly different) partition. Otherwise, + for things like template instantiations, make_dependency might + not realise that this is also provided from a partition and + should be considered part of this module (and thus always + emitted into the primary interface's CMI). */ + module_state *imp = import_entity_module (*slot); + if (!imp->is_partition ()) + *slot = ident; + } } return true; diff --git a/gcc/testsuite/g++.dg/modules/partial-8.h b/gcc/testsuite/g++.dg/modules/partial-8.h new file mode 100644 index 00000000000..d9a83a83e54 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-8.h @@ -0,0 +1,8 @@ +// PR c++/120013 + +template struct tuple_element; +template tuple_element get(T); + +// This case wasn't an issue for the PR, but worth double-checking +template constexpr int var = 123; +template void foo(T, int = var); diff --git a/gcc/testsuite/g++.dg/modules/partial-8_a.C b/gcc/testsuite/g++.dg/modules/partial-8_a.C new file mode 100644 index 00000000000..d6848c78360 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-8_a.C @@ -0,0 +1,10 @@ +// PR c++/120013 +// { dg-additional-options "-fmodules -Wno-global-module" } +// { dg-module-cmi m:a } + +module; +#include "partial-8.h" +template struct tuple_element; +template constexpr int var = 456; +module m:a; +template void a(T t) { ::get(t); foo(t); } diff --git a/gcc/testsuite/g++.dg/modules/partial-8_b.C b/gcc/testsuite/g++.dg/modules/partial-8_b.C new file mode 100644 index 00000000000..ce5cd097d65 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-8_b.C @@ -0,0 +1,8 @@ +// PR c++/120013 +// { dg-additional-options "-fmodules -Wno-global-module" } +// { dg-module-cmi m:b } + +module; +#include "partial-8.h" +module m:b; +template void b(T t) { ::get(t); foo(t); } diff --git a/gcc/testsuite/g++.dg/modules/partial-8_c.C b/gcc/testsuite/g++.dg/modules/partial-8_c.C new file mode 100644 index 00000000000..eadd282c6ad --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-8_c.C @@ -0,0 +1,7 @@ +// PR c++/120013 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi m } + +export module m; +import :a; +import :b; diff --git a/gcc/testsuite/g++.dg/modules/partial-8_d.C b/gcc/testsuite/g++.dg/modules/partial-8_d.C new file mode 100644 index 00000000000..2aedb39670c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-8_d.C @@ -0,0 +1,9 @@ +// PR c++/120013 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi m } +// Same as partial-8_c.C but in the other order, to ensure +// that loading a partial spec over an instantiation works + +export module m; +import :b; +import :a;