diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index db5fa9076c3..03359db28e1 100644
--- c/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -2783,11 +2783,7 @@ enum merge_kind
   MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL.  */
 
   MK_type_spec = MK_template_mask,
-  MK_type_tmpl_spec = MK_type_spec | MK_tmpl_tmpl_mask,
-
   MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask,
-  MK_decl_tmpl_spec = MK_decl_spec | MK_tmpl_tmpl_mask,
-
   MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask,
 
   MK_hwm = 0x20
@@ -8062,10 +8058,10 @@ trees_in::decl_value ()
 	{
 	  /* Add to specialization tables now that constraints etc are
 	     added.  */
-	  bool is_decl = (mk & MK_template_mask) && (mk & MK_tmpl_decl_mask);
+	  bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
 
-	  spec.spec = is_decl ? inner : type;
-	  add_mergeable_specialization (is_decl, &spec, decl, spec_flags);
+	  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))
@@ -10229,7 +10225,6 @@ trees_out::get_merge_kind (tree decl, depset *dep)
     case depset::EK_SPECIALIZATION:
       {
 	gcc_checking_assert (dep->is_special ());
-	spec_entry *entry = reinterpret_cast <spec_entry *> (dep->deps[0]);
 
 	if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
 	  /* An block-scope classes of templates are themselves
@@ -10247,13 +10242,8 @@ trees_out::get_merge_kind (tree decl, depset *dep)
 
 	if (TREE_CODE (decl) == TEMPLATE_DECL)
 	  {
-	    tree res = DECL_TEMPLATE_RESULT (decl);
-	    if (!(mk & MK_tmpl_decl_mask))
-	      res = TREE_TYPE (res);
-
-	    if (res == entry->spec)
-	      /* We check we can get back to the template during
-		 streaming.  */
+	    spec_entry *entry = reinterpret_cast <spec_entry *> (dep->deps[0]);
+	    if (TREE_CODE (entry->spec) != TEMPLATE_DECL)
 	      mk = merge_kind (mk | MK_tmpl_tmpl_mask);
 	  }
       }
@@ -10362,15 +10352,14 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 		gcc_assert (match_mergeable_specialization (false, entry)
 			    == TREE_TYPE (existing));
 	      else if (mk & MK_tmpl_tmpl_mask)
-		if (tree ti = DECL_TEMPLATE_INFO (existing))
-		  existing = TI_TEMPLATE (ti);
+		existing = DECL_TI_TEMPLATE (existing);
 	    }
 	  else
 	    {
-	      if (!(mk & MK_tmpl_tmpl_mask))
+	      if (mk & MK_tmpl_tmpl_mask)
+		existing = CLASSTYPE_TI_TEMPLATE (existing);
+	      else
 		existing = TYPE_NAME (existing);
-	      else if (tree ti = CLASSTYPE_TEMPLATE_INFO (existing))
-		existing = TI_TEMPLATE (ti);
 	    }
 
 	  /* The walkabout should have found ourselves.  */
@@ -10677,13 +10666,6 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
       DECL_NAME (inner) = DECL_NAME (decl);
       DECL_CONTEXT (inner) = DECL_CONTEXT (decl);
 
-      spec.spec = decl;
-      if (mk & MK_tmpl_tmpl_mask)
-	{
-	  if (inner == decl)
-	    return error_mark_node;
-	  spec.spec = inner;
-	}
       tree constr = NULL_TREE;
       bool is_decl = mk & MK_tmpl_decl_mask;
       if (is_decl)
@@ -10694,13 +10676,10 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	      if (constr)
 		set_constraints (inner, constr);
 	    }
+	  spec.spec = (mk & MK_tmpl_tmpl_mask) ? inner : decl;
 	}
       else
-	{
-	  if (mk == MK_type_spec && inner != decl)
-	    return error_mark_node;
-	  spec.spec = type;
-	}
+	spec.spec = type;
       existing = match_mergeable_specialization (is_decl, &spec);
       if (constr)
 	/* We'll add these back later, if this is the new decl.  */
@@ -10712,24 +10691,15 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	{
 	  /* A declaration specialization.  */
 	  if (mk & MK_tmpl_tmpl_mask)
-	    if (tree ti = DECL_TEMPLATE_INFO (existing))
-	      {
-		tree tmpl = TI_TEMPLATE (ti);
-		if (DECL_TEMPLATE_RESULT (tmpl) == existing)
-		  existing = tmpl;
-	      }
+	    existing = DECL_TI_TEMPLATE (existing);
 	}
       else
 	{
 	  /* A type specialization.  */
-	  if (!(mk & MK_tmpl_tmpl_mask))
+	  if (mk & MK_tmpl_tmpl_mask)
+	    existing = CLASSTYPE_TI_TEMPLATE (existing);
+	  else
 	    existing = TYPE_NAME (existing);
-	  else if (tree ti = CLASSTYPE_TEMPLATE_INFO (existing))
-	    {
-	      tree tmpl = TI_TEMPLATE (ti);
-	      if (DECL_TEMPLATE_RESULT (tmpl) == TYPE_NAME (existing))
-		existing = tmpl;
-	    }
 	}
     }
   else if (mk == MK_unique)
diff --git c/gcc/testsuite/g++.dg/modules/pr99528.h w/gcc/testsuite/g++.dg/modules/pr99528.h
new file mode 100644
index 00000000000..ea5d60f489a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99528.h
@@ -0,0 +1,9 @@
+template<typename _Tp>
+class new_allocator
+{
+public:
+  template<typename _Tp1>
+  new_allocator(const new_allocator<_Tp1>&) noexcept { }
+};
+
+extern template class new_allocator<char>;
diff --git c/gcc/testsuite/g++.dg/modules/pr99528_a.H w/gcc/testsuite/g++.dg/modules/pr99528_a.H
new file mode 100644
index 00000000000..08f766bd879
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99528_a.H
@@ -0,0 +1,4 @@
+// PR 99528, ICE with template/function mismatch
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+#include "pr99528.h"
diff --git c/gcc/testsuite/g++.dg/modules/pr99528_b.H w/gcc/testsuite/g++.dg/modules/pr99528_b.H
new file mode 100644
index 00000000000..48c4b4d9741
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99528_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+#include "pr99528.h"
+
diff --git c/gcc/testsuite/g++.dg/modules/pr99528_c.C w/gcc/testsuite/g++.dg/modules/pr99528_c.C
new file mode 100644
index 00000000000..ca8d8677ce1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99528_c.C
@@ -0,0 +1,3 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+import "pr99528_a.H";
+import "pr99528_b.H";
