mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-03 07:10:28 +08:00
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:
parent
0d9a70ea38
commit
ded6a1953d
@ -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);
|
||||
|
@ -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))
|
||||
|
57
gcc/cp/pt.c
57
gcc/cp/pt.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
11
gcc/testsuite/g++.dg/modules/pr99285_a.H
Normal file
11
gcc/testsuite/g++.dg/modules/pr99285_a.H
Normal 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> {};
|
7
gcc/testsuite/g++.dg/modules/pr99285_b.H
Normal file
7
gcc/testsuite/g++.dg/modules/pr99285_b.H
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user