diff options
author | Patrick Palka <ppalka@redhat.com> | 2024-07-17 21:02:52 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2024-07-17 21:02:52 -0400 |
commit | 30dd420a06ad7d2adf4a672d176caee632f8168a (patch) | |
tree | 1b8c65683f1430b9e4eb83a6f59135ae63a760cc /gcc/cp | |
parent | 93c54caa64fee2a0fa7251d214cdf639b8d7899f (diff) | |
download | gcc-30dd420a06ad7d2adf4a672d176caee632f8168a.zip gcc-30dd420a06ad7d2adf4a672d176caee632f8168a.tar.gz gcc-30dd420a06ad7d2adf4a672d176caee632f8168a.tar.bz2 |
c++: prev declared hidden tmpl friend inst [PR112288]
When partially instantiating a previously declared hidden template
friend definition (at class template scope) such as slot_allocated in
the first testcase below, tsubst_friend_function needs to go through
all existing specializations thereof and make them point to the new
definition.
But when the previous declaration was also at class template scope,
old_decl is not the most general template, instead it's the partial
instantiation, and since instantiations are relative to the most general
template, old_decl's DECL_TEMPLATE_INSTANTIATIONS is empty. So we
to consistently use the most general template here. And when adjusting
DECL_TI_ARGS to match, only the innermost template arguments should be
preserved; the outer ones should correspond to the new definition.
Otherwise we fail a checking-only sanity check in instantiate_decl in
the first testcase, and in the second/third we end up emitting multiple
definitions of the template friend instantiation, resulting in a link
failure.
PR c++/112288
gcc/cp/ChangeLog:
* pt.cc (tsubst_friend_function): When adjusting existing
specializations after defining a previously declared template
friend, consider the most general template and correct
DECL_TI_ARGS adjustment.
gcc/testsuite/ChangeLog:
* g++.dg/template/friend80.C: New test.
* g++.dg/template/friend81.C: New test.
* g++.dg/template/friend81a.C: New test.
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/pt.cc | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 0620c8c..057797f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11582,6 +11582,7 @@ tsubst_friend_function (tree decl, tree args) ; else { + tree old_template = most_general_template (old_decl); tree new_template = TI_TEMPLATE (new_friend_template_info); tree new_args = TI_ARGS (new_friend_template_info); @@ -11619,7 +11620,7 @@ tsubst_friend_function (tree decl, tree args) /* Reassign any specializations already in the hash table to the new more general template, and add the additional template args. */ - for (t = DECL_TEMPLATE_INSTANTIATIONS (old_decl); + for (t = DECL_TEMPLATE_INSTANTIATIONS (old_template); t != NULL_TREE; t = TREE_CHAIN (t)) { @@ -11632,15 +11633,15 @@ tsubst_friend_function (tree decl, tree args) decl_specializations->remove_elt (&elt); - DECL_TI_ARGS (spec) - = add_outermost_template_args (new_args, - DECL_TI_ARGS (spec)); + tree& spec_args = DECL_TI_ARGS (spec); + spec_args = add_outermost_template_args + (new_args, INNERMOST_TEMPLATE_ARGS (spec_args)); register_specialization - (spec, new_template, DECL_TI_ARGS (spec), true, 0); + (spec, new_template, spec_args, true, 0); } - DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE; + DECL_TEMPLATE_INSTANTIATIONS (old_template) = NULL_TREE; } } |