]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Template argument hashing [pr94454]
authorNathan Sidwell <nathan@acm.org>
Mon, 20 Apr 2020 13:44:08 +0000 (06:44 -0700)
committerNathan Sidwell <nathan@acm.org>
Mon, 20 Apr 2020 13:44:08 +0000 (06:44 -0700)
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.

gcc/cp/ChangeLog
gcc/cp/pt.c

index 9533cca713702cc3213e3ec4544343b23f117c02..5191db9580ed18d2a63202903472c08727553429 100644 (file)
@@ -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
index 9e39f46a090c602b52628f89fd30f0388779571a..4814b768c2caaaa81b3bf19fa884cc1d26e826e8 100644 (file)
@@ -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;
 }