This failure was ultimately from incorrect handling of alias templates, but required a specific set of occurrences to happen in the specialization hash table. This cleans up the specialization streaming to add alias instantiations at the same point as other instantiations. I also removed some unneeded global variables dealing with mapping of duplicate decl contexts.

        PR c++/99425
        gcc/cp/
        * cp-tree.h (map_context_from, map_context_to): Delete.
        (add_mergeable_specialization): Add is_alias parm.
        * pt.c (add_mergeable_specialization): Add is_alias parm, add them.
        * module.cc (map_context_from, map_context_to): Delete.
        (trees_in::decl_value): Add specializations later, adjust call.
        Drop useless alias lookup. Set duplicate fn parm context.
        (check_mergeable_decl): Drop context mapping.
        (trees_in::is_matching_decl): Likewise.
        (trees_in::read_function_def): Drop parameter context adjustment
        here.
        gcc/testsuite/
        * g++.dg/modules/pr99425-1.h: New.
        * g++.dg/modules/pr99425-1_a.H: New.
        * g++.dg/modules/pr99425-1_b.H: New.
        * g++.dg/modules/pr99425-1_c.C: New.
        * g++.dg/modules/pr99425-2_a.X: New.
        * g++.dg/modules/pr99425-2_b.X: New.
        * g++.dg/template/pr99425.C: New.

--
Nathan Sidwell
diff --git c/gcc/cp/cp-tree.h w/gcc/cp/cp-tree.h
index 81ff375f8a5..e68e3905f80 100644
--- c/gcc/cp/cp-tree.h
+++ w/gcc/cp/cp-tree.h
@@ -5444,10 +5444,6 @@ extern int comparing_specializations;
    FIXME we should always do this except during deduction/ordering.  */
 extern int comparing_dependent_aliases;
 
-/* When comparing specializations permit context _FROM to match _TO.  */
-extern tree map_context_from;
-extern tree map_context_to;
-
 /* In parser.c.  */
 
 /* Nonzero if we are parsing an unevaluated operand: an operand to
@@ -7241,7 +7237,8 @@ extern void walk_specializations		(bool,
 						 void *);
 extern tree match_mergeable_specialization	(bool is_decl, spec_entry *);
 extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
-extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
+extern void add_mergeable_specialization        (bool is_decl, bool is_alias,
+						 spec_entry *,
 						 tree outer, unsigned);
 extern tree add_outermost_template_args		(tree, tree);
 extern tree add_extra_args			(tree, tree);
diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index 6dbdc926cb4..2b529d80499 100644
--- c/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -279,11 +279,6 @@ static inline tree identifier (const cpp_hashnode *node)
   return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast<cpp_hashnode *> (node)));
 }
 
-/* During duplicate detection we need to tell some comparators that
-   these are equivalent.  */
-tree map_context_from;
-tree map_context_to;
-
 /* Id for dumping module information.  */
 int module_dump_id;
 
@@ -8074,16 +8069,6 @@ trees_in::decl_value ()
 
       if (spec.spec)
 	set_constraints (decl, spec.spec);
-      if (mk & MK_template_mask
-	  || mk == MK_partial)
-	{
-	  /* Add to specialization tables now that constraints etc are
-	     added.  */
-	  bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
-
-	  spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
-	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
-	}
 
       if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl))
 	{
@@ -8111,28 +8096,25 @@ trees_in::decl_value ()
 	/* Set the TEMPLATE_DECL's type.  */
 	TREE_TYPE (decl) = TREE_TYPE (inner);
 
+      if (mk & MK_template_mask
+	  || mk == MK_partial)
+	{
+	  /* Add to specialization tables now that constraints etc are
+	     added.  */
+	  bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
+
+	  spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
+	  add_mergeable_specialization (!is_type,
+					!is_type && mk & MK_tmpl_alias_mask,
+					&spec, decl, spec_flags);
+	}
+
       if (NAMESPACE_SCOPE_P (decl)
 	  && (mk == MK_named || mk == MK_unique
 	      || mk == MK_enum || mk == MK_friend_spec)
 	  && !(VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)))
 	add_module_namespace_decl (CP_DECL_CONTEXT (decl), decl);
 
-      /* The late insertion of an alias here or an implicit member
-         (next block), is ok, because we ensured that all imports were
-         loaded up before we started this cluster.  Thus an insertion
-         from some other import cannot have happened between the
-         merged insertion above and these insertions down here.  */
-      if (mk == MK_alias_spec)
-	{
-	  /* Insert into type table.  */
-	  tree ti = DECL_TEMPLATE_INFO (inner);
-	  spec_entry elt = 
-	    {TI_TEMPLATE (ti), TI_ARGS (ti), TREE_TYPE (inner)};
-	  tree texist = match_mergeable_specialization (false, &elt);
-	  if (texist)
-	    set_overrun ();
-	}
-
       if (DECL_ARTIFICIAL (decl)
 	  && TREE_CODE (decl) == FUNCTION_DECL
 	  && !DECL_TEMPLATE_INFO (decl)
@@ -8176,6 +8158,14 @@ trees_in::decl_value ()
       if (!is_matching_decl (existing, decl, is_typedef))
 	unmatched_duplicate (existing);
 
+      if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+	{
+	  tree e_inner = STRIP_TEMPLATE (existing);
+	  for (auto parm = DECL_ARGUMENTS (inner);
+	       parm; parm = DECL_CHAIN (parm))
+	    DECL_CONTEXT (parm) = e_inner;
+	}
+
       /* And our result is the existing node.  */
       decl = existing;
     }
@@ -8186,7 +8176,7 @@ trees_in::decl_value ()
       if (!e)
 	{
 	  spec.spec = inner;
-	  add_mergeable_specialization (true, &spec, decl, spec_flags);
+	  add_mergeable_specialization (true, false, &spec, decl, spec_flags);
 	}
       else if (e != existing)
 	set_overrun ();
@@ -10378,8 +10368,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	    {
 	      if (mk & MK_tmpl_alias_mask)
 		/* It should be in both tables.  */
-		gcc_assert (match_mergeable_specialization (false, entry)
-			    == TREE_TYPE (existing));
+		gcc_checking_assert
+		  (match_mergeable_specialization (false, entry)
+		   == TREE_TYPE (existing));
 	      else if (mk & MK_tmpl_tmpl_mask)
 		existing = DECL_TI_TEMPLATE (existing);
 	    }
@@ -10392,7 +10383,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	    }
 
 	  /* The walkabout should have found ourselves.  */
-	  gcc_assert (existing == decl);
+	  gcc_checking_assert (existing == decl);
 	}
     }
   else if (mk != MK_unique)
@@ -10622,8 +10613,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
 	  break;
 
 	case FUNCTION_DECL:
-	  map_context_from = d_inner;
-	  map_context_to = m_inner;
 	  if (tree m_type = TREE_TYPE (m_inner))
 	    if ((!key.ret
 		 || same_type_p (key.ret, fndecl_declared_return_type (m_inner)))
@@ -10647,7 +10636,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
 		if (cp_tree_equal (key.constraints, m_reqs))
 		  found = match;
 	      }
-	  map_context_from = map_context_to = NULL_TREE;
 	  break;
 
 	case TYPE_DECL:
@@ -11022,12 +11010,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
       gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
     }
 
-  gcc_checking_assert (!map_context_from);
-  /* This mapping requres the new decl on the lhs and the existing
-     entity on the rhs of the comparitors below.  */
-  map_context_from = d_inner;
-  map_context_to = e_inner;
-
   if (TREE_CODE (d_inner) == FUNCTION_DECL)
     {
       tree e_ret = fndecl_declared_return_type (existing);
@@ -11104,7 +11086,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
   else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing)))
     {
     mismatch:
-      map_context_from = map_context_to = NULL_TREE;
       if (DECL_IS_UNDECLARED_BUILTIN (existing))
 	/* Just like duplicate_decls, presum the user knows what
 	   they're doing in overriding a builtin.   */
@@ -11121,8 +11102,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
 	}
     }
 
-  map_context_from = map_context_to = NULL_TREE;
-
   if (DECL_IS_UNDECLARED_BUILTIN (existing)
       && !DECL_IS_UNDECLARED_BUILTIN (decl))
     {
@@ -11463,10 +11442,6 @@ trees_in::read_function_def (tree decl, tree maybe_template)
   tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl));
   bool installing = maybe_dup && !DECL_SAVED_TREE (decl);
 
-  if (maybe_dup)
-    for (auto parm = DECL_ARGUMENTS (maybe_dup); parm; parm = DECL_CHAIN (parm))
-      DECL_CONTEXT (parm) = decl;
-
   if (int wtag = i ())
     {
       int tag = 1;
@@ -12881,10 +12856,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
 			   || DECL_CLASS_TEMPLATE_P (entry->tmpl));
 
        /* Only alias templates can appear in both tables (and
-	  if they're in the type table they must also be in the decl table).  */
+	  if they're in the type table they must also be in the decl
+	  table).  */
        gcc_checking_assert
 	 (!match_mergeable_specialization (true, entry)
-	  == (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl)));
+	  == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
     }
   else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
     gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
diff --git c/gcc/cp/pt.c w/gcc/cp/pt.c
index 5e485f10d19..3f05737f17c 100644
--- c/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -30008,25 +30008,41 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
    get_mergeable_specialization_flags.  */
 
 void
-add_mergeable_specialization (bool decl_p, spec_entry *elt,
+add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
 			      tree decl, unsigned flags)
 {
-  hash_table<spec_hasher> *specializations
-    = decl_p ? decl_specializations : type_specializations;
-
   hashval_t hash = spec_hasher::hash (elt);
-  auto *slot = specializations->find_slot_with_hash (elt, hash, INSERT);
-
-  /* We don't distinguish different constrained partial type
-     specializations, so there could be duplicates.  Everything else
-     must be new.   */
-  if (!(flags & 2 && *slot))
+  if (decl_p)
     {
-      gcc_checking_assert (!*slot);
+      auto *slot = decl_specializations->find_slot_with_hash (elt, hash, INSERT);
 
+      gcc_checking_assert (!*slot);
       auto entry = ggc_alloc<spec_entry> ();
       *entry = *elt;
       *slot = entry;
+
+      if (alias_p)
+	{
+	  elt->spec = TREE_TYPE (elt->spec);
+	  gcc_checking_assert (elt->spec);
+	}
+    }
+
+  if (!decl_p || alias_p)
+    {
+      auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
+
+      /* We don't distinguish different constrained partial type
+	 specializations, so there could be duplicates.  Everything else
+	 must be new.   */
+      if (!(flags & 2 && *slot))
+	{
+	  gcc_checking_assert (!*slot);
+
+	  auto entry = ggc_alloc<spec_entry> ();
+	  *entry = *elt;
+	  *slot = entry;
+	}
     }
 
   if (flags & 1)
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-1.h w/gcc/testsuite/g++.dg/modules/pr99425-1.h
new file mode 100644
index 00000000000..de167a64331
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-1.h
@@ -0,0 +1,11 @@
+template<typename T>
+struct make_signed 
+{
+  using type = int;
+};
+
+template<typename S>
+using make_signed_t = typename make_signed<S>::type;
+
+template<typename U>
+auto ssize (U &parm) -> make_signed_t<decltype(parm.call())>;
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-1_a.H w/gcc/testsuite/g++.dg/modules/pr99425-1_a.H
new file mode 100644
index 00000000000..6117d4a182c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-1_a.H
@@ -0,0 +1,4 @@
+// PR 99425 alias dependent specializations
+// { dg-additional-options {-fmodule-header} }
+// { dg-module-cmi {} }
+#include "pr99425-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-1_b.H w/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
new file mode 100644
index 00000000000..98303a0c687
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodule-header -fdump-lang-module-alias} }
+// { dg-module-cmi {} }
+
+#include "pr99425-1.h"
+
+import "pr99425-1_a.H";
+
+struct Cont
+{
+  int call ();
+};
+
+inline void widget (Cont parm)
+{
+  ssize (parm);
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s alias spec merge key \(new\) type_decl:'::make_signed_t'\n  ...  Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::make_signed'\n  Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
+
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-1_c.C w/gcc/testsuite/g++.dg/modules/pr99425-1_c.C
new file mode 100644
index 00000000000..28ef3a1ff30
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-1_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
+import "pr99425-1_a.H";
+import "pr99425-1_b.H";
+
+void frob (Cont parm)
+{
+  ssize (parm);
+}
+
+// { dg-final { scan-lang-dump {Read:-1's named merge key \(new\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-2_a.X w/gcc/testsuite/g++.dg/modules/pr99425-2_a.X
new file mode 100644
index 00000000000..9a44dc33567
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-2_a.X
@@ -0,0 +1,7 @@
+// PR 99425 template aliases can cause equivalences in the hash
+// tables, and for extra excitement be reordered on rehash.
+
+// { dg-additional-options {-x c++-system-header stdexcept -fmodules-ts} }
+// { dg-prune-output {linker input file unused} }
+
+No! DO NOT COMPILE;
diff --git c/gcc/testsuite/g++.dg/modules/pr99425-2_b.X w/gcc/testsuite/g++.dg/modules/pr99425-2_b.X
new file mode 100644
index 00000000000..5e453542cd1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99425-2_b.X
@@ -0,0 +1,4 @@
+// { dg-additional-options {-x c++-system-header mutex -fmodules-ts} }
+// { dg-prune-output {linker input file unused} }
+
+No! DO NOT COMPILE;
diff --git c/gcc/testsuite/g++.dg/template/pr99425.C w/gcc/testsuite/g++.dg/template/pr99425.C
new file mode 100644
index 00000000000..fd49c86b74c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/template/pr99425.C
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++20 } }
+// a potential fix for 99425 generated an ICE here.
+
+template<typename _Tp>
+struct is_nothrow_destructible;
+
+template<typename _Tp>
+struct common_reference;
+
+template<typename _Tp>
+concept same_as
+  = true;
+
+template<typename _Sent, typename _Iter>
+concept sentinel_for
+  = same_as<common_reference<_Sent>>
+  && is_nothrow_destructible<_Iter>::value;
+
+template<typename _Tp>
+concept __member_end
+  = requires (_Tp& __t)
+  {
+    { true }
+    -> sentinel_for<decltype(__t)>;
+  };
+
+template<typename _Tp>
+concept __adl_end
+  = requires (_Tp& __t)
+  {
+    { true }
+    -> sentinel_for<decltype(__t)>;
+  };
+
+template<typename _Tp>
+requires __member_end<_Tp> || __adl_end<_Tp>
+  void
+  Bar (_Tp&& __t)
+{
+}
+
+void test03 ()
+{
+  Bar (1); // { dg-error "no matching function" }
+}

Reply via email to