diff options
author | Nathan Sidwell <nathan@acm.org> | 2021-03-08 10:01:21 -0800 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2021-03-08 10:08:51 -0800 |
commit | ded6a1953dd7f43229c44e5d0d17c264338a3f4c (patch) | |
tree | d6152c9982472c8080f11a2ff4337bea81d68295 | |
parent | 0d9a70ea3881c284b7689b691d54d047b55b486d (diff) | |
download | gcc-ded6a1953dd7f43229c44e5d0d17c264338a3f4c.zip gcc-ded6a1953dd7f43229c44e5d0d17c264338a3f4c.tar.gz gcc-ded6a1953dd7f43229c44e5d0d17c264338a3f4c.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/module.cc | 23 | ||||
-rw-r--r-- | gcc/cp/pt.c | 57 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99285_a.H | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/pr99285_b.H | 7 |
5 files changed, 71 insertions, 34 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 39e2ad8..81ff375 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 48862dd..2518d73 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -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)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 81df8c8..5e485f1 100644 --- a/gcc/cp/pt.c +++ b/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; } } diff --git a/gcc/testsuite/g++.dg/modules/pr99285_a.H b/gcc/testsuite/g++.dg/modules/pr99285_a.H new file mode 100644 index 0000000..14d0aa0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99285_a.H @@ -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> {}; diff --git a/gcc/testsuite/g++.dg/modules/pr99285_b.H b/gcc/testsuite/g++.dg/modules/pr99285_b.H new file mode 100644 index 0000000..01a8eaf --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99285_b.H @@ -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; |