Bug 109531 - [13/14 Regression] Checking ICE with hash table checking failed: equal operator returns true for a pair of values with a different hash value since r13-3292-gc2565a31c1622a
Summary: [13/14 Regression] Checking ICE with hash table checking failed: equal opera...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 13.0
: P3 normal
Target Milestone: 13.0
Assignee: Patrick Palka
URL:
Keywords: ice-checking, ice-on-valid-code
Depends on: 109651
Blocks: 100131
  Show dependency treegraph
 
Reported: 2023-04-17 03:11 UTC by Sam James
Modified: 2023-04-28 06:25 UTC (History)
6 users (show)

See Also:
Host: x86_64-pc-linux-gnu
Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2023-04-17 00:00:00


Attachments
ArithmeticSubtermGeneralization.ii.orig.xz (255.26 KB, application/x-xz)
2023-04-17 03:11 UTC, Sam James
Details
invalid_reduction.ii (141 bytes, text/plain)
2023-04-17 04:01 UTC, Sam James
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sam James 2023-04-17 03:11:46 UTC
Created attachment 54872 [details]
ArithmeticSubtermGeneralization.ii.orig.xz

Hit this with vampire-4.7:

```
$ /usr/bin/x86_64-pc-linux-gnu-g++ -DCHECK_LEAKS=0 -DVDEBUG=0 -DVZ3=1 -I/var/tmp/portage/sci-mathematics/vampire-4.7-r1/work/vampire-2d02e4655e1b08d1ca9ee7c0aade40f59f046460  -O2 -march=znver3 -pipe -U_GLIBCXX_ASSERTIONS -U_FORTIFY_SOURCE -fno-strict-aliasing -std=c++14 -fdiagnostics-color=always -Wall -c /var/tmp/portage/sci-mathematics/vampire-4.7-r1/work/vampire-2d02e4655e1b08d1ca9ee7c0aade40f59f046460/Inferences/ArithmeticSubtermGeneralization.cpp
hash table checking failed: equal operator returns true for a pair of values with a different hash value
[... warning output ...]
/var/tmp/portage/sci-mathematics/vampire-4.7-r1/work/vampire-2d02e4655e1b08d1ca9ee7c0aade40f59f046460/Lib/Metaiterators.hpp:1787:19: internal compiler error: in hashtab_chk_error, at hash-table.cc:137
 1787 |   Container<Elem> collect()
      |                   ^~~~~~~
0x18f8915 hashtab_chk_error()
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/hash-table.cc:137
0x67cd7a hash_table<ctp_hasher, false, xcallocator>::verify(tree_node* const&, unsigned int)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/hash-table.h:1118
0x67cd7a hash_table<ctp_hasher, false, xcallocator>::find_slot_with_hash(tree_node* const&, unsigned int, insert_option)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/hash-table.h:1046
0x67cd7a hash_table<ctp_hasher, false, xcallocator>::find_slot(tree_node* const&, insert_option)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/hash-table.h:435
0x67cd7a canonical_type_parameter(tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:4536
0x1d69d7f tsubst(tree_node*, tree_node*, int, tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:16298
0x1e7d600 tsubst_function_type
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:15649
0x1d689e9 tsubst(tree_node*, tree_node*, int, tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:16468
0x1e7a865 tsubst_function_decl
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:14419
0x202b236 tsubst_template_decl
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:14730
0x1e5be82 tsubst_decl
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:14892
0x1e72315 instantiate_class_template(tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:12338
0x1aa8568 complete_type(tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/typeck.cc:138
0x1aa8402 complete_type_or_maybe_complain(tree_node*, tree_node*, int)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/typeck.cc:151
0x1cab4b2 require_complete_type(tree_node*, int)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/typeck.cc:94
0x1ca483e build_cxx_call(tree_node*, int, tree_node**, int, tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/call.cc:10981
0x84ef64 build_over_call
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/call.cc:10432
0x1d91d09 build_new_method_call(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, tree_node*, int, tree_node**, int)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/call.cc:11703
0x1df5802 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:21314
0x1e1a540 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
        /usr/src/debug/sys-devel/gcc-13.0.1_pre20230416/gcc-13-20230416/gcc/cp/pt.cc:19888
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://bugs.gentoo.org/> for instructions.
```

'g++-13 -O2 -Wall -c ArithmeticSubtermGeneralization.ii' is enough to reproduce.

Reduction in progress.
Comment 1 Sam James 2023-04-17 04:01:06 UTC
Created attachment 54873 [details]
invalid_reduction.ii

meh, the reduction cvise just finished with is invalid, but it does trigger the ICE still. I'll include it and try refine it now.
Comment 2 Andrew Pinski 2023-04-17 05:06:35 UTC
command line that in the end needed to reproduce with the original non-reduced testcase:
-std=c++14  -march=znver3 -O2 -fno-strict-aliasing -Wall

Note you need all of those options to get the ICE.
Comment 3 Andrew Pinski 2023-04-17 05:20:17 UTC
I almost want to say there is some GC issue going on with the original testcase.
When I tried to use topformflat with the source (with all the "^# " lines removed), it no longer ICEs. But then again I did get a note about -flarge-source-files which might causing a warning not to be tried which is exposing the ICE.
Comment 4 Andrew Pinski 2023-04-17 05:24:20 UTC
Anyways I am trying to reduce this using delta with a script which tests if it passes no options (except -Wfatal-errors to speed up the testing); that should reduce it to a valid testcase I hope.
Comment 5 Andrew Pinski 2023-04-17 06:48:24 UTC
>'g++-13 -O2 -Wall -c ArithmeticSubtermGeneralization.ii' is enough to reproduce.

Interesting because it was not for me, but I noticed that removing all of the lines that begin with "#" is able to reproduce without any options only. Anyways my current reproducing script is:
```
if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus -std=c++14 -fno-checking -quiet -Wfatal-errors $1 >& file1.out); then
  exit 1
fi
if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus -std=c++14 -quiet -Wfatal-errors $1 >& file.out); then
  if grep "hashtab_chk_error" file.out >&/dev/null; then
    exit 0
  fi
  exit 1
fi
if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus -std=c++14  -march=znver3 -O2 -fno-strict-aliasing -Wall -quiet -Wfatal-errors $1 >& file1.out); then
  if grep "hashtab_chk_error" file1.out >&/dev/null; then
    exit 0
  fi
  exit 1
fi
```

Yes it is more complex than a standard one would be because I want to reduce it to be a valid testcase (the first run of cc1plus) and then I noticed sometimes it reproduces with slightly different options so test with those.
Hopefully the -fno-checking is enough to force not checking hashtable checking ...
Comment 6 Martin Liška 2023-04-17 07:25:16 UTC
(In reply to Andrew Pinski from comment #5)
> >'g++-13 -O2 -Wall -c ArithmeticSubtermGeneralization.ii' is enough to reproduce.
> 
> Interesting because it was not for me, but I noticed that removing all of
> the lines that begin with "#" is able to reproduce without any options only.
> Anyways my current reproducing script is:
> ```
> if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus
> -std=c++14 -fno-checking -quiet -Wfatal-errors $1 >& file1.out); then
>   exit 1
> fi
> if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus
> -std=c++14 -quiet -Wfatal-errors $1 >& file.out); then
>   if grep "hashtab_chk_error" file.out >&/dev/null; then
>     exit 0
>   fi
>   exit 1
> fi
> if !(~/upstream-gcc/libexec/gcc/x86_64-pc-linux-gnu/13.0.1/cc1plus
> -std=c++14  -march=znver3 -O2 -fno-strict-aliasing -Wall -quiet
> -Wfatal-errors $1 >& file1.out); then
>   if grep "hashtab_chk_error" file1.out >&/dev/null; then
>     exit 0
>   fi
>   exit 1
> fi
> ```
> 
> Yes it is more complex than a standard one would be because I want to reduce
> it to be a valid testcase (the first run of cc1plus) and then I noticed
> sometimes it reproduces with slightly different options so test with those.
> Hopefully the -fno-checking is enough to force not checking hashtable
> checking ...

You can achieve result with the following command with C-Vise:
cvise -c 'timeout 5 g++ -std=c++14  -march=znver3 -O2 -fno-strict-aliasing -Wall ArithmeticSubtermGeneralization.ii -w -Wfatal-errors 2>&1 | grep hashtab_chk_error && timeout 5 g++-13 ArithmeticSubtermGeneralization.ii -c -Wfatal-errors -w' ArithmeticSubtermGeneralization.ii

I'm currently reducing that right now..
Comment 7 Andrew Pinski 2023-04-17 07:35:26 UTC
(In reply to Martin Liška from comment #6)
> You can achieve result with the following command with C-Vise:
> cvise -c 'timeout 5 g++ -std=c++14  -march=znver3 -O2 -fno-strict-aliasing
> -Wall ArithmeticSubtermGeneralization.ii -w -Wfatal-errors 2>&1 | grep
> hashtab_chk_error && timeout 5 g++-13 ArithmeticSubtermGeneralization.ii -c
> -Wfatal-errors -w' ArithmeticSubtermGeneralization.ii
> 
> I'm currently reducing that right now..

No that is different because it only says if it reproduces with those specific options which it does not have to.

timeout 5 g++ -std=c++14 -w -Wfatal-errors -fno-checking && (( timeout 5 g++ -std=c++14 ArithmeticSubtermGeneralization.ii -w -Wfatal-errors 2>&1 | grep  hashtab_chk_error) || (timeout 5 g++ -std=c++14  -march=znver3 -O2 -fno-strict-aliasing -Wall ArithmeticSubtermGeneralization.ii -w -Wfatal-errors 2>&1 | grep  hashtab_chk_error))

is the more correct way of reducing it similar to my script :).
Comment 8 Martin Liška 2023-04-17 09:00:29 UTC
> is the more correct way of reducing it similar to my script :).

Sure, this is better not to rely on specific options.

Anyway, reduced to:

$ cat ArithmeticSubtermGeneralization.ii
template <class> using no_ref_t = int *;
template <class Arr, template <class> class ref_t>
struct ArrayishObjectIterator {
  typedef ref_t<typename Arr::_ElementType> _ElementType;
};
struct MappingIterator {
  typedef int *_ElementType;
};
template <class Iter> struct IterTraits {
  IterTraits<MappingIterator> map() {}
  template <template <class> class Container>
  Container<typename Iter::_ElementType> collect();
};
struct Clause {
  typedef int _ElementType;
};
IterTraits<ArrayishObjectIterator<Clause, no_ref_t>> __trans_tmp_3;

$ g++ ArithmeticSubtermGeneralization.ii -c -w
hash table checking failed: equal operator returns true for a pair of values with a different hash value
ArithmeticSubtermGeneralization.ii: In instantiation of ‘struct IterTraits<ArrayishObjectIterator<Clause, no_ref_t> >’:
ArithmeticSubtermGeneralization.ii:17:54:   required from here
ArithmeticSubtermGeneralization.ii:12:42: internal compiler error: in hashtab_chk_error, at hash-table.cc:137
   12 |   Container<typename Iter::_ElementType> collect();
      |                                          ^~~~~~~
0x92d1bd hashtab_chk_error()
	/home/marxin/Programming/gcc/gcc/hash-table.cc:137
0xb668b2 hash_table<ctp_hasher, false, xcallocator>::verify(tree_node* const&, unsigned int)
	/home/marxin/Programming/gcc/gcc/hash-table.h:1118
0xb668b2 hash_table<ctp_hasher, false, xcallocator>::find_slot_with_hash(tree_node* const&, unsigned int, insert_option)
	/home/marxin/Programming/gcc/gcc/hash-table.h:1046
0xb1ede9 hash_table<ctp_hasher, false, xcallocator>::find_slot(tree_node* const&, insert_option)
	/home/marxin/Programming/gcc/gcc/hash-table.h:435
0xb1ede9 canonical_type_parameter(tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:4536
0xb2e141 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:16298
0xb33018 tsubst_function_type
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:15649
0xb2cb3b tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:16468
0xb4e3b9 tsubst_function_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:14419
0xb51060 tsubst_template_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:14730
0xb2faba tsubst_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:14892
0xb5e566 instantiate_class_template(tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.cc:12338
0xbb0be8 complete_type(tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/typeck.cc:138
0x9d5494 start_decl_1(tree_node*, bool)
	/home/marxin/Programming/gcc/gcc/cp/decl.cc:6002
0x9d5494 start_decl_1(tree_node*, bool)
	/home/marxin/Programming/gcc/gcc/cp/decl.cc:5981
0x9f5507 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
	/home/marxin/Programming/gcc/gcc/cp/decl.cc:5968
0xaf8431 cp_parser_init_declarator
	/home/marxin/Programming/gcc/gcc/cp/parser.cc:22910
0xacf278 cp_parser_simple_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.cc:15403
0xb03bf3 cp_parser_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.cc:15089
0xb0473a cp_parser_toplevel_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.cc:15110
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Comment 9 Martin Liška 2023-04-17 09:21:18 UTC
Started with r13-3292-gc2565a31c1622a.
Comment 10 Jakub Jelinek 2023-04-17 09:58:39 UTC
Slightly cleaned up:

template <class>
using A = int *;
template <class T, template <class> class U>
struct B { typedef U <typename T::type> type; };
struct C { typedef int *type; };
template <class T>
struct D {
  D <C> foo () { return D <C> (); }
  template <template <class> class U>
  U <typename T::type> bar ();
};
struct E { typedef int type; };
D <B <E, A>> d;

As no floating point types are involved, I think this had to be latent before.
Comment 11 Jakub Jelinek 2023-04-17 11:00:48 UTC
Better don't reuse U for two different parameters:
template <class>
using A = int *;
template <class T, template <class> class U>
struct B { typedef U <typename T::type> type; };
struct C { typedef int *type; };
template <class T>
struct D {
  D <C> foo () { return D <C> (); }
  template <template <class> class V>
  V <typename T::type> bar ();
};
struct E { typedef int type; };
D <B <E, A>> d;

The ICE is on
(gdb) p debug_tree (*entry)
 <bound_template_template_parm 0x7fffea2f01f8 V type_0 type_6 VOID
    align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea2f01f8
    args <tree_vec 0x7fffea2f10c0 length:1
        elt:0 <pointer_type 0x7fffea2ed1f8 type type <integer_type 0x7fffea14f5e8 int>
            unsigned DI
            size <integer_cst 0x7fffea12cfc0 constant 64>
            unit-size <integer_cst 0x7fffea12cfd8 constant 8>
            align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea157b28>>
   index 0 level 1 orig_level 2
    chain <type_decl 0x7fffea2ebed8 V>>
$14 = void
(gdb) p debug_tree (comparable)
 <bound_template_template_parm 0x7fffea2f8540 V type_0 type_6 VOID
    align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea2eda80
    args <tree_vec 0x7fffea2f16a0 length:1
        elt:0 <pointer_type 0x7fffea2f87e0 type type <integer_type 0x7fffea14f5e8 int>
            unsigned DI
            size <integer_cst 0x7fffea12cfc0 constant 64>
            unit-size <integer_cst 0x7fffea12cfd8 constant 8>
            align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea157b28>>
   index 0 level 1 orig_level 2
    chain <type_decl 0x7fffea2f2850 V>>
$15 = void
Both of these BOUND_TEMPLATE_TEMPLARE_PARMs are created in
#4  0x0000000001462bbc in copy_node (node=<bound_template_template_parm 0x7fffea2eda80 V>) at ../../gcc/tree.cc:1334
#5  0x00000000005d9d68 in copy_type (type=<bound_template_template_parm 0x7fffea2eda80 V>) at ../../gcc/cp/lex.cc:1067
#6  0x0000000000767b5f in tsubst (t=<bound_template_template_parm 0x7fffea2eda80 V>, args=<tree_vec 0x7fffea2cec60>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>)
    at ../../gcc/cp/pt.cc:16262
#7  0x0000000000765155 in tsubst_function_type (t=<method_type 0x7fffea2edbd0>, args=<tree_vec 0x7fffea2cec60>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>)
    at ../../gcc/cp/pt.cc:15649
#8  0x00000000007687af in tsubst (t=<method_type 0x7fffea2edbd0>, args=<tree_vec 0x7fffea2cec60>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>) at ../../gcc/cp/pt.cc:16468
#9  0x000000000075afd2 in tsubst_function_decl (t=<function_decl 0x7fffea2da700 bar>, args=<tree_vec 0x7fffea2cec60>, complain=1, lambda_fntype=<tree 0x0>)
    at ../../gcc/cp/pt.cc:14419
#10 0x000000000075df67 in tsubst_template_decl (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2cec60>, complain=1, lambda_fntype=<tree 0x0>)
    at ../../gcc/cp/pt.cc:14730
#11 0x00000000007613a1 in tsubst_decl (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2cec60>, complain=1) at ../../gcc/cp/pt.cc:14892
#12 0x0000000000765f8e in tsubst (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2cec60>, complain=1, in_decl=<tree 0x0>) at ../../gcc/cp/pt.cc:15933
and
#4  0x0000000001462bbc in copy_node (node=<bound_template_template_parm 0x7fffea2eda80 V>) at ../../gcc/tree.cc:1334
#5  0x00000000005d9d68 in copy_type (type=<bound_template_template_parm 0x7fffea2eda80 V>) at ../../gcc/cp/lex.cc:1067
#6  0x0000000000767b5f in tsubst (t=<bound_template_template_parm 0x7fffea2eda80 V>, args=<tree_vec 0x7fffea2f1400>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>)
    at ../../gcc/cp/pt.cc:16262
#7  0x0000000000765155 in tsubst_function_type (t=<method_type 0x7fffea2edbd0>, args=<tree_vec 0x7fffea2f1400>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>)
    at ../../gcc/cp/pt.cc:15649
#8  0x00000000007687af in tsubst (t=<method_type 0x7fffea2edbd0>, args=<tree_vec 0x7fffea2f1400>, complain=1, in_decl=<function_decl 0x7fffea2da700 bar>) at ../../gcc/cp/pt.cc:16468
#9  0x000000000075afd2 in tsubst_function_decl (t=<function_decl 0x7fffea2da700 bar>, args=<tree_vec 0x7fffea2f1400>, complain=1, lambda_fntype=<tree 0x0>)
    at ../../gcc/cp/pt.cc:14419
#10 0x000000000075df67 in tsubst_template_decl (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2f1400>, complain=1, lambda_fntype=<tree 0x0>)
    at ../../gcc/cp/pt.cc:14730
#11 0x00000000007613a1 in tsubst_decl (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2f1400>, complain=1) at ../../gcc/cp/pt.cc:14892
#12 0x0000000000765f8e in tsubst (t=<template_decl 0x7ffff7ffa700 bar>, args=<tree_vec 0x7fffea2f1400>, complain=1, in_decl=<tree 0x0>) at ../../gcc/cp/pt.cc:15933
The first one being bar instantiation with C arg, the latter with B arg.

When hashing those, the difference is in
    if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
      val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val);
which is a TREE_VEC containing
 <pointer_type 0x7fffea2ed1f8 type
    type <integer_type 0x7fffea14f5e8 int public type_6 SI
        size <integer_cst 0x7fffea151210 constant 32>
        unit-size <integer_cst 0x7fffea151228 constant 4>
        align:32 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea14f5e8 precision:32 min <integer_cst 0x7fffea1511c8 -2147483648> max <integer_cst 0x7fffea1511e0 2147483647>
        pointer_to_this <pointer_type 0x7fffea157b28>>
    unsigned DI
    size <integer_cst 0x7fffea12cfc0 type <integer_type 0x7fffea14f0a8 bitsizetype> constant 64>
    unit-size <integer_cst 0x7fffea12cfd8 type <integer_type 0x7fffea14f000 sizetype> constant 8>
    align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea157b28>
in one case and
 <pointer_type 0x7fffea2f87e0 type
    type <integer_type 0x7fffea14f5e8 int public type_6 SI
        size <integer_cst 0x7fffea151210 constant 32>
        unit-size <integer_cst 0x7fffea151228 constant 4>
        align:32 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea14f5e8 precision:32 min <integer_cst 0x7fffea1511c8 -2147483648> max <integer_cst 0x7fffea1511e0 2147483647>
        pointer_to_this <pointer_type 0x7fffea157b28>>
    unsigned DI
    size <integer_cst 0x7fffea12cfc0 type <integer_type 0x7fffea14f0a8 bitsizetype> constant 64>
    unit-size <integer_cst 0x7fffea12cfd8 type <integer_type 0x7fffea14f000 sizetype> constant 8>
    align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffea157b28>
in another.
In the second case it triggers
      if (tree ats = alias_template_specialization_p (arg, nt_transparent))
        {
          // We want an alias specialization that survived strip_typedefs
          // to hash differently from its TYPE_CANONICAL, to avoid hash
          // collisions that compare as different in template_args_equal.
          // These could be dependent specializations that strip_typedefs
          // left alone, or untouched specializations because
          // coerce_template_parms returns the unconverted template
          // arguments if it sees incomplete argument packs.
          tree ti = TYPE_ALIAS_TEMPLATE_INFO (ats);
          return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
        }
in iterative_hash_template_arg, while in the first case it doesn't and it gets
        default:
          if (tree canonical = TYPE_CANONICAL (arg))
            val = iterative_hash_object (TYPE_HASH (canonical), val);
and so they hash differently.  But apparently structural_comptypes thinks they are equal.
Comment 12 Patrick Palka 2023-04-17 12:44:41 UTC
I suppose we're just neglecting to canonicalize a bound ttp's substituted args before determining its canonical type.  Adding a call to coerce_template_parms or canonicalize_type_argument seems to fix it:

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fcc8e0d1d57..5ff91414f69 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -16285,9 +16285,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                      return error_mark_node;
                    tree argvec = tsubst (TI_ARGS (tinfo), args,
                                          complain, in_decl);
+                   // this fixes it
+                   tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+                   argvec = coerce_template_parms (tparms, argvec,
+                                                   tmpl, complain);
                    if (argvec == error_mark_node)
                      return error_mark_node;
 
+                   // or this
+                   for (tree& arg : tree_vec_range (argvec))
+                     if (TYPE_P (arg))
+                       arg = canonicalize_type_argument (arg, complain);
+
                    TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r)
                      = build_template_info (tmpl, argvec);
                  }
Comment 13 GCC Commits 2023-04-17 22:52:19 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:2245459c85a3f4cde3d33bf3e4edaff08f3b2404

commit r14-11-g2245459c85a3f4cde3d33bf3e4edaff08f3b2404
Author: Patrick Palka <ppalka@redhat.com>
Date:   Mon Apr 17 18:52:07 2023 -0400

    c++: bound ttp level lowering [PR109531]
    
    Here when level lowering the bound ttp TT<typename T::type> via the
    substitution T=C, we're neglecting to canonicalize (and thereby strip
    of simple typedefs) the substituted template arguments {A<int>} before
    determining the new canonical type via hash table lookup.  This leads to
    a hash mismatch ICE for the two equivalent types TT<int> and TT<A<int>>
    since iterative_hash_template_arg assumes type arguments are already
    canonicalized.
    
    We can fix this by canonicalizing or coercing the substituted arguments
    directly, but seeing as creation and ordinary substitution of bound ttps
    both go through lookup_template_class, which in turn performs the desired
    coercion/canonicalization, it seems preferable to make this code path go
    through lookup_template_class as well.
    
            PR c++/109531
    
    gcc/cp/ChangeLog:
    
            * pt.cc (tsubst) <case BOUND_TEMPLATE_TEMPLATE_PARM>:
            In the level-lowering case just use lookup_template_class
            to rebuild the bound ttp.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/canon-type-20.C: New test.
            * g++.dg/template/ttp36.C: New test.
Comment 14 GCC Commits 2023-04-17 23:21:25 UTC
The releases/gcc-13 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:c895eb11c8c95aa5714fa4043194b1001336567e

commit r13-7208-gc895eb11c8c95aa5714fa4043194b1001336567e
Author: Patrick Palka <ppalka@redhat.com>
Date:   Mon Apr 17 18:52:07 2023 -0400

    c++: bound ttp level lowering [PR109531]
    
    Here when level lowering the bound ttp TT<typename T::type> via the
    substitution T=C, we're neglecting to canonicalize (and thereby strip
    of simple typedefs) the substituted template arguments {A<int>} before
    determining the new canonical type via hash table lookup.  This leads to
    a hash mismatch ICE for the two equivalent types TT<int> and TT<A<int>>
    since iterative_hash_template_arg assumes type arguments are already
    canonicalized.
    
    We can fix this by canonicalizing or coercing the substituted arguments
    directly, but seeing as creation and ordinary substitution of bound ttps
    both go through lookup_template_class, which in turn performs the desired
    coercion/canonicalization, it seems preferable to make this code path go
    through lookup_template_class as well.
    
            PR c++/109531
    
    gcc/cp/ChangeLog:
    
            * pt.cc (tsubst) <case BOUND_TEMPLATE_TEMPLATE_PARM>:
            In the level-lowering case just use lookup_template_class
            to rebuild the bound ttp.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/canon-type-20.C: New test.
            * g++.dg/template/ttp36.C: New test.
    
    (cherry picked from commit 2245459c85a3f4cde3d33bf3e4edaff08f3b2404)
Comment 15 Patrick Palka 2023-04-17 23:24:07 UTC
Fixed for GCC 13.