c++: Incorrect specialization hash table [PR 99285]

Class template partial specializations need to be in the
specialization hash, but not all of them.  This defers adding
streamed-in entities to the hash table, in the same way I deferred
adding the instantiation and specialization lists for 99170.

	PR c++/99285
	gcc/cp/
	* cp-tree.h (match_mergeable_specialization)
	(add_mergeable_specialization): Adjust parms.
	* module.cc (trees_in::decl_value): Adjust
	add_mergeable_specialization calls.
	(trees_out::key_mergeable): Adjust match_mergeable_specialization
	calls.
	(specialization_add): Likewise.
	* pt.c (match_mergeable_specialization): Do not insert.
	(add_mergeable_specialization): Add to hash table here.
	gcc/testsuite/
	* g++.dg/modules/pr99285_a.H: New.
	* g++.dg/modules/pr99285_b.H: New.
This commit is contained in:
Nathan Sidwell 2021-03-08 10:01:21 -08:00
parent 0d9a70ea38
commit ded6a1953d
5 changed files with 71 additions and 34 deletions

View File

@ -7239,11 +7239,10 @@ extern void walk_specializations (bool,
void (*)(bool, spec_entry *,
void *),
void *);
extern tree match_mergeable_specialization (bool is_decl, spec_entry *,
bool insert = true);
extern tree match_mergeable_specialization (bool is_decl, spec_entry *);
extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
extern void add_mergeable_specialization (tree tmpl, tree args,
tree spec, unsigned);
extern void add_mergeable_specialization (bool is_decl, spec_entry *,
tree outer, unsigned);
extern tree add_outermost_template_args (tree, tree);
extern tree add_extra_args (tree, tree);
extern tree build_extra_args (tree, tree, tsubst_flags_t);

View File

@ -8059,9 +8059,14 @@ trees_in::decl_value ()
set_constraints (decl, spec.spec);
if (mk & MK_template_mask
|| mk == MK_partial)
/* Add to specialization tables now that constraints etc are
added. */
add_mergeable_specialization (spec.tmpl, spec.args, decl, spec_flags);
{
/* Add to specialization tables now that constraints etc are
added. */
bool is_decl = (mk & MK_template_mask) && (mk & MK_tmpl_decl_mask);
spec.spec = is_decl ? inner : type;
add_mergeable_specialization (is_decl, &spec, decl, spec_flags);
}
if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl))
{
@ -8154,7 +8159,10 @@ trees_in::decl_value ()
{
tree e = match_mergeable_specialization (true, &spec);
if (!e)
add_mergeable_specialization (spec.tmpl, spec.args, decl, spec_flags);
{
spec.spec = inner;
add_mergeable_specialization (true, &spec, decl, spec_flags);
}
else if (e != existing)
set_overrun ();
}
@ -10344,14 +10352,14 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
{
/* Make sure we can locate the decl. */
tree existing = match_mergeable_specialization
(bool (mk & MK_tmpl_decl_mask), entry, false);
(bool (mk & MK_tmpl_decl_mask), entry);
gcc_assert (existing);
if (mk & MK_tmpl_decl_mask)
{
if (mk & MK_tmpl_alias_mask)
/* It should be in both tables. */
gcc_assert (match_mergeable_specialization (false, entry, false)
gcc_assert (match_mergeable_specialization (false, entry)
== TREE_TYPE (existing));
else if (mk & MK_tmpl_tmpl_mask)
if (tree ti = DECL_TEMPLATE_INFO (existing))
@ -10659,6 +10667,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
if (mk & MK_template_mask)
{
// FIXME: We could stream the specialization hash?
spec_entry spec;
spec.tmpl = tree_node ();
spec.args = tree_node ();
@ -12869,7 +12878,7 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
/* Only alias templates can appear in both tables (and
if they're in the type table they must also be in the decl table). */
gcc_checking_assert
(!match_mergeable_specialization (true, entry, false)
(!match_mergeable_specialization (true, entry)
== (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl)));
}
else if (VAR_OR_FUNCTION_DECL_P (entry->spec))

View File

@ -29955,28 +29955,19 @@ walk_specializations (bool decls_p,
}
/* Lookup the specialization of *ELT, in the decl or type
specialization table. Return the SPEC that's already there (NULL if
nothing). If INSERT is true, and there was nothing, add the new
spec. */
specialization table. Return the SPEC that's already there, or
NULL if nothing. */
tree
match_mergeable_specialization (bool decl_p, spec_entry *elt, bool insert)
match_mergeable_specialization (bool decl_p, spec_entry *elt)
{
hash_table<spec_hasher> *specializations
= decl_p ? decl_specializations : type_specializations;
hashval_t hash = spec_hasher::hash (elt);
spec_entry **slot
= specializations->find_slot_with_hash (elt, hash,
insert ? INSERT : NO_INSERT);
if (slot && *slot)
return (*slot)->spec;
auto *slot = specializations->find_slot_with_hash (elt, hash, NO_INSERT);
if (insert)
{
auto entry = ggc_alloc<spec_entry> ();
*entry = *elt;
*slot = entry;
}
if (slot)
return (*slot)->spec;
return NULL_TREE;
}
@ -30012,23 +30003,43 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
return flags;
}
/* Add a new specialization of TMPL. FLAGS is as returned from
/* Add a new specialization described by SPEC. DECL is the
maybe-template decl and FLAGS is as returned from
get_mergeable_specialization_flags. */
void
add_mergeable_specialization (tree tmpl, tree args, tree decl, unsigned flags)
add_mergeable_specialization (bool decl_p, spec_entry *elt,
tree decl, unsigned flags)
{
hash_table<spec_hasher> *specializations
= decl_p ? decl_specializations : type_specializations;
hashval_t hash = spec_hasher::hash (elt);
auto *slot = specializations->find_slot_with_hash (elt, hash, INSERT);
/* We don't distinguish different constrained partial type
specializations, so there could be duplicates. Everything else
must be new. */
if (!(flags & 2 && *slot))
{
gcc_checking_assert (!*slot);
auto entry = ggc_alloc<spec_entry> ();
*entry = *elt;
*slot = entry;
}
if (flags & 1)
DECL_TEMPLATE_INSTANTIATIONS (tmpl)
= tree_cons (args, decl, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl)
= tree_cons (elt->args, decl, DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl));
if (flags & 2)
{
/* A partial specialization. */
DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
= tree_cons (args, decl, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (tmpl))
= TREE_TYPE (DECL_TEMPLATE_RESULT (decl));
tree cons = tree_cons (elt->args, decl,
DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl));
TREE_TYPE (cons) = elt->spec;
DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl) = cons;
}
}

View File

@ -0,0 +1,11 @@
// PR 99285 ICE with template-template-parm
// { dg-additional-options -fmodule-header }
// { dg-module-cmi {} }
template<typename... _Tp> struct common_type;
template<> struct common_type<> {};
template<typename _Tp0> struct common_type<_Tp0> {};
template<typename _Tp1, typename _Tp2> struct common_type<_Tp1, _Tp2> {};

View File

@ -0,0 +1,7 @@
// { dg-additional-options -fmodule-header }
// { dg-module-cmi {} }
import "pr99285_a.H";
template<typename _Rep1, typename _Rep2,
typename _CRep = typename common_type<_Rep1, _Rep2>::type>
struct X;