From aa576f2a860c8287cac6bbe6d37f5f37448bf06a Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 20 Apr 2020 06:44:08 -0700 Subject: [PATCH] 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 + + 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 PR c++/94632 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9e39f46a090..4814b768c2c 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; } -- 2.30.2