On Tue, 24 Jun 2025, Jason Merrill wrote: > On 6/23/25 5:41 PM, Nathaniel Shead wrote: > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15? > > > > -- >8 -- > > > > We were erroring because the TEMPLATE_DECL of the existing partial > > specialisation has an undeduced return type, but the imported > > declaration did not. > > > > The root cause is similar to what was fixed in r13-2744-g4fac53d6522189, > > where modules streaming code assumes that a TEMPLATE_DECL and its > > DECL_TEMPLATE_RESULT will always have the same TREE_TYPE. That commit > > fixed the issue by ensuring that when the type of a variable is deduced > > the TEMPLATE_DECL is updated as well, but this missed handling partial > > specialisations. > > > > However, I don't think we actually care about that, since it seems that > > only the type of the inner decl actually matters in practice. Instead, > > this patch handles the issue on the modules side when deduping a > > streamed decl, by only comparing the inner type. > > > > PR c++/120644 > > > > gcc/cp/ChangeLog: > > > > * decl.cc (cp_finish_decl): Remove workaround. > > Hmm, if we aren't going to try to keep the type of the TEMPLATE_DECL correct, > maybe we should always set it to NULL_TREE to make sure we only look at the > inner type.
FWIW cp_finish_decl can get at the TEMPLATE_DECL of a VAR_DECL corresponding to a partial specialization via TI_TEMPLATE (TI_PARTIAL_INFO (DECL_TEMPLATE_INFO (decl))) if we do want to end up keeping the two TREE_TYPEs in sync. > > The rest of the patch is OK. > > > * module.cc (trees_in::is_matching_decl): Only compare types of > > inner decls. Clarify function return type deduction should only > > occur for non-TEMPLATE_DECL. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/modules/auto-7.h: New test. > > * g++.dg/modules/auto-7_a.H: New test. > > * g++.dg/modules/auto-7_b.C: New test. > > > > Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> > > --- > > gcc/cp/decl.cc | 6 ------ > > gcc/cp/module.cc | 5 +++-- > > gcc/testsuite/g++.dg/modules/auto-7.h | 12 ++++++++++++ > > gcc/testsuite/g++.dg/modules/auto-7_a.H | 5 +++++ > > gcc/testsuite/g++.dg/modules/auto-7_b.C | 5 +++++ > > 5 files changed, 25 insertions(+), 8 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/modules/auto-7.h > > create mode 100644 gcc/testsuite/g++.dg/modules/auto-7_a.H > > create mode 100644 gcc/testsuite/g++.dg/modules/auto-7_b.C > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > index febdc89f89d..150d26079a8 100644 > > --- a/gcc/cp/decl.cc > > +++ b/gcc/cp/decl.cc > > @@ -8921,12 +8921,6 @@ cp_finish_decl (tree decl, tree init, bool > > init_const_expr_p, > > /* Now that we have a type, try these again. */ > > layout_decl (decl, 0); > > cp_apply_type_quals_to_decl (cp_type_quals (type), decl); > > - > > - /* Update the type of the corresponding TEMPLATE_DECL to match. */ > > - if (DECL_LANG_SPECIFIC (decl) > > - && DECL_TEMPLATE_INFO (decl) > > - && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) == decl) > > - TREE_TYPE (DECL_TI_TEMPLATE (decl)) = type; > > } > > if (ensure_literal_type_for_constexpr_object (decl) == > > error_mark_node) > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > > index c99988da05b..606eac77db9 100644 > > --- a/gcc/cp/module.cc > > +++ b/gcc/cp/module.cc > > @@ -12193,7 +12193,8 @@ trees_in::is_matching_decl (tree existing, tree > > decl, bool is_typedef) > > { > > dump (dumper::MERGE) > > && dump ("Propagating deduced return type to %N", existing); > > - FNDECL_USED_AUTO (e_inner) = true; > > + gcc_checking_assert (existing == e_inner); > > + FNDECL_USED_AUTO (existing) = true; > > DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type); > > TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), > > e_type); > > } > > @@ -12248,7 +12249,7 @@ trees_in::is_matching_decl (tree existing, tree > > decl, bool is_typedef) > > /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs > > here. I suspect the entities that directly do that are things > > that shouldn't go to duplicate_decls (FIELD_DECLs etc). */ > > - else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) > > + else if (!cp_tree_equal (TREE_TYPE (d_inner), TREE_TYPE (e_inner))) > > { > > mismatch_msg = G_("conflicting type for imported declaration %#qD"); > > mismatch: > > diff --git a/gcc/testsuite/g++.dg/modules/auto-7.h > > b/gcc/testsuite/g++.dg/modules/auto-7.h > > new file mode 100644 > > index 00000000000..324b60cfa0a > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/modules/auto-7.h > > @@ -0,0 +1,12 @@ > > +// PR c++/120644 > > + > > +enum class E { E0, E1 }; > > + > > +template <typename T> > > +constexpr auto fmt_kind = E::E0; > > + > > +template <typename T> > > +class opt{}; > > + > > +template <typename T> > > +constexpr auto fmt_kind<opt<T>> = E::E1; > > diff --git a/gcc/testsuite/g++.dg/modules/auto-7_a.H > > b/gcc/testsuite/g++.dg/modules/auto-7_a.H > > new file mode 100644 > > index 00000000000..40cb0f886c0 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/modules/auto-7_a.H > > @@ -0,0 +1,5 @@ > > +// PR c++/120644 > > +// { dg-additional-options "-fmodule-header" } > > +// { dg-module-cmi {} } > > + > > +#include "auto-7.h" > > diff --git a/gcc/testsuite/g++.dg/modules/auto-7_b.C > > b/gcc/testsuite/g++.dg/modules/auto-7_b.C > > new file mode 100644 > > index 00000000000..c6ad37fd828 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/modules/auto-7_b.C > > @@ -0,0 +1,5 @@ > > +// PR c++/120644 > > +// { dg-additional-options "-fmodules -fno-module-lazy" } > > + > > +#include "auto-7.h" > > +import "auto-7_a.H"; > >