aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-04-20 06:44:08 -0700
committerNathan Sidwell <nathan@acm.org>2020-04-20 06:44:08 -0700
commitaa576f2a860c8287cac6bbe6d37f5f37448bf06a (patch)
treece77b77ef21f537759c4abbb0c9461a4ee45b726 /gcc
parent48c82310947355665d628d4d1c8e736df9987574 (diff)
downloadgcc-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/ChangeLog9
-rw-r--r--gcc/cp/pt.c75
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;
}