Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15? -- >8 --
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 <nathanielosh...@gmail.com> --- gcc/cp/module.cc | 41 ++++++++++++++++------ gcc/testsuite/g++.dg/modules/partial-8.h | 8 +++++ gcc/testsuite/g++.dg/modules/partial-8_a.C | 10 ++++++ gcc/testsuite/g++.dg/modules/partial-8_b.C | 8 +++++ gcc/testsuite/g++.dg/modules/partial-8_c.C | 7 ++++ gcc/testsuite/g++.dg/modules/partial-8_d.C | 9 +++++ 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/partial-8.h create mode 100644 gcc/testsuite/g++.dg/modules/partial-8_a.C create mode 100644 gcc/testsuite/g++.dg/modules/partial-8_b.C create mode 100644 gcc/testsuite/g++.dg/modules/partial-8_c.C create mode 100644 gcc/testsuite/g++.dg/modules/partial-8_d.C 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 <typename> struct tuple_element; +template <typename T> tuple_element<T*> get(T); + +// This case wasn't an issue for the PR, but worth double-checking +template <typename> constexpr int var = 123; +template <typename T> void foo(T, int = var<T*>); 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 <typename T> struct tuple_element<T*>; +template <typename T> constexpr int var<T*> = 456; +module m:a; +template <typename T> 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 <typename T> 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; -- 2.47.0