diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-04-20 06:44:08 -0700 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-04-20 06:44:08 -0700 |
commit | aa576f2a860c8287cac6bbe6d37f5f37448bf06a (patch) | |
tree | ce77b77ef21f537759c4abbb0c9461a4ee45b726 /gcc | |
parent | 48c82310947355665d628d4d1c8e736df9987574 (diff) | |
download | gcc-aa576f2a860c8287cac6bbe6d37f5f37448bf06a.zip gcc-aa576f2a860c8287cac6bbe6d37f5f37448bf06a.tar.gz gcc-aa576f2a860c8287cac6bbe6d37f5f37448bf06a.tar.bz2 |
c++: Template argument hashing [pr94454]
One of the problems hit by pr94454 was that the argument hasher was
not skipping nodes that template_args_equal would. Fixed by replacing
the STRIP_NOPS invocation by a bespoke loop. We also confuse the
canonical type machinery by treating tpl-tpl-parms as types. They're
not; bound-tpl-tpl-parms are. We can get away with them being
type-like. Unfortunately we give the original level==orig_level case
a canonical type, but the reduced cases of level<orig_level get
structural equality. That breaks the hasher because we'll use
TYPE_HASH (CANONICAL_TYPE ()) when we can. There's a note in
tsubst[TEMPLATE_TEMPLATE_PARM] about why the reduced ones cannot have
a canonical type. (I didn't feel like questioning that assertion at
this point.)
* pt.c (iterative_hash_template_arg): Strip nodes as
template_args_equal does.
[ARGUMENT_PACK_SELECT, TREE_VEC, CONSTRUCTOR]: Refactor.
[node_class:TEMPLATE_TEMPLATE_PARM]: Hash by level & index.
[node_class:default]: Refactor.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/pt.c | 75 |
2 files changed, 55 insertions, 29 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9533cca..5191db9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2020-04-20 Nathan Sidwell <nathan@acm.org> + + PR c++/94454 Template Argument Hashing + * pt.c (iterative_hash_template_arg): Strip nodes as + template_args_equal does. + [ARGUMENT_PACK_SELECT, TREE_VEC, CONSTRUCTOR]: Refactor. + [node_class:TEMPLATE_TEMPLATE_PARM]: Hash by level & index. + [node_class:default]: Refactor. + 2020-04-18 Patrick Palka <ppalka@redhat.com> PR c++/94632 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9e39f46..4814b76 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -195,6 +195,7 @@ static void set_current_access_from_decl (tree); static enum template_base_result get_template_base (tree, tree, tree, tree, bool , tree *); static tree try_class_unification (tree, tree, tree, tree, bool); +static bool class_nttp_const_wrapper_p (tree t); static int coerce_template_template_parms (tree, tree, tsubst_flags_t, tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree); @@ -1737,31 +1738,32 @@ spec_hasher::hash (spec_entry *e) } /* Recursively calculate a hash value for a template argument ARG, for use - in the hash tables of template specializations. */ + in the hash tables of template specializations. We must be + careful to (at least) skip the same entities template_args_equal + does. */ hashval_t iterative_hash_template_arg (tree arg, hashval_t val) { - unsigned HOST_WIDE_INT i; - enum tree_code code; - char tclass; - if (arg == NULL_TREE) return iterative_hash_object (arg, val); if (!TYPE_P (arg)) - STRIP_NOPS (arg); - - if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT) - gcc_unreachable (); + /* Strip nop-like things, but not the same as STRIP_NOPS. */ + while (CONVERT_EXPR_P (arg) + || TREE_CODE (arg) == NON_LVALUE_EXPR + || class_nttp_const_wrapper_p (arg)) + arg = TREE_OPERAND (arg, 0); - code = TREE_CODE (arg); - tclass = TREE_CODE_CLASS (code); + enum tree_code code = TREE_CODE (arg); val = iterative_hash_object (code, val); switch (code) { + case ARGUMENT_PACK_SELECT: + gcc_unreachable (); + case ERROR_MARK: return val; @@ -1769,12 +1771,9 @@ iterative_hash_template_arg (tree arg, hashval_t val) return iterative_hash_object (IDENTIFIER_HASH_VALUE (arg), val); case TREE_VEC: - { - int i, len = TREE_VEC_LENGTH (arg); - for (i = 0; i < len; ++i) - val = iterative_hash_template_arg (TREE_VEC_ELT (arg, i), val); - return val; - } + for (int i = 0, len = TREE_VEC_LENGTH (arg); i < len; ++i) + val = iterative_hash_template_arg (TREE_VEC_ELT (arg, i), val); + return val; case TYPE_PACK_EXPANSION: case EXPR_PACK_EXPANSION: @@ -1798,6 +1797,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) case CONSTRUCTOR: { tree field, value; + unsigned i; iterative_hash_template_arg (TREE_TYPE (arg), val); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg), i, field, value) { @@ -1884,6 +1884,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) break; } + char tclass = TREE_CODE_CLASS (code); switch (tclass) { case tcc_type: @@ -1899,12 +1900,30 @@ iterative_hash_template_arg (tree arg, hashval_t val) tree ti = TYPE_ALIAS_TEMPLATE_INFO (ats); return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti)); } - if (TYPE_CANONICAL (arg)) - return iterative_hash_object (TYPE_HASH (TYPE_CANONICAL (arg)), - val); - else if (TREE_CODE (arg) == DECLTYPE_TYPE) - return iterative_hash_template_arg (DECLTYPE_TYPE_EXPR (arg), val); - /* Otherwise just compare the types during lookup. */ + + switch (TREE_CODE (arg)) + { + case TEMPLATE_TEMPLATE_PARM: + { + tree tpi = TEMPLATE_TYPE_PARM_INDEX (arg); + + /* Do not recurse with TPI directly, as that is unbounded + recursion. */ + val = iterative_hash_object (TEMPLATE_PARM_LEVEL (tpi), val); + val = iterative_hash_object (TEMPLATE_PARM_IDX (tpi), val); + } + break; + + case DECLTYPE_TYPE: + val = iterative_hash_template_arg (DECLTYPE_TYPE_EXPR (arg), val); + break; + + default: + if (tree canonical = TYPE_CANONICAL (arg)) + val = iterative_hash_object (TYPE_HASH (canonical), val); + break; + } + return val; case tcc_declaration: @@ -1913,13 +1932,11 @@ iterative_hash_template_arg (tree arg, hashval_t val) default: gcc_assert (IS_EXPR_CODE_CLASS (tclass)); - { - unsigned n = cp_tree_operand_length (arg); - for (i = 0; i < n; ++i) - val = iterative_hash_template_arg (TREE_OPERAND (arg, i), val); - return val; - } + for (int i = 0, n = cp_tree_operand_length (arg); i < n; ++i) + val = iterative_hash_template_arg (TREE_OPERAND (arg, i), val); + return val; } + gcc_unreachable (); return 0; } |