diff mbox series

c++/modules: member alias tmpl partial inst [PR103994]

Message ID 20240304222654.1511204-1-ppalka@redhat.com
State New
Headers show
Series c++/modules: member alias tmpl partial inst [PR103994] | expand

Commit Message

Patrick Palka March 4, 2024, 10:26 p.m. UTC
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

Alias templates are weird in that their specializations can appear in
both decl_specializations and type_specializations.  They appear in the
latter only at parse time via finish_template_type.  This should probably
be revisited in GCC 15 since it seems sufficient to store them only in
decl_specializations.  In the meantime, the below patch makes sure that
if a such a specialization is stored in both tables then we don't
overwrite in the type code path the TEMPLATE_INFO set by the decl code
path (which always runs first).  That's because tsubst_template_decl
during partial instantiation of a member template sets TI_TEMPLATE of
the TYPE_DECL to point to the partially instantiated TEMPLATE_DECL
whereas lookup_template_class wants to always point to the most general
template.  This ends up confusing modules in the testcase below for the
partial instantiation A<B>::key_arg<T> -- we decide to stream the
TYPE_DECL for this partial instantiation separately from the
corresponding TEMPLATE_DECL due to this incorrect TI_TEMPLATE setting.

	PR c++/103994

gcc/cp/ChangeLog:

	* pt.cc (lookup_template_class): Don't overwrite TEMPLATE_INFO
	for an alias template specialization.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/tpl-alias-2_a.H: New test.
	* g++.dg/modules/tpl-alias-2_b.C: New test.
---
 gcc/cp/pt.cc                                 |  7 ++++++-
 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 +++++++++++++++
 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C

Comments

Jason Merrill March 7, 2024, 3:55 a.m. UTC | #1
On 3/4/24 17:26, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk?
> 
> -- >8 --
> 
> Alias templates are weird in that their specializations can appear in
> both decl_specializations and type_specializations.  They appear in the
> latter only at parse time via finish_template_type.  This should probably
> be revisited in GCC 15 since it seems sufficient to store them only in
> decl_specializations.

It looks like most all of lookup_template_class is wrong for alias 
templates.

Can we move the alias template handling up higher and unconditionally 
return the result of tsubst?

Jason
Patrick Palka March 7, 2024, 4:06 p.m. UTC | #2
On Wed, 6 Mar 2024, Jason Merrill wrote:

> On 3/4/24 17:26, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > -- >8 --
> > 
> > Alias templates are weird in that their specializations can appear in
> > both decl_specializations and type_specializations.  They appear in the
> > latter only at parse time via finish_template_type.  This should probably
> > be revisited in GCC 15 since it seems sufficient to store them only in
> > decl_specializations.
> 
> It looks like most all of lookup_template_class is wrong for alias templates.
> 
> Can we move the alias template handling up higher and unconditionally return
> the result of tsubst?

This works nicely (although we have to use instantiate_alias_template
directly instead of tsubst since tsubst would first substitute the
uncoerced arguments into the generic DECL_TI_ARGS which breaks for
for parameter packs).  And it allows for some nice simplifications in
the modules code which had to handle alias template specializations
specially.

Bootstrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++/modules: member alias tmpl partial inst [PR103994]

Alias templates are weird in that their specializations can appear in
both decl_specializations and type_specializations.  They appear in the
type table only at parse time via finish_template_type.  There seems
to be no good reason for this, and the code paths end up stepping over
each other in particular for a partial alias template instantiation such
as A<B>::key_arg<T> in the below modules testcase: the type code path
(lookup_template_class) wants to set TI_TEMPLATE to the most general
template whereas the decl code path (tsubst_template_decl called during
instantiation of A<B>) already set TI_TEMPLATE to the partially
instantiated TEMPLATE_DECL.  This ends up confusing modules which
decides to stream the logically equivalent TYPE_DECL and TEMPLATE_DECL
for this partial alias template instantiation separately.

This patch fixes this by making lookup_template_class dispatch to
instantiatie_alias_template early for alias template specializations.
In turn we now only add such specializations to the decl table and
not also the type table.  This admits some nice simplification in
the modules code which otherwise has to cope with such specializations
appearing in both tables.

	PR c++/103994

gcc/cp/ChangeLog:

	* cp-tree.h (add_mergeable_specialization): Remove is_alias
	parameter.
	* module.cc (depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
	(depset::is_alias): Remove.
	(merge_kind::MK_tmpl_alias_mask): Remove.
	(merge_kind::MK_alias_spec): Remove.
	(merge_kind_name): Remove entries for alias specializations.
	(trees_in::decl_value): Adjust add_mergeable_specialization
	calls.
	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
	Use MK_decl_spec for alias template specializations.
	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
	removal.
	(specialization_add): Don't allow alias templates when !decl_p.
	(depset::hash::add_specializations): Remove now-dead code
	accomodating alias template specializations in the type table.
	* pt.cc (lookup_template_class): Dispatch early to
	instantiate_alias_template for alias templates.  Simplify
	accordingly.
	(add_mergeable_specialization): Remove alias_p parameter and
	simplify accordingly.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
	* g++.dg/modules/tpl-alias-2_a.H: New test.
	* g++.dg/modules/tpl-alias-2_b.C: New test.
---
 gcc/cp/cp-tree.h                             |  3 +-
 gcc/cp/module.cc                             | 50 ++----------
 gcc/cp/pt.cc                                 | 84 ++++++++------------
 gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++
 7 files changed, 69 insertions(+), 96 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4469d965ef0..14895bc6585 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7642,8 +7642,7 @@ 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, bool is_alias,
-						 spec_entry *,
+extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
 						 tree outer, unsigned);
 extern tree add_to_template_args		(tree, tree);
 extern tree add_outermost_template_args		(tree, tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 4ecd6d7c813..cc038ee9cba 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2306,10 +2306,7 @@ private:
     /* The following bits are not independent, but enumerating them is
        awkward.  */
     DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
-    DB_ALIAS_SPEC_BIT,		/* Specialization of an alias template
-				   (in both spec tables).  */
-    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.
-				   */
+    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.  */
     DB_FRIEND_SPEC_BIT,		/* An instantiated template friend.  */
   };
 
@@ -2404,10 +2401,6 @@ public:
   {
     return get_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
   }
-  bool is_alias () const
-  {
-    return get_flag_bit<DB_ALIAS_SPEC_BIT> ();
-  }
   bool is_hidden () const
   {
     return get_flag_bit<DB_HIDDEN_BIT> ();
@@ -2782,13 +2775,11 @@ enum merge_kind
   MK_template_mask = 0x10,  /* A template specialization.  */
 
   MK_tmpl_decl_mask = 0x4, /* In decl table.  */
-  MK_tmpl_alias_mask = 0x2, /* Also in type table  */
 
   MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL.  */
 
   MK_type_spec = MK_template_mask,
   MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask,
-  MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask,
 
   MK_hwm = 0x20
 };
@@ -2806,7 +2797,7 @@ static char const *const merge_kind_name[MK_hwm] =
     NULL, NULL,
 
     "decl spec", "decl tmpl spec",	/* 20,21 decl (template).  */
-    "alias spec", "alias tmpl spec",	/* 22,23 alias (template). */
+    NULL, NULL,
     NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL,
   };
@@ -8306,16 +8297,13 @@ trees_in::decl_value ()
 	{
 	  bool is_type = TREE_CODE (inner) == TYPE_DECL;
 	  spec.spec = is_type ? type : inner;
-	  add_mergeable_specialization (!is_type, false,
-					&spec, decl, spec_flags);
+	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
 	}
       else if (mk & MK_template_mask)
 	{
 	  bool is_type = !(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);
+	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
 	}
 
       if (NAMESPACE_SCOPE_P (decl)
@@ -8392,7 +8380,7 @@ trees_in::decl_value ()
       if (!e)
 	{
 	  spec.spec = inner;
-	  add_mergeable_specialization (true, false, &spec, decl, spec_flags);
+	  add_mergeable_specialization (true, &spec, decl, spec_flags);
 	}
       else if (e != existing)
 	set_overrun ();
@@ -10620,8 +10608,6 @@ trees_out::get_merge_kind (tree decl, depset *dep)
 	  mk = MK_friend_spec;
 	else if (dep->is_type_spec ())
 	  mk = MK_type_spec;
-	else if (dep->is_alias ())
-	  mk = MK_alias_spec;
 	else
 	  mk = MK_decl_spec;
 
@@ -10732,11 +10718,6 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	  gcc_assert (existing);
 	  if (mk & MK_tmpl_decl_mask)
 	    {
-	      if (mk & MK_tmpl_alias_mask)
-		/* It should be in both tables.  */
-		gcc_checking_assert
-		  (same_type_p (match_mergeable_specialization (false, entry),
-				TREE_TYPE (existing)));
 	      if (mk & MK_tmpl_tmpl_mask)
 		existing = DECL_TI_TEMPLATE (existing);
 	    }
@@ -13228,16 +13209,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
 	 heuristic.  We don't attempt to replicate that algorithm, but
 	 observe its behaviour and reproduce it upon read back.  */
 
-       gcc_checking_assert (DECL_ALIAS_TEMPLATE_P (entry->tmpl)
-			   || TREE_CODE (entry->spec) == ENUMERAL_TYPE
+       gcc_checking_assert (TREE_CODE (entry->spec) == ENUMERAL_TYPE
 			   || 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).  */
        gcc_checking_assert
-	 (!match_mergeable_specialization (true, entry)
-	  == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
+	 (!match_mergeable_specialization (true, entry));
     }
   else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
     gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
@@ -13392,17 +13368,7 @@ depset::hash::add_specializations (bool decl_p)
       gcc_checking_assert (!TREE_VISITED (spec));
       depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION);
       if (dep->is_special ())
-	{
-	  /* An already located specialization, this must be the TYPE
-	     corresponding to an alias_decl we found in the decl
-	     table.  */
-	  spec_entry *other = reinterpret_cast <spec_entry *> (dep->deps[0]);
-	  gcc_checking_assert (!decl_p && is_alias && !dep->is_type_spec ());
-	  gcc_checking_assert (other->tmpl == entry->tmpl
-			       && template_args_equal (other->args, entry->args)
-			       && TREE_TYPE (other->spec) == entry->spec);
-	  dep->set_flag_bit<DB_ALIAS_SPEC_BIT> ();
-	}
+	gcc_unreachable ();
       else
 	{
 	  gcc_checking_assert (decl_p || !is_alias);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d73f6d93485..99aa64b1cc3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10055,6 +10055,32 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
       /* Now we should have enough arguments.  */
       gcc_assert (parm_depth == arg_depth);
 
+      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	{
+	  /* The user referred to a specialization of an alias
+	    template represented by GEN_TMPL.
+
+	    [temp.alias]/2 says:
+
+		When a template-id refers to the specialization of an
+		alias template, it is equivalent to the associated
+		type obtained by substitution of its
+		template-arguments for the template-parameters in the
+		type-id of the alias template.  */
+
+	  t = instantiate_alias_template (gen_tmpl, arglist, complain);
+	  /* Note that the call above (by indirectly calling
+	     register_specialization in tsubst_decl) registers the
+	     TYPE_DECL representing the specialization of the alias
+	     template.  So next time someone substitutes ARGLIST for
+	     the template parms into the alias template (GEN_TMPL),
+	     she'll get that TYPE_DECL back.  */
+
+	  if (t == error_mark_node)
+	    return error_mark_node;
+	  return TREE_TYPE (t);
+	}
+
       /* From here on, we're only interested in the most general
 	 template.  */
 
@@ -10120,7 +10146,6 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
          lookup. This prevents redundant checks on previously
          instantiated specializations. */
       if (flag_concepts
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)
 	  && !constraints_satisfied_p (gen_tmpl, arglist))
         {
           if (complain & tf_error)
@@ -10189,31 +10214,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	context = global_namespace;
 
       /* Create the type.  */
-      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
-	{
-	  /* The user referred to a specialization of an alias
-	    template represented by GEN_TMPL.
-
-	    [temp.alias]/2 says:
-
-	        When a template-id refers to the specialization of an
-		alias template, it is equivalent to the associated
-		type obtained by substitution of its
-		template-arguments for the template-parameters in the
-		type-id of the alias template.  */
-
-	  t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl);
-	  /* Note that the call above (by indirectly calling
-	     register_specialization in tsubst_decl) registers the
-	     TYPE_DECL representing the specialization of the alias
-	     template.  So next time someone substitutes ARGLIST for
-	     the template parms into the alias template (GEN_TMPL),
-	     she'll get that TYPE_DECL back.  */
-
-	  if (t == error_mark_node)
-	    return t;
-	}
-      else if (TREE_CODE (template_type) == ENUMERAL_TYPE)
+      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
 	{
 	  if (!is_dependent_type)
 	    {
@@ -10301,8 +10302,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	    }
 	}
 
-      if (OVERLOAD_TYPE_P (t)
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+      if (OVERLOAD_TYPE_P (t))
 	{
 	  static const char *tags[] = {"abi_tag", "may_alias"};
 
@@ -10369,7 +10369,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	{
 	  TREE_VEC_LENGTH (arglist)--;
 	  ++processing_template_decl;
-	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (gen_tmpl));
+	  tree tinfo = TYPE_TEMPLATE_INFO (TREE_TYPE (gen_tmpl));
 	  tree partial_inst_args =
 	    tsubst (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)),
 		    arglist, complain, NULL_TREE);
@@ -10407,17 +10407,9 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	     TEMPLATE_PARM_LEVEL.  */
 	  found = tsubst (gen_tmpl, arglist, tf_none, NULL_TREE);
 	  TREE_VEC_LENGTH (arglist)++;
-	  /* FOUND is either a proper class type, or an alias
-	     template specialization.  In the later case, it's a
-	     TYPE_DECL, resulting from the substituting of arguments
-	     for parameters in the TYPE_DECL of the alias template
-	     done earlier.  So be careful while getting the template
-	     of FOUND.  */
 	  found = (TREE_CODE (found) == TEMPLATE_DECL
 		   ? found
-		   : (TREE_CODE (found) == TYPE_DECL
-		      ? DECL_TI_TEMPLATE (found)
-		      : CLASSTYPE_TI_TEMPLATE (found)));
+		   : CLASSTYPE_TI_TEMPLATE (found));
 
 	  if (DECL_CLASS_TEMPLATE_P (found)
 	      && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
@@ -10447,8 +10439,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 		     DECL_TEMPLATE_INSTANTIATIONS (found));
 
       if (TREE_CODE (template_type) == ENUMERAL_TYPE
-	  && !uses_template_parms (current_nonlambda_scope ())
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	  && !uses_template_parms (current_nonlambda_scope ()))
 	/* Now that the type has been registered on the instantiations
 	   list, we set up the enumerators.  Because the enumeration
 	   constants may involve the enumeration type itself, we make
@@ -31578,8 +31569,8 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
    get_mergeable_specialization_flags.  */
 
 void
-add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
-			      tree decl, unsigned flags)
+add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
+			      unsigned flags)
 {
   hashval_t hash = spec_hasher::hash (elt);
   if (decl_p)
@@ -31590,15 +31581,8 @@ add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
       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)
+  else
     {
       auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
 
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
index 53d28b4ef5e..e75b3129dd3 100644
--- a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
+++ b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
@@ -15,5 +15,5 @@ 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
 
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
index 37002ee9ae1..14a25be586f 100644
--- a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
@@ -6,4 +6,4 @@
 // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
 // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* type_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
 
-// { dg-final { scan-lang-dump {Writing:-[0-9]*'s alias spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
new file mode 100644
index 00000000000..76917f778e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
@@ -0,0 +1,15 @@
+// PR c++/103994
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<class>
+struct A {
+  template<class> using key_arg = int;
+};
+
+struct B {
+  template<class T>
+  void f() {
+    using type = A<B>::key_arg<T>;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
new file mode 100644
index 00000000000..44fa5f42757
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
@@ -0,0 +1,9 @@
+// PR c++/103994
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-alias-2_a.H";
+
+int main() {
+  B b;
+  b.f<int>();
+}
Patrick Palka March 7, 2024, 7:41 p.m. UTC | #3
On Thu, 7 Mar 2024, Patrick Palka wrote:

> On Wed, 6 Mar 2024, Jason Merrill wrote:
> 
> > On 3/4/24 17:26, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > Alias templates are weird in that their specializations can appear in
> > > both decl_specializations and type_specializations.  They appear in the
> > > latter only at parse time via finish_template_type.  This should probably
> > > be revisited in GCC 15 since it seems sufficient to store them only in
> > > decl_specializations.
> > 
> > It looks like most all of lookup_template_class is wrong for alias templates.
> > 
> > Can we move the alias template handling up higher and unconditionally return
> > the result of tsubst?
> 
> This works nicely (although we have to use instantiate_alias_template
> directly instead of tsubst since tsubst would first substitute the
> uncoerced arguments into the generic DECL_TI_ARGS which breaks for
> for parameter packs).  And it allows for some nice simplifications in
> the modules code which had to handle alias template specializations
> specially.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu.
> 
> -- >8 --
> 
> Subject: [PATCH] c++/modules: member alias tmpl partial inst [PR103994]
> 
> Alias templates are weird in that their specializations can appear in
> both decl_specializations and type_specializations.  They appear in the
> type table only at parse time via finish_template_type.  There seems
> to be no good reason for this, and the code paths end up stepping over
> each other in particular for a partial alias template instantiation such
> as A<B>::key_arg<T> in the below modules testcase: the type code path
> (lookup_template_class) wants to set TI_TEMPLATE to the most general
> template whereas the decl code path (tsubst_template_decl called during
> instantiation of A<B>) already set TI_TEMPLATE to the partially
> instantiated TEMPLATE_DECL.  This ends up confusing modules which
> decides to stream the logically equivalent TYPE_DECL and TEMPLATE_DECL
> for this partial alias template instantiation separately.
> 
> This patch fixes this by making lookup_template_class dispatch to
> instantiatie_alias_template early for alias template specializations.
> In turn we now only add such specializations to the decl table and
> not also the type table.  This admits some nice simplification in
> the modules code which otherwise has to cope with such specializations
> appearing in both tables.
> 
> 	PR c++/103994
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-tree.h (add_mergeable_specialization): Remove is_alias
> 	parameter.
> 	* module.cc (depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
> 	(depset::is_alias): Remove.
> 	(merge_kind::MK_tmpl_alias_mask): Remove.
> 	(merge_kind::MK_alias_spec): Remove.
> 	(merge_kind_name): Remove entries for alias specializations.
> 	(trees_in::decl_value): Adjust add_mergeable_specialization
> 	calls.
> 	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
> 	Use MK_decl_spec for alias template specializations.
> 	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
> 	removal.
> 	(specialization_add): Don't allow alias templates when !decl_p.
> 	(depset::hash::add_specializations): Remove now-dead code
> 	accomodating alias template specializations in the type table.
> 	* pt.cc (lookup_template_class): Dispatch early to
> 	instantiate_alias_template for alias templates.  Simplify
> 	accordingly.
> 	(add_mergeable_specialization): Remove alias_p parameter and
> 	simplify accordingly.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
> 	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
> 	* g++.dg/modules/tpl-alias-2_a.H: New test.
> 	* g++.dg/modules/tpl-alias-2_b.C: New test.
> ---
>  gcc/cp/cp-tree.h                             |  3 +-
>  gcc/cp/module.cc                             | 50 ++----------
>  gcc/cp/pt.cc                                 | 84 ++++++++------------
>  gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
>  gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
>  gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
>  gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++
>  7 files changed, 69 insertions(+), 96 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 4469d965ef0..14895bc6585 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7642,8 +7642,7 @@ 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, bool is_alias,
> -						 spec_entry *,
> +extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
>  						 tree outer, unsigned);
>  extern tree add_to_template_args		(tree, tree);
>  extern tree add_outermost_template_args		(tree, tree);
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 4ecd6d7c813..cc038ee9cba 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -2306,10 +2306,7 @@ private:
>      /* The following bits are not independent, but enumerating them is
>         awkward.  */
>      DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */

It seems we don't need DB_ALIAS_TMPL_INST_BIT anymore either, so the
updated patch below removes it too.

-- >8 --

	PR c++/103994

gcc/cp/ChangeLog:

	* cp-tree.h (add_mergeable_specialization): Remove is_alias
	parameter.
	* module.cc (depset::disc_bits::DB_ALIAS_TMPL_INST_BIT): Remove.
	(depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
	(depset::is_alias_tmpl_inst): Remove.
	(depset::is_alias): Remove.
	(merge_kind::MK_tmpl_alias_mask): Remove.
	(merge_kind::MK_alias_spec): Remove.
	(merge_kind_name): Remove entries for alias specializations.
	(trees_out::core_vals) <case TEMPLATE_DECL>: Adjust after
	removing is_alias_tmpl_inst.
	(trees_in::decl_value): Adjust add_mergeable_specialization
	calls.
	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
	Use MK_decl_spec for alias template specializations.
	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
	removal.
	(depset::hash::make_dependency): Adjust after removing
	DB_ALIAS_TMPL_INST_BIT.
	(specialization_add): Don't allow alias templates when !decl_p.
	(depset::hash::add_specializations): Remove now-dead code
	accomodating alias template specializations in the type table.
	* pt.cc (lookup_template_class): Dispatch early to
	instantiate_alias_template for alias templates.  Simplify
	accordingly.
	(add_mergeable_specialization): Remove alias_p parameter and
	simplify accordingly.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
	* g++.dg/modules/tpl-alias-2_a.H: New test.
	* g++.dg/modules/tpl-alias-2_b.C: New test.
---
 gcc/cp/cp-tree.h                             |  3 +-
 gcc/cp/module.cc                             | 86 ++++----------------
 gcc/cp/pt.cc                                 | 84 ++++++++-----------
 gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 ++
 7 files changed, 78 insertions(+), 123 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4469d965ef0..14895bc6585 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7642,8 +7642,7 @@ 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, bool is_alias,
-						 spec_entry *,
+extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
 						 tree outer, unsigned);
 extern tree add_to_template_args		(tree, tree);
 extern tree add_outermost_template_args		(tree, tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 4ecd6d7c813..dfe4536c0ae 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2305,11 +2305,7 @@ private:
     DB_HIDDEN_BIT,		/* A hidden binding.  */
     /* The following bits are not independent, but enumerating them is
        awkward.  */
-    DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
-    DB_ALIAS_SPEC_BIT,		/* Specialization of an alias template
-				   (in both spec tables).  */
-    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.
-				   */
+    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.  */
     DB_FRIEND_SPEC_BIT,		/* An instantiated template friend.  */
   };
 
@@ -2400,14 +2396,6 @@ public:
   {
     return get_flag_bit<DB_UNREACHED_BIT> ();
   }
-  bool is_alias_tmpl_inst () const
-  {
-    return get_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
-  }
-  bool is_alias () const
-  {
-    return get_flag_bit<DB_ALIAS_SPEC_BIT> ();
-  }
   bool is_hidden () const
   {
     return get_flag_bit<DB_HIDDEN_BIT> ();
@@ -2782,13 +2770,11 @@ enum merge_kind
   MK_template_mask = 0x10,  /* A template specialization.  */
 
   MK_tmpl_decl_mask = 0x4, /* In decl table.  */
-  MK_tmpl_alias_mask = 0x2, /* Also in type table  */
 
   MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL.  */
 
   MK_type_spec = MK_template_mask,
   MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask,
-  MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask,
 
   MK_hwm = 0x20
 };
@@ -2806,7 +2792,7 @@ static char const *const merge_kind_name[MK_hwm] =
     NULL, NULL,
 
     "decl spec", "decl tmpl spec",	/* 20,21 decl (template).  */
-    "alias spec", "alias tmpl spec",	/* 22,23 alias (template). */
+    NULL, NULL,
     NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL,
   };
@@ -6356,8 +6342,7 @@ trees_out::core_vals (tree t)
       gcc_checking_assert
       	(TREE_VISITED (((lang_tree_node *)t)->template_decl.arguments));
       gcc_checking_assert
-	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result)
-	 || dep_hash->find_dependency (t)->is_alias_tmpl_inst ());
+	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result));
       if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (t))
 	WT (DECL_CHAIN (t));
       break;
@@ -8306,16 +8291,13 @@ trees_in::decl_value ()
 	{
 	  bool is_type = TREE_CODE (inner) == TYPE_DECL;
 	  spec.spec = is_type ? type : inner;
-	  add_mergeable_specialization (!is_type, false,
-					&spec, decl, spec_flags);
+	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
 	}
       else if (mk & MK_template_mask)
 	{
 	  bool is_type = !(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);
+	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
 	}
 
       if (NAMESPACE_SCOPE_P (decl)
@@ -8392,7 +8374,7 @@ trees_in::decl_value ()
       if (!e)
 	{
 	  spec.spec = inner;
-	  add_mergeable_specialization (true, false, &spec, decl, spec_flags);
+	  add_mergeable_specialization (true, &spec, decl, spec_flags);
 	}
       else if (e != existing)
 	set_overrun ();
@@ -10620,8 +10602,6 @@ trees_out::get_merge_kind (tree decl, depset *dep)
 	  mk = MK_friend_spec;
 	else if (dep->is_type_spec ())
 	  mk = MK_type_spec;
-	else if (dep->is_alias ())
-	  mk = MK_alias_spec;
 	else
 	  mk = MK_decl_spec;
 
@@ -10732,11 +10712,6 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	  gcc_assert (existing);
 	  if (mk & MK_tmpl_decl_mask)
 	    {
-	      if (mk & MK_tmpl_alias_mask)
-		/* It should be in both tables.  */
-		gcc_checking_assert
-		  (same_type_p (match_mergeable_specialization (false, entry),
-				TREE_TYPE (existing)));
 	      if (mk & MK_tmpl_tmpl_mask)
 		existing = DECL_TI_TEMPLATE (existing);
 	    }
@@ -12830,17 +12805,12 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
 	 bindings.  */
       *slot = dep = make_entity (decl, ek, has_def);
 
-      if (TREE_CODE (decl) == TEMPLATE_DECL)
-	{
-	  if (DECL_ALIAS_TEMPLATE_P (decl) && DECL_TEMPLATE_INFO (decl))
-	    dep->set_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
-	  else if (CHECKING_P)
-	    /* The template_result should otherwise not be in the
-	       table, or be an empty redirect (created above).  */
-	    if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false))
-	      gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
-				   && !(*eslot)->deps.length ());
-	}
+      if (CHECKING_P && TREE_CODE (decl) == TEMPLATE_DECL)
+	/* The template_result should otherwise not be in the
+	   table, or be an empty redirect (created above).  */
+	if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false))
+	  gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
+			       && !(*eslot)->deps.length ());
 
       if (ek != EK_USING)
 	{
@@ -13228,16 +13198,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
 	 heuristic.  We don't attempt to replicate that algorithm, but
 	 observe its behaviour and reproduce it upon read back.  */
 
-       gcc_checking_assert (DECL_ALIAS_TEMPLATE_P (entry->tmpl)
-			   || TREE_CODE (entry->spec) == ENUMERAL_TYPE
+       gcc_checking_assert (TREE_CODE (entry->spec) == ENUMERAL_TYPE
 			   || 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).  */
        gcc_checking_assert
-	 (!match_mergeable_specialization (true, entry)
-	  == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
+	 (!match_mergeable_specialization (true, entry));
     }
   else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
     gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
@@ -13293,7 +13258,6 @@ depset::hash::add_specializations (bool decl_p)
       spec_entry *entry = data.pop ();
       tree spec = entry->spec;
       int use_tpl = 0;
-      bool is_alias = false;
       bool is_friend = false;
 
       if (decl_p && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (entry->tmpl))
@@ -13301,13 +13265,7 @@ depset::hash::add_specializations (bool decl_p)
 	   instantiation.  */
 	is_friend = true;
 
-      if (!decl_p && DECL_ALIAS_TEMPLATE_P (entry->tmpl))
-	{
-	  spec = TYPE_NAME (spec);
-	  is_alias = true;
-	}
-
-      if (decl_p || is_alias)
+      if (decl_p)
 	{
 	  if (tree ti = DECL_TEMPLATE_INFO (spec))
 	    {
@@ -13392,20 +13350,10 @@ depset::hash::add_specializations (bool decl_p)
       gcc_checking_assert (!TREE_VISITED (spec));
       depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION);
       if (dep->is_special ())
-	{
-	  /* An already located specialization, this must be the TYPE
-	     corresponding to an alias_decl we found in the decl
-	     table.  */
-	  spec_entry *other = reinterpret_cast <spec_entry *> (dep->deps[0]);
-	  gcc_checking_assert (!decl_p && is_alias && !dep->is_type_spec ());
-	  gcc_checking_assert (other->tmpl == entry->tmpl
-			       && template_args_equal (other->args, entry->args)
-			       && TREE_TYPE (other->spec) == entry->spec);
-	  dep->set_flag_bit<DB_ALIAS_SPEC_BIT> ();
-	}
+	gcc_unreachable ();
       else
 	{
-	  gcc_checking_assert (decl_p || !is_alias);
+	  gcc_checking_assert (decl_p);
 	  if (dep->get_entity_kind () == depset::EK_REDIRECT)
 	    dep = dep->deps[0];
 	  else if (dep->get_entity_kind () == depset::EK_SPECIALIZATION)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d73f6d93485..99aa64b1cc3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10055,6 +10055,32 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
       /* Now we should have enough arguments.  */
       gcc_assert (parm_depth == arg_depth);
 
+      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	{
+	  /* The user referred to a specialization of an alias
+	    template represented by GEN_TMPL.
+
+	    [temp.alias]/2 says:
+
+		When a template-id refers to the specialization of an
+		alias template, it is equivalent to the associated
+		type obtained by substitution of its
+		template-arguments for the template-parameters in the
+		type-id of the alias template.  */
+
+	  t = instantiate_alias_template (gen_tmpl, arglist, complain);
+	  /* Note that the call above (by indirectly calling
+	     register_specialization in tsubst_decl) registers the
+	     TYPE_DECL representing the specialization of the alias
+	     template.  So next time someone substitutes ARGLIST for
+	     the template parms into the alias template (GEN_TMPL),
+	     she'll get that TYPE_DECL back.  */
+
+	  if (t == error_mark_node)
+	    return error_mark_node;
+	  return TREE_TYPE (t);
+	}
+
       /* From here on, we're only interested in the most general
 	 template.  */
 
@@ -10120,7 +10146,6 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
          lookup. This prevents redundant checks on previously
          instantiated specializations. */
       if (flag_concepts
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)
 	  && !constraints_satisfied_p (gen_tmpl, arglist))
         {
           if (complain & tf_error)
@@ -10189,31 +10214,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	context = global_namespace;
 
       /* Create the type.  */
-      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
-	{
-	  /* The user referred to a specialization of an alias
-	    template represented by GEN_TMPL.
-
-	    [temp.alias]/2 says:
-
-	        When a template-id refers to the specialization of an
-		alias template, it is equivalent to the associated
-		type obtained by substitution of its
-		template-arguments for the template-parameters in the
-		type-id of the alias template.  */
-
-	  t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl);
-	  /* Note that the call above (by indirectly calling
-	     register_specialization in tsubst_decl) registers the
-	     TYPE_DECL representing the specialization of the alias
-	     template.  So next time someone substitutes ARGLIST for
-	     the template parms into the alias template (GEN_TMPL),
-	     she'll get that TYPE_DECL back.  */
-
-	  if (t == error_mark_node)
-	    return t;
-	}
-      else if (TREE_CODE (template_type) == ENUMERAL_TYPE)
+      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
 	{
 	  if (!is_dependent_type)
 	    {
@@ -10301,8 +10302,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	    }
 	}
 
-      if (OVERLOAD_TYPE_P (t)
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+      if (OVERLOAD_TYPE_P (t))
 	{
 	  static const char *tags[] = {"abi_tag", "may_alias"};
 
@@ -10369,7 +10369,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	{
 	  TREE_VEC_LENGTH (arglist)--;
 	  ++processing_template_decl;
-	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (gen_tmpl));
+	  tree tinfo = TYPE_TEMPLATE_INFO (TREE_TYPE (gen_tmpl));
 	  tree partial_inst_args =
 	    tsubst (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)),
 		    arglist, complain, NULL_TREE);
@@ -10407,17 +10407,9 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	     TEMPLATE_PARM_LEVEL.  */
 	  found = tsubst (gen_tmpl, arglist, tf_none, NULL_TREE);
 	  TREE_VEC_LENGTH (arglist)++;
-	  /* FOUND is either a proper class type, or an alias
-	     template specialization.  In the later case, it's a
-	     TYPE_DECL, resulting from the substituting of arguments
-	     for parameters in the TYPE_DECL of the alias template
-	     done earlier.  So be careful while getting the template
-	     of FOUND.  */
 	  found = (TREE_CODE (found) == TEMPLATE_DECL
 		   ? found
-		   : (TREE_CODE (found) == TYPE_DECL
-		      ? DECL_TI_TEMPLATE (found)
-		      : CLASSTYPE_TI_TEMPLATE (found)));
+		   : CLASSTYPE_TI_TEMPLATE (found));
 
 	  if (DECL_CLASS_TEMPLATE_P (found)
 	      && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
@@ -10447,8 +10439,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 		     DECL_TEMPLATE_INSTANTIATIONS (found));
 
       if (TREE_CODE (template_type) == ENUMERAL_TYPE
-	  && !uses_template_parms (current_nonlambda_scope ())
-	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	  && !uses_template_parms (current_nonlambda_scope ()))
 	/* Now that the type has been registered on the instantiations
 	   list, we set up the enumerators.  Because the enumeration
 	   constants may involve the enumeration type itself, we make
@@ -31578,8 +31569,8 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
    get_mergeable_specialization_flags.  */
 
 void
-add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
-			      tree decl, unsigned flags)
+add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
+			      unsigned flags)
 {
   hashval_t hash = spec_hasher::hash (elt);
   if (decl_p)
@@ -31590,15 +31581,8 @@ add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
       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)
+  else
     {
       auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
 
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
index 53d28b4ef5e..e75b3129dd3 100644
--- a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
+++ b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
@@ -15,5 +15,5 @@ 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
 
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
index 37002ee9ae1..14a25be586f 100644
--- a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
@@ -6,4 +6,4 @@
 // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
 // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* type_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
 
-// { dg-final { scan-lang-dump {Writing:-[0-9]*'s alias spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
new file mode 100644
index 00000000000..76917f778e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
@@ -0,0 +1,15 @@
+// PR c++/103994
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<class>
+struct A {
+  template<class> using key_arg = int;
+};
+
+struct B {
+  template<class T>
+  void f() {
+    using type = A<B>::key_arg<T>;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
new file mode 100644
index 00000000000..44fa5f42757
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
@@ -0,0 +1,9 @@
+// PR c++/103994
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-alias-2_a.H";
+
+int main() {
+  B b;
+  b.f<int>();
+}
Jason Merrill March 7, 2024, 8:43 p.m. UTC | #4
On 3/7/24 14:41, Patrick Palka wrote:
> On Thu, 7 Mar 2024, Patrick Palka wrote:
> 
>> On Wed, 6 Mar 2024, Jason Merrill wrote:
>>
>>> On 3/4/24 17:26, Patrick Palka wrote:
>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
>>>> OK for trunk?
>>>>
>>>> -- >8 --
>>>>
>>>> Alias templates are weird in that their specializations can appear in
>>>> both decl_specializations and type_specializations.  They appear in the
>>>> latter only at parse time via finish_template_type.  This should probably
>>>> be revisited in GCC 15 since it seems sufficient to store them only in
>>>> decl_specializations.
>>>
>>> It looks like most all of lookup_template_class is wrong for alias templates.
>>>
>>> Can we move the alias template handling up higher and unconditionally return
>>> the result of tsubst?
>>
>> This works nicely (although we have to use instantiate_alias_template
>> directly instead of tsubst since tsubst would first substitute the
>> uncoerced arguments into the generic DECL_TI_ARGS which breaks for
>> for parameter packs).  And it allows for some nice simplifications in
>> the modules code which had to handle alias template specializations
>> specially.
>>
>> Bootstrapped and regtested on x86_64-pc-linux-gnu.
>>
>> -- >8 --
>>
>> Subject: [PATCH] c++/modules: member alias tmpl partial inst [PR103994]
>>
>> Alias templates are weird in that their specializations can appear in
>> both decl_specializations and type_specializations.  They appear in the
>> type table only at parse time via finish_template_type.  There seems
>> to be no good reason for this, and the code paths end up stepping over
>> each other in particular for a partial alias template instantiation such
>> as A<B>::key_arg<T> in the below modules testcase: the type code path
>> (lookup_template_class) wants to set TI_TEMPLATE to the most general
>> template whereas the decl code path (tsubst_template_decl called during
>> instantiation of A<B>) already set TI_TEMPLATE to the partially
>> instantiated TEMPLATE_DECL.  This ends up confusing modules which
>> decides to stream the logically equivalent TYPE_DECL and TEMPLATE_DECL
>> for this partial alias template instantiation separately.
>>
>> This patch fixes this by making lookup_template_class dispatch to
>> instantiatie_alias_template early for alias template specializations.
>> In turn we now only add such specializations to the decl table and
>> not also the type table.  This admits some nice simplification in
>> the modules code which otherwise has to cope with such specializations
>> appearing in both tables.
>>
>> 	PR c++/103994
>>
>> gcc/cp/ChangeLog:
>>
>> 	* cp-tree.h (add_mergeable_specialization): Remove is_alias
>> 	parameter.
>> 	* module.cc (depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
>> 	(depset::is_alias): Remove.
>> 	(merge_kind::MK_tmpl_alias_mask): Remove.
>> 	(merge_kind::MK_alias_spec): Remove.
>> 	(merge_kind_name): Remove entries for alias specializations.
>> 	(trees_in::decl_value): Adjust add_mergeable_specialization
>> 	calls.
>> 	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
>> 	Use MK_decl_spec for alias template specializations.
>> 	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
>> 	removal.
>> 	(specialization_add): Don't allow alias templates when !decl_p.
>> 	(depset::hash::add_specializations): Remove now-dead code
>> 	accomodating alias template specializations in the type table.
>> 	* pt.cc (lookup_template_class): Dispatch early to
>> 	instantiate_alias_template for alias templates.  Simplify
>> 	accordingly.
>> 	(add_mergeable_specialization): Remove alias_p parameter and
>> 	simplify accordingly.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
>> 	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
>> 	* g++.dg/modules/tpl-alias-2_a.H: New test.
>> 	* g++.dg/modules/tpl-alias-2_b.C: New test.
>> ---
>>   gcc/cp/cp-tree.h                             |  3 +-
>>   gcc/cp/module.cc                             | 50 ++----------
>>   gcc/cp/pt.cc                                 | 84 ++++++++------------
>>   gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
>>   gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
>>   gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
>>   gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++
>>   7 files changed, 69 insertions(+), 96 deletions(-)
>>   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
>>   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
>>
>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>> index 4469d965ef0..14895bc6585 100644
>> --- a/gcc/cp/cp-tree.h
>> +++ b/gcc/cp/cp-tree.h
>> @@ -7642,8 +7642,7 @@ 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, bool is_alias,
>> -						 spec_entry *,
>> +extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
>>   						 tree outer, unsigned);
>>   extern tree add_to_template_args		(tree, tree);
>>   extern tree add_outermost_template_args		(tree, tree);
>> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
>> index 4ecd6d7c813..cc038ee9cba 100644
>> --- a/gcc/cp/module.cc
>> +++ b/gcc/cp/module.cc
>> @@ -2306,10 +2306,7 @@ private:
>>       /* The following bits are not independent, but enumerating them is
>>          awkward.  */
>>       DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
> 
> It seems we don't need DB_ALIAS_TMPL_INST_BIT anymore either, so the
> updated patch below removes it too.

OK.

> -- >8 --
> 
> 	PR c++/103994
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-tree.h (add_mergeable_specialization): Remove is_alias
> 	parameter.
> 	* module.cc (depset::disc_bits::DB_ALIAS_TMPL_INST_BIT): Remove.
> 	(depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
> 	(depset::is_alias_tmpl_inst): Remove.
> 	(depset::is_alias): Remove.
> 	(merge_kind::MK_tmpl_alias_mask): Remove.
> 	(merge_kind::MK_alias_spec): Remove.
> 	(merge_kind_name): Remove entries for alias specializations.
> 	(trees_out::core_vals) <case TEMPLATE_DECL>: Adjust after
> 	removing is_alias_tmpl_inst.
> 	(trees_in::decl_value): Adjust add_mergeable_specialization
> 	calls.
> 	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
> 	Use MK_decl_spec for alias template specializations.
> 	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
> 	removal.
> 	(depset::hash::make_dependency): Adjust after removing
> 	DB_ALIAS_TMPL_INST_BIT.
> 	(specialization_add): Don't allow alias templates when !decl_p.
> 	(depset::hash::add_specializations): Remove now-dead code
> 	accomodating alias template specializations in the type table.
> 	* pt.cc (lookup_template_class): Dispatch early to
> 	instantiate_alias_template for alias templates.  Simplify
> 	accordingly.
> 	(add_mergeable_specialization): Remove alias_p parameter and
> 	simplify accordingly.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
> 	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
> 	* g++.dg/modules/tpl-alias-2_a.H: New test.
> 	* g++.dg/modules/tpl-alias-2_b.C: New test.
> ---
>   gcc/cp/cp-tree.h                             |  3 +-
>   gcc/cp/module.cc                             | 86 ++++----------------
>   gcc/cp/pt.cc                                 | 84 ++++++++-----------
>   gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
>   gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
>   gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
>   gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 ++
>   7 files changed, 78 insertions(+), 123 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
>   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 4469d965ef0..14895bc6585 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7642,8 +7642,7 @@ 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, bool is_alias,
> -						 spec_entry *,
> +extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
>   						 tree outer, unsigned);
>   extern tree add_to_template_args		(tree, tree);
>   extern tree add_outermost_template_args		(tree, tree);
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 4ecd6d7c813..dfe4536c0ae 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -2305,11 +2305,7 @@ private:
>       DB_HIDDEN_BIT,		/* A hidden binding.  */
>       /* The following bits are not independent, but enumerating them is
>          awkward.  */
> -    DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
> -    DB_ALIAS_SPEC_BIT,		/* Specialization of an alias template
> -				   (in both spec tables).  */
> -    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.
> -				   */
> +    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.  */
>       DB_FRIEND_SPEC_BIT,		/* An instantiated template friend.  */
>     };
>   
> @@ -2400,14 +2396,6 @@ public:
>     {
>       return get_flag_bit<DB_UNREACHED_BIT> ();
>     }
> -  bool is_alias_tmpl_inst () const
> -  {
> -    return get_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
> -  }
> -  bool is_alias () const
> -  {
> -    return get_flag_bit<DB_ALIAS_SPEC_BIT> ();
> -  }
>     bool is_hidden () const
>     {
>       return get_flag_bit<DB_HIDDEN_BIT> ();
> @@ -2782,13 +2770,11 @@ enum merge_kind
>     MK_template_mask = 0x10,  /* A template specialization.  */
>   
>     MK_tmpl_decl_mask = 0x4, /* In decl table.  */
> -  MK_tmpl_alias_mask = 0x2, /* Also in type table  */
>   
>     MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL.  */
>   
>     MK_type_spec = MK_template_mask,
>     MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask,
> -  MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask,
>   
>     MK_hwm = 0x20
>   };
> @@ -2806,7 +2792,7 @@ static char const *const merge_kind_name[MK_hwm] =
>       NULL, NULL,
>   
>       "decl spec", "decl tmpl spec",	/* 20,21 decl (template).  */
> -    "alias spec", "alias tmpl spec",	/* 22,23 alias (template). */
> +    NULL, NULL,
>       NULL, NULL, NULL, NULL,
>       NULL, NULL, NULL, NULL,
>     };
> @@ -6356,8 +6342,7 @@ trees_out::core_vals (tree t)
>         gcc_checking_assert
>         	(TREE_VISITED (((lang_tree_node *)t)->template_decl.arguments));
>         gcc_checking_assert
> -	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result)
> -	 || dep_hash->find_dependency (t)->is_alias_tmpl_inst ());
> +	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result));
>         if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (t))
>   	WT (DECL_CHAIN (t));
>         break;
> @@ -8306,16 +8291,13 @@ trees_in::decl_value ()
>   	{
>   	  bool is_type = TREE_CODE (inner) == TYPE_DECL;
>   	  spec.spec = is_type ? type : inner;
> -	  add_mergeable_specialization (!is_type, false,
> -					&spec, decl, spec_flags);
> +	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
>   	}
>         else if (mk & MK_template_mask)
>   	{
>   	  bool is_type = !(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);
> +	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
>   	}
>   
>         if (NAMESPACE_SCOPE_P (decl)
> @@ -8392,7 +8374,7 @@ trees_in::decl_value ()
>         if (!e)
>   	{
>   	  spec.spec = inner;
> -	  add_mergeable_specialization (true, false, &spec, decl, spec_flags);
> +	  add_mergeable_specialization (true, &spec, decl, spec_flags);
>   	}
>         else if (e != existing)
>   	set_overrun ();
> @@ -10620,8 +10602,6 @@ trees_out::get_merge_kind (tree decl, depset *dep)
>   	  mk = MK_friend_spec;
>   	else if (dep->is_type_spec ())
>   	  mk = MK_type_spec;
> -	else if (dep->is_alias ())
> -	  mk = MK_alias_spec;
>   	else
>   	  mk = MK_decl_spec;
>   
> @@ -10732,11 +10712,6 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
>   	  gcc_assert (existing);
>   	  if (mk & MK_tmpl_decl_mask)
>   	    {
> -	      if (mk & MK_tmpl_alias_mask)
> -		/* It should be in both tables.  */
> -		gcc_checking_assert
> -		  (same_type_p (match_mergeable_specialization (false, entry),
> -				TREE_TYPE (existing)));
>   	      if (mk & MK_tmpl_tmpl_mask)
>   		existing = DECL_TI_TEMPLATE (existing);
>   	    }
> @@ -12830,17 +12805,12 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
>   	 bindings.  */
>         *slot = dep = make_entity (decl, ek, has_def);
>   
> -      if (TREE_CODE (decl) == TEMPLATE_DECL)
> -	{
> -	  if (DECL_ALIAS_TEMPLATE_P (decl) && DECL_TEMPLATE_INFO (decl))
> -	    dep->set_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
> -	  else if (CHECKING_P)
> -	    /* The template_result should otherwise not be in the
> -	       table, or be an empty redirect (created above).  */
> -	    if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false))
> -	      gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
> -				   && !(*eslot)->deps.length ());
> -	}
> +      if (CHECKING_P && TREE_CODE (decl) == TEMPLATE_DECL)
> +	/* The template_result should otherwise not be in the
> +	   table, or be an empty redirect (created above).  */
> +	if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false))
> +	  gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
> +			       && !(*eslot)->deps.length ());
>   
>         if (ek != EK_USING)
>   	{
> @@ -13228,16 +13198,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
>   	 heuristic.  We don't attempt to replicate that algorithm, but
>   	 observe its behaviour and reproduce it upon read back.  */
>   
> -       gcc_checking_assert (DECL_ALIAS_TEMPLATE_P (entry->tmpl)
> -			   || TREE_CODE (entry->spec) == ENUMERAL_TYPE
> +       gcc_checking_assert (TREE_CODE (entry->spec) == ENUMERAL_TYPE
>   			   || 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).  */
>          gcc_checking_assert
> -	 (!match_mergeable_specialization (true, entry)
> -	  == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
> +	 (!match_mergeable_specialization (true, entry));
>       }
>     else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
>       gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
> @@ -13293,7 +13258,6 @@ depset::hash::add_specializations (bool decl_p)
>         spec_entry *entry = data.pop ();
>         tree spec = entry->spec;
>         int use_tpl = 0;
> -      bool is_alias = false;
>         bool is_friend = false;
>   
>         if (decl_p && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (entry->tmpl))
> @@ -13301,13 +13265,7 @@ depset::hash::add_specializations (bool decl_p)
>   	   instantiation.  */
>   	is_friend = true;
>   
> -      if (!decl_p && DECL_ALIAS_TEMPLATE_P (entry->tmpl))
> -	{
> -	  spec = TYPE_NAME (spec);
> -	  is_alias = true;
> -	}
> -
> -      if (decl_p || is_alias)
> +      if (decl_p)
>   	{
>   	  if (tree ti = DECL_TEMPLATE_INFO (spec))
>   	    {
> @@ -13392,20 +13350,10 @@ depset::hash::add_specializations (bool decl_p)
>         gcc_checking_assert (!TREE_VISITED (spec));
>         depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION);
>         if (dep->is_special ())
> -	{
> -	  /* An already located specialization, this must be the TYPE
> -	     corresponding to an alias_decl we found in the decl
> -	     table.  */
> -	  spec_entry *other = reinterpret_cast <spec_entry *> (dep->deps[0]);
> -	  gcc_checking_assert (!decl_p && is_alias && !dep->is_type_spec ());
> -	  gcc_checking_assert (other->tmpl == entry->tmpl
> -			       && template_args_equal (other->args, entry->args)
> -			       && TREE_TYPE (other->spec) == entry->spec);
> -	  dep->set_flag_bit<DB_ALIAS_SPEC_BIT> ();
> -	}
> +	gcc_unreachable ();
>         else
>   	{
> -	  gcc_checking_assert (decl_p || !is_alias);
> +	  gcc_checking_assert (decl_p);
>   	  if (dep->get_entity_kind () == depset::EK_REDIRECT)
>   	    dep = dep->deps[0];
>   	  else if (dep->get_entity_kind () == depset::EK_SPECIALIZATION)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index d73f6d93485..99aa64b1cc3 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10055,6 +10055,32 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>         /* Now we should have enough arguments.  */
>         gcc_assert (parm_depth == arg_depth);
>   
> +      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> +	{
> +	  /* The user referred to a specialization of an alias
> +	    template represented by GEN_TMPL.
> +
> +	    [temp.alias]/2 says:
> +
> +		When a template-id refers to the specialization of an
> +		alias template, it is equivalent to the associated
> +		type obtained by substitution of its
> +		template-arguments for the template-parameters in the
> +		type-id of the alias template.  */
> +
> +	  t = instantiate_alias_template (gen_tmpl, arglist, complain);
> +	  /* Note that the call above (by indirectly calling
> +	     register_specialization in tsubst_decl) registers the
> +	     TYPE_DECL representing the specialization of the alias
> +	     template.  So next time someone substitutes ARGLIST for
> +	     the template parms into the alias template (GEN_TMPL),
> +	     she'll get that TYPE_DECL back.  */
> +
> +	  if (t == error_mark_node)
> +	    return error_mark_node;
> +	  return TREE_TYPE (t);
> +	}

I'm surprised we don't still need the call to coerce_template_parms, a 
bit below this?

>         /* From here on, we're only interested in the most general
>   	 template.  */
>   
> @@ -10120,7 +10146,6 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>            lookup. This prevents redundant checks on previously
>            instantiated specializations. */
>         if (flag_concepts
> -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)
>   	  && !constraints_satisfied_p (gen_tmpl, arglist))
>           {
>             if (complain & tf_error)
> @@ -10189,31 +10214,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>   	context = global_namespace;
>   
>         /* Create the type.  */
> -      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> -	{
> -	  /* The user referred to a specialization of an alias
> -	    template represented by GEN_TMPL.
> -
> -	    [temp.alias]/2 says:
> -
> -	        When a template-id refers to the specialization of an
> -		alias template, it is equivalent to the associated
> -		type obtained by substitution of its
> -		template-arguments for the template-parameters in the
> -		type-id of the alias template.  */
> -
> -	  t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl);
> -	  /* Note that the call above (by indirectly calling
> -	     register_specialization in tsubst_decl) registers the
> -	     TYPE_DECL representing the specialization of the alias
> -	     template.  So next time someone substitutes ARGLIST for
> -	     the template parms into the alias template (GEN_TMPL),
> -	     she'll get that TYPE_DECL back.  */
> -
> -	  if (t == error_mark_node)
> -	    return t;
> -	}
> -      else if (TREE_CODE (template_type) == ENUMERAL_TYPE)
> +      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
>   	{
>   	  if (!is_dependent_type)
>   	    {
> @@ -10301,8 +10302,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>   	    }
>   	}
>   
> -      if (OVERLOAD_TYPE_P (t)
> -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> +      if (OVERLOAD_TYPE_P (t))
>   	{
>   	  static const char *tags[] = {"abi_tag", "may_alias"};
>   
> @@ -10369,7 +10369,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>   	{
>   	  TREE_VEC_LENGTH (arglist)--;
>   	  ++processing_template_decl;
> -	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (gen_tmpl));
> +	  tree tinfo = TYPE_TEMPLATE_INFO (TREE_TYPE (gen_tmpl));
>   	  tree partial_inst_args =
>   	    tsubst (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)),
>   		    arglist, complain, NULL_TREE);
> @@ -10407,17 +10407,9 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>   	     TEMPLATE_PARM_LEVEL.  */
>   	  found = tsubst (gen_tmpl, arglist, tf_none, NULL_TREE);
>   	  TREE_VEC_LENGTH (arglist)++;
> -	  /* FOUND is either a proper class type, or an alias
> -	     template specialization.  In the later case, it's a
> -	     TYPE_DECL, resulting from the substituting of arguments
> -	     for parameters in the TYPE_DECL of the alias template
> -	     done earlier.  So be careful while getting the template
> -	     of FOUND.  */
>   	  found = (TREE_CODE (found) == TEMPLATE_DECL
>   		   ? found
> -		   : (TREE_CODE (found) == TYPE_DECL
> -		      ? DECL_TI_TEMPLATE (found)
> -		      : CLASSTYPE_TI_TEMPLATE (found)));
> +		   : CLASSTYPE_TI_TEMPLATE (found));
>   
>   	  if (DECL_CLASS_TEMPLATE_P (found)
>   	      && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
> @@ -10447,8 +10439,7 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>   		     DECL_TEMPLATE_INSTANTIATIONS (found));
>   
>         if (TREE_CODE (template_type) == ENUMERAL_TYPE
> -	  && !uses_template_parms (current_nonlambda_scope ())
> -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> +	  && !uses_template_parms (current_nonlambda_scope ()))
>   	/* Now that the type has been registered on the instantiations
>   	   list, we set up the enumerators.  Because the enumeration
>   	   constants may involve the enumeration type itself, we make
> @@ -31578,8 +31569,8 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
>      get_mergeable_specialization_flags.  */
>   
>   void
> -add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
> -			      tree decl, unsigned flags)
> +add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
> +			      unsigned flags)
>   {
>     hashval_t hash = spec_hasher::hash (elt);
>     if (decl_p)
> @@ -31590,15 +31581,8 @@ add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
>         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)
> +  else
>       {
>         auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
>   
> diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> index 53d28b4ef5e..e75b3129dd3 100644
> --- a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> +++ b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> @@ -15,5 +15,5 @@ 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
> +// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl 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:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
>   
> diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> index 37002ee9ae1..14a25be586f 100644
> --- a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> @@ -6,4 +6,4 @@
>   // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
>   // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]* type_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
>   
> -// { dg-final { scan-lang-dump {Writing:-[0-9]*'s alias spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
> +// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
> diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> new file mode 100644
> index 00000000000..76917f778e0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> @@ -0,0 +1,15 @@
> +// PR c++/103994
> +// { dg-additional-options -fmodule-header }
> +// { dg-module-cmi {} }
> +
> +template<class>
> +struct A {
> +  template<class> using key_arg = int;
> +};
> +
> +struct B {
> +  template<class T>
> +  void f() {
> +    using type = A<B>::key_arg<T>;
> +  }
> +};
> diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> new file mode 100644
> index 00000000000..44fa5f42757
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> @@ -0,0 +1,9 @@
> +// PR c++/103994
> +// { dg-additional-options -fmodules-ts }
> +
> +import "tpl-alias-2_a.H";
> +
> +int main() {
> +  B b;
> +  b.f<int>();
> +}
Patrick Palka March 7, 2024, 8:58 p.m. UTC | #5
On Thu, 7 Mar 2024, Jason Merrill wrote:

> On 3/7/24 14:41, Patrick Palka wrote:
> > On Thu, 7 Mar 2024, Patrick Palka wrote:
> > 
> > > On Wed, 6 Mar 2024, Jason Merrill wrote:
> > > 
> > > > On 3/4/24 17:26, Patrick Palka wrote:
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > OK for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > Alias templates are weird in that their specializations can appear in
> > > > > both decl_specializations and type_specializations.  They appear in
> > > > > the
> > > > > latter only at parse time via finish_template_type.  This should
> > > > > probably
> > > > > be revisited in GCC 15 since it seems sufficient to store them only in
> > > > > decl_specializations.
> > > > 
> > > > It looks like most all of lookup_template_class is wrong for alias
> > > > templates.
> > > > 
> > > > Can we move the alias template handling up higher and unconditionally
> > > > return
> > > > the result of tsubst?
> > > 
> > > This works nicely (although we have to use instantiate_alias_template
> > > directly instead of tsubst since tsubst would first substitute the
> > > uncoerced arguments into the generic DECL_TI_ARGS which breaks for
> > > for parameter packs).  And it allows for some nice simplifications in
> > > the modules code which had to handle alias template specializations
> > > specially.
> > > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu.
> > > 
> > > -- >8 --
> > > 
> > > Subject: [PATCH] c++/modules: member alias tmpl partial inst [PR103994]
> > > 
> > > Alias templates are weird in that their specializations can appear in
> > > both decl_specializations and type_specializations.  They appear in the
> > > type table only at parse time via finish_template_type.  There seems
> > > to be no good reason for this, and the code paths end up stepping over
> > > each other in particular for a partial alias template instantiation such
> > > as A<B>::key_arg<T> in the below modules testcase: the type code path
> > > (lookup_template_class) wants to set TI_TEMPLATE to the most general
> > > template whereas the decl code path (tsubst_template_decl called during
> > > instantiation of A<B>) already set TI_TEMPLATE to the partially
> > > instantiated TEMPLATE_DECL.  This ends up confusing modules which
> > > decides to stream the logically equivalent TYPE_DECL and TEMPLATE_DECL
> > > for this partial alias template instantiation separately.
> > > 
> > > This patch fixes this by making lookup_template_class dispatch to
> > > instantiatie_alias_template early for alias template specializations.
> > > In turn we now only add such specializations to the decl table and
> > > not also the type table.  This admits some nice simplification in
> > > the modules code which otherwise has to cope with such specializations
> > > appearing in both tables.
> > > 
> > > 	PR c++/103994
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	* cp-tree.h (add_mergeable_specialization): Remove is_alias
> > > 	parameter.
> > > 	* module.cc (depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
> > > 	(depset::is_alias): Remove.
> > > 	(merge_kind::MK_tmpl_alias_mask): Remove.
> > > 	(merge_kind::MK_alias_spec): Remove.
> > > 	(merge_kind_name): Remove entries for alias specializations.
> > > 	(trees_in::decl_value): Adjust add_mergeable_specialization
> > > 	calls.
> > > 	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
> > > 	Use MK_decl_spec for alias template specializations.
> > > 	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
> > > 	removal.
> > > 	(specialization_add): Don't allow alias templates when !decl_p.
> > > 	(depset::hash::add_specializations): Remove now-dead code
> > > 	accomodating alias template specializations in the type table.
> > > 	* pt.cc (lookup_template_class): Dispatch early to
> > > 	instantiate_alias_template for alias templates.  Simplify
> > > 	accordingly.
> > > 	(add_mergeable_specialization): Remove alias_p parameter and
> > > 	simplify accordingly.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
> > > 	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
> > > 	* g++.dg/modules/tpl-alias-2_a.H: New test.
> > > 	* g++.dg/modules/tpl-alias-2_b.C: New test.
> > > ---
> > >   gcc/cp/cp-tree.h                             |  3 +-
> > >   gcc/cp/module.cc                             | 50 ++----------
> > >   gcc/cp/pt.cc                                 | 84 ++++++++------------
> > >   gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
> > >   gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
> > >   gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
> > >   gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++
> > >   7 files changed, 69 insertions(+), 96 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> > >   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> > > 
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index 4469d965ef0..14895bc6585 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -7642,8 +7642,7 @@ 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, bool
> > > is_alias,
> > > -						 spec_entry *,
> > > +extern void add_mergeable_specialization        (bool is_decl, spec_entry
> > > *,
> > >   						 tree outer, unsigned);
> > >   extern tree add_to_template_args		(tree, tree);
> > >   extern tree add_outermost_template_args		(tree, tree);
> > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > index 4ecd6d7c813..cc038ee9cba 100644
> > > --- a/gcc/cp/module.cc
> > > +++ b/gcc/cp/module.cc
> > > @@ -2306,10 +2306,7 @@ private:
> > >       /* The following bits are not independent, but enumerating them is
> > >          awkward.  */
> > >       DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
> > 
> > It seems we don't need DB_ALIAS_TMPL_INST_BIT anymore either, so the
> > updated patch below removes it too.
> 
> OK.

Thanks a lot.

> 
> > -- >8 --
> > 
> > 	PR c++/103994
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* cp-tree.h (add_mergeable_specialization): Remove is_alias
> > 	parameter.
> > 	* module.cc (depset::disc_bits::DB_ALIAS_TMPL_INST_BIT): Remove.
> > 	(depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
> > 	(depset::is_alias_tmpl_inst): Remove.
> > 	(depset::is_alias): Remove.
> > 	(merge_kind::MK_tmpl_alias_mask): Remove.
> > 	(merge_kind::MK_alias_spec): Remove.
> > 	(merge_kind_name): Remove entries for alias specializations.
> > 	(trees_out::core_vals) <case TEMPLATE_DECL>: Adjust after
> > 	removing is_alias_tmpl_inst.
> > 	(trees_in::decl_value): Adjust add_mergeable_specialization
> > 	calls.
> > 	(trees_out::get_merge_kind) <case depset::EK_SPECIALIZATION>:
> > 	Use MK_decl_spec for alias template specializations.
> > 	(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
> > 	removal.
> > 	(depset::hash::make_dependency): Adjust after removing
> > 	DB_ALIAS_TMPL_INST_BIT.
> > 	(specialization_add): Don't allow alias templates when !decl_p.
> > 	(depset::hash::add_specializations): Remove now-dead code
> > 	accomodating alias template specializations in the type table.
> > 	* pt.cc (lookup_template_class): Dispatch early to
> > 	instantiate_alias_template for alias templates.  Simplify
> > 	accordingly.
> > 	(add_mergeable_specialization): Remove alias_p parameter and
> > 	simplify accordingly.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
> > 	* g++.dg/modules/tpl-alias-1_a.H: Likewise.
> > 	* g++.dg/modules/tpl-alias-2_a.H: New test.
> > 	* g++.dg/modules/tpl-alias-2_b.C: New test.
> > ---
> >   gcc/cp/cp-tree.h                             |  3 +-
> >   gcc/cp/module.cc                             | 86 ++++----------------
> >   gcc/cp/pt.cc                                 | 84 ++++++++-----------
> >   gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
> >   gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
> >   gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 ++++
> >   gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 ++
> >   7 files changed, 78 insertions(+), 123 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> >   create mode 100644 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> > 
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 4469d965ef0..14895bc6585 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7642,8 +7642,7 @@ 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, bool
> > is_alias,
> > -						 spec_entry *,
> > +extern void add_mergeable_specialization        (bool is_decl, spec_entry
> > *,
> >   						 tree outer, unsigned);
> >   extern tree add_to_template_args		(tree, tree);
> >   extern tree add_outermost_template_args		(tree, tree);
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 4ecd6d7c813..dfe4536c0ae 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -2305,11 +2305,7 @@ private:
> >       DB_HIDDEN_BIT,		/* A hidden binding.  */
> >       /* The following bits are not independent, but enumerating them is
> >          awkward.  */
> > -    DB_ALIAS_TMPL_INST_BIT,	/* An alias template instantiation. */
> > -    DB_ALIAS_SPEC_BIT,		/* Specialization of an alias template
> > -				   (in both spec tables).  */
> > -    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.
> > -				   */
> > +    DB_TYPE_SPEC_BIT,		/* Specialization in the type table.
> > */
> >       DB_FRIEND_SPEC_BIT,		/* An instantiated template friend.
> > */
> >     };
> >   @@ -2400,14 +2396,6 @@ public:
> >     {
> >       return get_flag_bit<DB_UNREACHED_BIT> ();
> >     }
> > -  bool is_alias_tmpl_inst () const
> > -  {
> > -    return get_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
> > -  }
> > -  bool is_alias () const
> > -  {
> > -    return get_flag_bit<DB_ALIAS_SPEC_BIT> ();
> > -  }
> >     bool is_hidden () const
> >     {
> >       return get_flag_bit<DB_HIDDEN_BIT> ();
> > @@ -2782,13 +2770,11 @@ enum merge_kind
> >     MK_template_mask = 0x10,  /* A template specialization.  */
> >       MK_tmpl_decl_mask = 0x4, /* In decl table.  */
> > -  MK_tmpl_alias_mask = 0x2, /* Also in type table  */
> >       MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL.  */
> >       MK_type_spec = MK_template_mask,
> >     MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask,
> > -  MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask,
> >       MK_hwm = 0x20
> >   };
> > @@ -2806,7 +2792,7 @@ static char const *const merge_kind_name[MK_hwm] =
> >       NULL, NULL,
> >         "decl spec", "decl tmpl spec",	/* 20,21 decl (template).  */
> > -    "alias spec", "alias tmpl spec",	/* 22,23 alias (template). */
> > +    NULL, NULL,
> >       NULL, NULL, NULL, NULL,
> >       NULL, NULL, NULL, NULL,
> >     };
> > @@ -6356,8 +6342,7 @@ trees_out::core_vals (tree t)
> >         gcc_checking_assert
> >         	(TREE_VISITED (((lang_tree_node
> > *)t)->template_decl.arguments));
> >         gcc_checking_assert
> > -	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result)
> > -	 || dep_hash->find_dependency (t)->is_alias_tmpl_inst ());
> > +	(TREE_VISITED (((lang_tree_node *)t)->template_decl.result));
> >         if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (t))
> >   	WT (DECL_CHAIN (t));
> >         break;
> > @@ -8306,16 +8291,13 @@ trees_in::decl_value ()
> >   	{
> >   	  bool is_type = TREE_CODE (inner) == TYPE_DECL;
> >   	  spec.spec = is_type ? type : inner;
> > -	  add_mergeable_specialization (!is_type, false,
> > -					&spec, decl, spec_flags);
> > +	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
> >   	}
> >         else if (mk & MK_template_mask)
> >   	{
> >   	  bool is_type = !(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);
> > +	  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
> >   	}
> >           if (NAMESPACE_SCOPE_P (decl)
> > @@ -8392,7 +8374,7 @@ trees_in::decl_value ()
> >         if (!e)
> >   	{
> >   	  spec.spec = inner;
> > -	  add_mergeable_specialization (true, false, &spec, decl, spec_flags);
> > +	  add_mergeable_specialization (true, &spec, decl, spec_flags);
> >   	}
> >         else if (e != existing)
> >   	set_overrun ();
> > @@ -10620,8 +10602,6 @@ trees_out::get_merge_kind (tree decl, depset *dep)
> >   	  mk = MK_friend_spec;
> >   	else if (dep->is_type_spec ())
> >   	  mk = MK_type_spec;
> > -	else if (dep->is_alias ())
> > -	  mk = MK_alias_spec;
> >   	else
> >   	  mk = MK_decl_spec;
> >   @@ -10732,11 +10712,6 @@ trees_out::key_mergeable (int tag, merge_kind mk,
> > tree decl, tree inner,
> >   	  gcc_assert (existing);
> >   	  if (mk & MK_tmpl_decl_mask)
> >   	    {
> > -	      if (mk & MK_tmpl_alias_mask)
> > -		/* It should be in both tables.  */
> > -		gcc_checking_assert
> > -		  (same_type_p (match_mergeable_specialization (false, entry),
> > -				TREE_TYPE (existing)));
> >   	      if (mk & MK_tmpl_tmpl_mask)
> >   		existing = DECL_TI_TEMPLATE (existing);
> >   	    }
> > @@ -12830,17 +12805,12 @@ depset::hash::make_dependency (tree decl,
> > entity_kind ek)
> >   	 bindings.  */
> >         *slot = dep = make_entity (decl, ek, has_def);
> >   -      if (TREE_CODE (decl) == TEMPLATE_DECL)
> > -	{
> > -	  if (DECL_ALIAS_TEMPLATE_P (decl) && DECL_TEMPLATE_INFO (decl))
> > -	    dep->set_flag_bit<DB_ALIAS_TMPL_INST_BIT> ();
> > -	  else if (CHECKING_P)
> > -	    /* The template_result should otherwise not be in the
> > -	       table, or be an empty redirect (created above).  */
> > -	    if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl),
> > false))
> > -	      gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
> > -				   && !(*eslot)->deps.length ());
> > -	}
> > +      if (CHECKING_P && TREE_CODE (decl) == TEMPLATE_DECL)
> > +	/* The template_result should otherwise not be in the
> > +	   table, or be an empty redirect (created above).  */
> > +	if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false))
> > +	  gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT
> > +			       && !(*eslot)->deps.length ());
> >           if (ek != EK_USING)
> >   	{
> > @@ -13228,16 +13198,11 @@ specialization_add (bool decl_p, spec_entry
> > *entry, void *data_)
> >   	 heuristic.  We don't attempt to replicate that algorithm, but
> >   	 observe its behaviour and reproduce it upon read back.  */
> >   -       gcc_checking_assert (DECL_ALIAS_TEMPLATE_P (entry->tmpl)
> > -			   || TREE_CODE (entry->spec) == ENUMERAL_TYPE
> > +       gcc_checking_assert (TREE_CODE (entry->spec) == ENUMERAL_TYPE
> >   			   || 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).  */
> >          gcc_checking_assert
> > -	 (!match_mergeable_specialization (true, entry)
> > -	  == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
> > +	 (!match_mergeable_specialization (true, entry));
> >       }
> >     else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
> >       gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
> > @@ -13293,7 +13258,6 @@ depset::hash::add_specializations (bool decl_p)
> >         spec_entry *entry = data.pop ();
> >         tree spec = entry->spec;
> >         int use_tpl = 0;
> > -      bool is_alias = false;
> >         bool is_friend = false;
> >           if (decl_p && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (entry->tmpl))
> > @@ -13301,13 +13265,7 @@ depset::hash::add_specializations (bool decl_p)
> >   	   instantiation.  */
> >   	is_friend = true;
> >   -      if (!decl_p && DECL_ALIAS_TEMPLATE_P (entry->tmpl))
> > -	{
> > -	  spec = TYPE_NAME (spec);
> > -	  is_alias = true;
> > -	}
> > -
> > -      if (decl_p || is_alias)
> > +      if (decl_p)
> >   	{
> >   	  if (tree ti = DECL_TEMPLATE_INFO (spec))
> >   	    {
> > @@ -13392,20 +13350,10 @@ depset::hash::add_specializations (bool decl_p)
> >         gcc_checking_assert (!TREE_VISITED (spec));
> >         depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION);
> >         if (dep->is_special ())
> > -	{
> > -	  /* An already located specialization, this must be the TYPE
> > -	     corresponding to an alias_decl we found in the decl
> > -	     table.  */
> > -	  spec_entry *other = reinterpret_cast <spec_entry *> (dep->deps[0]);
> > -	  gcc_checking_assert (!decl_p && is_alias && !dep->is_type_spec ());
> > -	  gcc_checking_assert (other->tmpl == entry->tmpl
> > -			       && template_args_equal (other->args,
> > entry->args)
> > -			       && TREE_TYPE (other->spec) == entry->spec);
> > -	  dep->set_flag_bit<DB_ALIAS_SPEC_BIT> ();
> > -	}
> > +	gcc_unreachable ();
> >         else
> >   	{
> > -	  gcc_checking_assert (decl_p || !is_alias);
> > +	  gcc_checking_assert (decl_p);
> >   	  if (dep->get_entity_kind () == depset::EK_REDIRECT)
> >   	    dep = dep->deps[0];
> >   	  else if (dep->get_entity_kind () == depset::EK_SPECIALIZATION)
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index d73f6d93485..99aa64b1cc3 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -10055,6 +10055,32 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >         /* Now we should have enough arguments.  */
> >         gcc_assert (parm_depth == arg_depth);
> >   +      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> > +	{
> > +	  /* The user referred to a specialization of an alias
> > +	    template represented by GEN_TMPL.
> > +
> > +	    [temp.alias]/2 says:
> > +
> > +		When a template-id refers to the specialization of an
> > +		alias template, it is equivalent to the associated
> > +		type obtained by substitution of its
> > +		template-arguments for the template-parameters in the
> > +		type-id of the alias template.  */
> > +
> > +	  t = instantiate_alias_template (gen_tmpl, arglist, complain);
> > +	  /* Note that the call above (by indirectly calling
> > +	     register_specialization in tsubst_decl) registers the
> > +	     TYPE_DECL representing the specialization of the alias
> > +	     template.  So next time someone substitutes ARGLIST for
> > +	     the template parms into the alias template (GEN_TMPL),
> > +	     she'll get that TYPE_DECL back.  */
> > +
> > +	  if (t == error_mark_node)
> > +	    return error_mark_node;
> > +	  return TREE_TYPE (t);
> > +	}
> 
> I'm surprised we don't still need the call to coerce_template_parms, a bit
> below this?

Luckily we can skip it since instantiate_alias_template already
immediately calls coerce_template_parms.  I guess that's a nice
benefit of calling instantiate_alias_template directly instead
of going through tsubst.

> 
> >         /* From here on, we're only interested in the most general
> >   	 template.  */
> >   @@ -10120,7 +10146,6 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >            lookup. This prevents redundant checks on previously
> >            instantiated specializations. */
> >         if (flag_concepts
> > -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)
> >   	  && !constraints_satisfied_p (gen_tmpl, arglist))
> >           {
> >             if (complain & tf_error)
> > @@ -10189,31 +10214,7 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >   	context = global_namespace;
> >           /* Create the type.  */
> > -      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> > -	{
> > -	  /* The user referred to a specialization of an alias
> > -	    template represented by GEN_TMPL.
> > -
> > -	    [temp.alias]/2 says:
> > -
> > -	        When a template-id refers to the specialization of an
> > -		alias template, it is equivalent to the associated
> > -		type obtained by substitution of its
> > -		template-arguments for the template-parameters in the
> > -		type-id of the alias template.  */
> > -
> > -	  t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl);
> > -	  /* Note that the call above (by indirectly calling
> > -	     register_specialization in tsubst_decl) registers the
> > -	     TYPE_DECL representing the specialization of the alias
> > -	     template.  So next time someone substitutes ARGLIST for
> > -	     the template parms into the alias template (GEN_TMPL),
> > -	     she'll get that TYPE_DECL back.  */
> > -
> > -	  if (t == error_mark_node)
> > -	    return t;
> > -	}
> > -      else if (TREE_CODE (template_type) == ENUMERAL_TYPE)
> > +      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
> >   	{
> >   	  if (!is_dependent_type)
> >   	    {
> > @@ -10301,8 +10302,7 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >   	    }
> >   	}
> >   -      if (OVERLOAD_TYPE_P (t)
> > -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> > +      if (OVERLOAD_TYPE_P (t))
> >   	{
> >   	  static const char *tags[] = {"abi_tag", "may_alias"};
> >   @@ -10369,7 +10369,7 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >   	{
> >   	  TREE_VEC_LENGTH (arglist)--;
> >   	  ++processing_template_decl;
> > -	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (gen_tmpl));
> > +	  tree tinfo = TYPE_TEMPLATE_INFO (TREE_TYPE (gen_tmpl));
> >   	  tree partial_inst_args =
> >   	    tsubst (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)),
> >   		    arglist, complain, NULL_TREE);
> > @@ -10407,17 +10407,9 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >   	     TEMPLATE_PARM_LEVEL.  */
> >   	  found = tsubst (gen_tmpl, arglist, tf_none, NULL_TREE);
> >   	  TREE_VEC_LENGTH (arglist)++;
> > -	  /* FOUND is either a proper class type, or an alias
> > -	     template specialization.  In the later case, it's a
> > -	     TYPE_DECL, resulting from the substituting of arguments
> > -	     for parameters in the TYPE_DECL of the alias template
> > -	     done earlier.  So be careful while getting the template
> > -	     of FOUND.  */
> >   	  found = (TREE_CODE (found) == TEMPLATE_DECL
> >   		   ? found
> > -		   : (TREE_CODE (found) == TYPE_DECL
> > -		      ? DECL_TI_TEMPLATE (found)
> > -		      : CLASSTYPE_TI_TEMPLATE (found)));
> > +		   : CLASSTYPE_TI_TEMPLATE (found));
> >     	  if (DECL_CLASS_TEMPLATE_P (found)
> >   	      && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
> > @@ -10447,8 +10439,7 @@ lookup_template_class (tree d1, tree arglist, tree
> > in_decl, tree context,
> >   		     DECL_TEMPLATE_INSTANTIATIONS (found));
> >           if (TREE_CODE (template_type) == ENUMERAL_TYPE
> > -	  && !uses_template_parms (current_nonlambda_scope ())
> > -	  && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
> > +	  && !uses_template_parms (current_nonlambda_scope ()))
> >   	/* Now that the type has been registered on the instantiations
> >   	   list, we set up the enumerators.  Because the enumeration
> >   	   constants may involve the enumeration type itself, we make
> > @@ -31578,8 +31569,8 @@ get_mergeable_specialization_flags (tree tmpl, tree
> > decl)
> >      get_mergeable_specialization_flags.  */
> >     void
> > -add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
> > -			      tree decl, unsigned flags)
> > +add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
> > +			      unsigned flags)
> >   {
> >     hashval_t hash = spec_hasher::hash (elt);
> >     if (decl_p)
> > @@ -31590,15 +31581,8 @@ add_mergeable_specialization (bool decl_p, bool
> > alias_p, spec_entry *elt,
> >         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)
> > +  else
> >       {
> >         auto *slot = type_specializations->find_slot_with_hash (elt, hash,
> > INSERT);
> >   diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> > b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> > index 53d28b4ef5e..e75b3129dd3 100644
> > --- a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> > +++ b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
> > @@ -15,5 +15,5 @@ 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:-[0-9]*'s named merge key
> > \(matched\) template_decl:'::template ssize'} module } }
> > +// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl 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:-[0-9]*'s named merge key
> > \(matched\) template_decl:'::template ssize'} module } }
> >   diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> > b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> > index 37002ee9ae1..14a25be586f 100644
> > --- a/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> > +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
> > @@ -6,4 +6,4 @@
> >   // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]*
> > template_decl:'::allocator_traits<::allocator<long int>>::template
> > rebind_alloc<_Up>'} module } }
> >   // { dg-final { scan-lang-dump {Writing decl tmpl spec:-[0-9]*
> > type_decl:'::allocator_traits<::allocator<long int>>::template
> > rebind_alloc<_Up>'} module } }
> >   -// { dg-final { scan-lang-dump {Writing:-[0-9]*'s alias spec merge key
> > \(specialization\) type_decl:'::allocator_traits<::allocator<long
> > int>>::rebind_alloc<long int>'} module } }
> > +// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key
> > \(specialization\) type_decl:'::allocator_traits<::allocator<long
> > int>>::rebind_alloc<long int>'} module } }
> > diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> > b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> > new file mode 100644
> > index 00000000000..76917f778e0
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
> > @@ -0,0 +1,15 @@
> > +// PR c++/103994
> > +// { dg-additional-options -fmodule-header }
> > +// { dg-module-cmi {} }
> > +
> > +template<class>
> > +struct A {
> > +  template<class> using key_arg = int;
> > +};
> > +
> > +struct B {
> > +  template<class T>
> > +  void f() {
> > +    using type = A<B>::key_arg<T>;
> > +  }
> > +};
> > diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> > b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> > new file mode 100644
> > index 00000000000..44fa5f42757
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
> > @@ -0,0 +1,9 @@
> > +// PR c++/103994
> > +// { dg-additional-options -fmodules-ts }
> > +
> > +import "tpl-alias-2_a.H";
> > +
> > +int main() {
> > +  B b;
> > +  b.f<int>();
> > +}
> 
>
diff mbox series

Patch

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c4bc54a8fdb..ce2d53fe762 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10431,7 +10431,12 @@  lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 	}
 
       /* Build template info for the new specialization.  */
-      SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
+      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	/* Already properly set by instantiate_template (or
+	   tsubst_template_decl).  */
+	gcc_assert (DECL_TEMPLATE_INFO (TYPE_NAME (t)));
+      else
+	SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
 
       elt.spec = t;
       slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
new file mode 100644
index 00000000000..76917f778e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H
@@ -0,0 +1,15 @@ 
+// PR c++/103994
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<class>
+struct A {
+  template<class> using key_arg = int;
+};
+
+struct B {
+  template<class T>
+  void f() {
+    using type = A<B>::key_arg<T>;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
new file mode 100644
index 00000000000..44fa5f42757
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C
@@ -0,0 +1,9 @@ 
+// PR c++/103994
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-alias-2_a.H";
+
+int main() {
+  B b;
+  b.f<int>();
+}