diff mbox series

c++: imported templates and alias-template changes [PR 99283]

Message ID 30ab3815-093b-a87b-8fad-902969727178@acm.org
State New
Headers show
Series c++: imported templates and alias-template changes [PR 99283] | expand

Commit Message

Nathan Sidwell March 26, 2021, 7:08 p.m. UTC
During development of modules, I had difficulty	deciding whether the 
module flags of a template should live on the decl_template_result, the 
template_decl, or both.  I chose the latter, and require them to be 
consistent.  This and a few other defects show how hard that consistency 
is.  Hence this patch move to holding the flags on the 
template-decl-result decl.  That's the entity various bits of the parser 
have at the appropriate time.   Once needs STRIP_TEMPLATE in a bunch of 
places, which this patch adds.  Also a check that we never give a 
TEMPLATE_DECL to the module flag accessors.

This left a problem with how I was handling template aliases.  These 
were in two parts -- separating the TEMPLATE_DECL from the TYPE_DECL. 
That seemed somewhat funky, but development showed it necessary.  Of 
course, that causes problems if the TEMPLATE_DECL cannot contain 'am 
imported' information.	Investigating now shows	that we	do not need to 
treat them separately.	By reverting a bit of template instantiation 
machinery that caused the problem, we're back on course.  I think what 
has happened is that between then and now, other typedef fixes have 
corrected the underlying problem this separation was working around. It 
allows a bunch of cleanup in the decl streamer, as we no longer have to 
handle a null TEMPLATE_DECL_RESULT.


         PR c++/99283
         gcc/cp/
         * cp-tree.h (DECL_MODULE_CHECK): Ban TEMPLATE_DECL.
         (SET_TYPE_TEMPLATE_INFO): Restore Alias template setting.
         * decl.c (duplicate_decls): Remove template_decl module flag
         propagation.
         * module.cc (merge_kind_name): Add alias tmpl spec as a thing.
         (dumper::impl::nested_name): Adjust for template-decl module flag
         change.
         (trees_in::assert_definition): Likewise.
         (trees_in::install_entity): Likewise.
         (trees_out::decl_value): Likewise.  Remove alias template
         separation of template and type_decl.
         (trees_in::decl_value): Likewise.
         (trees_out::key_mergeable): Likewise,
         (trees_in::key_mergeable): Likewise.
         (trees_out::decl_node): Adjust for template-decl module flag
         change.
         (depset::hash::make_dependency): Likewise.
         (get_originating_module, module_may_redeclare): Likewise.
         (set_instantiating_module, set_defining_module): Likewise.
         * name-lookup.c (name_lookup::search_adl): Likewise.
         (do_pushdecl): Likewise.
         * pt.c (build_template_decl): Likewise.
         (lookup_template_class_1): Remove special alias_template handling
         of DECL_TI_TEMPLATE.
         (tsubst_template_decl): Likewise.
         gcc/testsuite/
         * g++.dg/modules/pr99283-2_a.H: New.
         * g++.dg/modules/pr99283-2_b.H: New.
         * g++.dg/modules/pr99283-2_c.H: New.
         * g++.dg/modules/pr99283-3_a.H: New.
         * g++.dg/modules/pr99283-3_b.H: New.
         * g++.dg/modules/pr99283-4.H: New.
         * g++.dg/modules/tpl-alias-1_a.H: Adjust scans.
         * g++.dg/modules/tpl-alias-1_b.C: Adjust scans.

Comments

Patrick Palka April 2, 2021, 7:36 p.m. UTC | #1
On Fri, 26 Mar 2021, Nathan Sidwell wrote:

> 
> During development of modules, I had difficulty	deciding whether the module
> flags of a template should live on the decl_template_result, the
> template_decl, or both.  I chose the latter, and require them to be
> consistent.  This and a few other defects show how hard that consistency is.
> Hence this patch move to holding the flags on the template-decl-result decl.
> That's the entity various bits of the parser have at the appropriate time.
> Once needs STRIP_TEMPLATE in a bunch of places, which this patch adds.  Also a
> check that we never give a TEMPLATE_DECL to the module flag accessors.
> 
> This left a problem with how I was handling template aliases.  These were in
> two parts -- separating the TEMPLATE_DECL from the TYPE_DECL. That seemed
> somewhat funky, but development showed it necessary.  Of course, that causes
> problems if the TEMPLATE_DECL cannot contain 'am imported' information.
> Investigating now shows	that we	do not need to treat them separately.	By
> reverting a bit of template instantiation machinery that caused the problem,
> we're back on course.  I think what has happened is that between then and now,
> other typedef fixes have corrected the underlying problem this separation was
> working around. It allows a bunch of cleanup in the decl streamer, as we no
> longer have to handle a null TEMPLATE_DECL_RESULT.
> 
> 
>         PR c++/99283
>         gcc/cp/
>         * cp-tree.h (DECL_MODULE_CHECK): Ban TEMPLATE_DECL.

This seems to cause us to ICE when calling debug_tree on a
TEMPLATE_DECL.  Does the following fix for this look OK?

-- >8 --

Subject: [PATCH] c++: Fix ICE when dumping a TEMPLATE_DECL via debug_tree

This adjusts cxx_print_decl to avoid using the module flag accessors on
a TEMPLATE_DECL after r11-7866 made it an error to do so.

gcc/cp/ChangeLog:

	* ptree.c (cxx_print_decl): Don't check module flags on a
	TEMPLATE_DECL.
---
 gcc/cp/ptree.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index 95a4fdf284a..4c4642eccfe 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -62,7 +62,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
   if (TREE_CODE (node) == FUNCTION_DECL
       || TREE_CODE (node) == VAR_DECL
       || TREE_CODE (node) == TYPE_DECL
-      || TREE_CODE (node) == TEMPLATE_DECL
       || TREE_CODE (node) == CONCEPT_DECL
       || TREE_CODE (node) == NAMESPACE_DECL)
     {
diff mbox series

Patch

diff --git c/gcc/cp/cp-tree.h w/gcc/cp/cp-tree.h
index e68e3905f80..a4d4d69075f 100644
--- c/gcc/cp/cp-tree.h
+++ w/gcc/cp/cp-tree.h
@@ -1661,9 +1661,11 @@  check_constraint_info (tree t)
 #define CONSTRAINED_PARM_PROTOTYPE(NODE) \
   DECL_INITIAL (TYPE_DECL_CHECK (NODE))
 
-/* Module defines.  */
-// Too many _DECLS: FUNCTION,VAR,TYPE,TEMPLATE,CONCEPT or NAMESPACE
-#define DECL_MODULE_CHECK(NODE) (NODE)
+/* Module flags on FUNCTION,VAR,TYPE,CONCEPT or NAMESPACE
+   A TEMPLATE_DECL holds them on the DECL_TEMPLATE_RESULT object --
+   it's just not practical to keep them consistent.  */
+#define DECL_MODULE_CHECK(NODE)						\
+  TREE_NOT_CHECK (NODE, TEMPLATE_DECL)
 
 /* In the purview of a module (including header unit).  */
 #define DECL_MODULE_PURVIEW_P(N) \
@@ -3626,9 +3628,10 @@  struct GTY(()) lang_decl {
 /* Set the template information for a non-alias n ENUMERAL_, RECORD_,
    or UNION_TYPE to VAL.  ALIAS's are dealt with separately.  */
 #define SET_TYPE_TEMPLATE_INFO(NODE, VAL)				\
-  (gcc_checking_assert (TREE_CODE (NODE) == ENUMERAL_TYPE		\
-			|| (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))), \
-   (TYPE_LANG_SLOT_1 (NODE) = (VAL)))					\
+  (TREE_CODE (NODE) == ENUMERAL_TYPE		\
+   || (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))			\
+   ? (TYPE_LANG_SLOT_1 (NODE) = (VAL))					\
+   : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL)))			\
 
 #define TI_TEMPLATE(NODE) \
   ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->tmpl
diff --git c/gcc/cp/decl.c w/gcc/cp/decl.c
index 3483b0c0398..6789aa859cc 100644
--- c/gcc/cp/decl.c
+++ w/gcc/cp/decl.c
@@ -2275,10 +2275,6 @@  duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	    }
 	}
 
-      DECL_MODULE_IMPORT_P (olddecl)
-	= DECL_MODULE_IMPORT_P (old_result)
-	= DECL_MODULE_IMPORT_P (newdecl);
-
       return olddecl;
     }
 
@@ -2931,19 +2927,6 @@  duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	}
     }
 
-  if (DECL_LANG_SPECIFIC (olddecl) && DECL_TEMPLATE_INFO (olddecl))
-    {
-      /* Repropagate the module information to the template.  */
-      tree tmpl = DECL_TI_TEMPLATE (olddecl);
-
-      if (DECL_TEMPLATE_RESULT (tmpl) == olddecl)
-	{
-	  DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (olddecl);
-	  gcc_checking_assert (!DECL_MODULE_IMPORT_P (olddecl));
-	  DECL_MODULE_IMPORT_P (tmpl) = false;
-	}
-    }
-
   if (VAR_OR_FUNCTION_DECL_P (newdecl))
     {
       if (DECL_EXTERNAL (olddecl)
diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index e4da5557f9e..8a1cfbdfdcb 100644
--- c/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -2797,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", NULL,			/* 22,23 alias. */
+    "alias spec", "alias tmpl spec",	/* 22,23 alias (template). */
     NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL,
   };
@@ -4144,10 +4144,17 @@  dumper::impl::nested_name (tree t)
       if (ti && TREE_CODE (TI_TEMPLATE (ti)) == TEMPLATE_DECL
 	  && (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == t))
 	t = TI_TEMPLATE (ti);
+      tree not_tmpl = t;
       if (TREE_CODE (t) == TEMPLATE_DECL)
-	fputs ("template ", stream);
+	{
+	  fputs ("template ", stream);
+	  not_tmpl = DECL_TEMPLATE_RESULT (t);
+	}
 
-      if (DECL_LANG_SPECIFIC (t) && DECL_MODULE_IMPORT_P (t))
+      if (not_tmpl
+	  && DECL_P (not_tmpl)
+	  && DECL_LANG_SPECIFIC (not_tmpl)
+	  && DECL_MODULE_IMPORT_P (not_tmpl))
 	{
 	  /* We need to be careful here, so as to not explode on
 	     inconsistent data -- we're probably debugging, because
@@ -4484,9 +4491,9 @@  trees_in::assert_definition (tree decl ATTRIBUTE_UNUSED,
     gcc_assert (!is_duplicate (decl)
 		? !slot
 		: (slot
-		   || !DECL_LANG_SPECIFIC (decl)
-		   || !DECL_MODULE_PURVIEW_P (decl)
-		   || (!DECL_MODULE_IMPORT_P (decl)
+		   || !DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl))
+		   || !DECL_MODULE_PURVIEW_P (STRIP_TEMPLATE (decl))
+		   || (!DECL_MODULE_IMPORT_P (STRIP_TEMPLATE (decl))
 		       && header_module_p ())));
 
   if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -7445,11 +7452,12 @@  trees_in::install_entity (tree decl)
   (*entity_ary)[ident] = decl;
 
   /* And into the entity map, if it's not already there.  */
-  if (!DECL_LANG_SPECIFIC (decl)
-      || !DECL_MODULE_ENTITY_P (decl))
+  tree not_tmpl = STRIP_TEMPLATE (decl);
+  if (!DECL_LANG_SPECIFIC (not_tmpl)
+      || !DECL_MODULE_ENTITY_P (not_tmpl))
     {
-      retrofit_lang_decl (decl);
-      DECL_MODULE_ENTITY_P (decl) = true;
+      retrofit_lang_decl (not_tmpl);
+      DECL_MODULE_ENTITY_P (not_tmpl) = true;
 
       /* Insert into the entity hash (it cannot already be there).  */
       bool existed;
@@ -7510,12 +7518,11 @@  trees_out::decl_value (tree decl, depset *dep)
 	      tree o = get_originating_module_decl (decl);
 	      bool is_mod = false;
 
-	      if (dep && dep->is_alias_tmpl_inst ())
-		/* Alias template instantiations are templatey, but
-		   found by name.  */
-		is_mod = false;
-	      else if (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o))
+	      tree not_tmpl = STRIP_TEMPLATE (o);
+	      if (DECL_LANG_SPECIFIC (not_tmpl)
+		  && DECL_MODULE_PURVIEW_P (not_tmpl))
 		is_mod = true;
+
 	      b (is_mod);
 	    }
 	  b (dep && dep->has_defn ());
@@ -7533,26 +7540,18 @@  trees_out::decl_value (tree decl, depset *dep)
   int inner_tag = 0;
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
-      if (dep && dep->is_alias_tmpl_inst ())
-	inner = NULL_TREE;
-      else
-	{
-	  inner = DECL_TEMPLATE_RESULT (decl);
-	  inner_tag = insert (inner, WK_value);
-	}
+      inner = DECL_TEMPLATE_RESULT (decl);
+      inner_tag = insert (inner, WK_value);
 
       if (streaming_p ())
 	{
-	  int code = inner ? TREE_CODE (inner) : 0;
+	  int code = TREE_CODE (inner);
 	  u (code);
-	  if (inner)
-	    {
-	      start (inner, true);
-	      tree_node_bools (inner);
-	      dump (dumper::TREE)
-		&& dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], inner_tag,
-			 TREE_CODE (inner), inner, inner);
-	    }
+	  start (inner, true);
+	  tree_node_bools (inner);
+	  dump (dumper::TREE)
+	    && dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], inner_tag,
+		     TREE_CODE (inner), inner, inner);
 	}
     }
 
@@ -7560,7 +7559,7 @@  trees_out::decl_value (tree decl, depset *dep)
   int type_tag = 0;
   tree stub_decl = NULL_TREE;
   int stub_tag = 0;
-  if (inner && TREE_CODE (inner) == TYPE_DECL)
+  if (TREE_CODE (inner) == TYPE_DECL)
     {
       type = TREE_TYPE (inner);
       bool has_type = (type == TYPE_MAIN_VARIANT (type)
@@ -7612,7 +7611,7 @@  trees_out::decl_value (tree decl, depset *dep)
   unsigned tpl_levels = 0;
   if (decl != inner)
     tpl_header (decl, &tpl_levels);
-  if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+  if (TREE_CODE (inner) == FUNCTION_DECL)
     fn_parms_init (inner);
 
   /* Now write out the merging information, and then really
@@ -7624,7 +7623,7 @@  trees_out::decl_value (tree decl, depset *dep)
       && dump ("Wrote:%d's %s merge key %C:%N", tag,
 	       merge_kind_name[mk], TREE_CODE (decl), decl);
 
-  if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+  if (TREE_CODE (inner) == FUNCTION_DECL)
     fn_parms_fini (inner);
 
   if (!is_key_order ())
@@ -7636,18 +7635,6 @@  trees_out::decl_value (tree decl, depset *dep)
 	tree_node_vals (inner);
       tpl_parms_fini (decl, tpl_levels);
     }
-  else if (!inner)
-    {
-      /* A template alias instantiation.  */
-      inner = DECL_TEMPLATE_RESULT (decl);
-      if (!is_key_order ())
-	tree_node (inner);
-      if (streaming_p ())
-	dump (dumper::TREE)
-	  && dump ("Wrote(%d) alias template %C:%N",
-		   get_tag (inner), TREE_CODE (inner), inner);
-      inner = NULL_TREE;
-    }
 
   if (type && !is_key_order ())
     {
@@ -7693,8 +7680,7 @@  trees_out::decl_value (tree decl, depset *dep)
       install_entity (decl, dep);
     }
 
-  if (inner
-      && VAR_OR_FUNCTION_DECL_P (inner)
+  if (VAR_OR_FUNCTION_DECL_P (inner)
       && DECL_LANG_SPECIFIC (inner)
       && DECL_MODULE_ATTACHMENTS_P (inner)
       && !is_key_order ())
@@ -7715,7 +7701,7 @@  trees_out::decl_value (tree decl, depset *dep)
     }
 
   bool is_typedef = false;
-  if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
+  if (!type && TREE_CODE (inner) == TYPE_DECL)
     {
       tree t = TREE_TYPE (inner);
       unsigned tdef_flags = 0;
@@ -7766,10 +7752,9 @@  trees_out::decl_value (tree decl, depset *dep)
     dump (dumper::TREE) && dump ("Written decl:%d %C:%N", tag,
 				 TREE_CODE (decl), decl);
 
-  if (!inner || NAMESPACE_SCOPE_P (inner))
-    gcc_checking_assert (!inner
-			 || !dep == (VAR_OR_FUNCTION_DECL_P (inner)
-				     && DECL_LOCAL_DECL_P (inner)));
+  if (NAMESPACE_SCOPE_P (inner))
+    gcc_checking_assert (!dep == (VAR_OR_FUNCTION_DECL_P (inner)
+				  && DECL_LOCAL_DECL_P (inner)));
   else if ((TREE_CODE (inner) == TYPE_DECL
 	    && !is_typedef
 	    && TYPE_NAME (TREE_TYPE (inner)) == inner)
@@ -7828,31 +7813,23 @@  trees_in::decl_value ()
   if (decl && TREE_CODE (decl) == TEMPLATE_DECL)
     {
       int code = u ();
-      if (!code)
-	{
-	  inner = NULL_TREE;
-	  DECL_TEMPLATE_RESULT (decl) = error_mark_node;
-	}
+      inner = start (code);
+      if (inner && tree_node_bools (inner))
+	DECL_TEMPLATE_RESULT (decl) = inner;
       else
-	{
-	  inner = start (code);
-	  if (inner && tree_node_bools (inner))
-	    DECL_TEMPLATE_RESULT (decl) = inner;
-	  else
-	    decl = NULL_TREE;
+	decl = NULL_TREE;
 
-	  inner_tag = insert (inner);
-	  if (decl)
-	    dump (dumper::TREE)
-	      && dump ("Reading:%d %C", inner_tag, TREE_CODE (inner));
-	}
+      inner_tag = insert (inner);
+      if (decl)
+	dump (dumper::TREE)
+	  && dump ("Reading:%d %C", inner_tag, TREE_CODE (inner));
     }
 
   tree type = NULL_TREE;
   int type_tag = 0;
   tree stub_decl = NULL_TREE;
   int stub_tag = 0;
-  if (decl && inner && TREE_CODE (inner) == TYPE_DECL)
+  if (decl && TREE_CODE (inner) == TYPE_DECL)
     {
       if (unsigned type_code = u ())
 	{
@@ -7917,7 +7894,7 @@  trees_in::decl_value ()
   if (decl != inner)
     if (!tpl_header (decl, &tpl_levels))
       goto bail;
-  if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+  if (TREE_CODE (inner) == FUNCTION_DECL)
     parm_tag = fn_parms_init (inner);
 
   tree existing = key_mergeable (tag, mk, decl, inner, type, container, is_mod);
@@ -7972,15 +7949,6 @@  trees_in::decl_value ()
       if (!tpl_parms_fini (decl, tpl_levels))
 	goto bail;
     }
-  else if (!inner)
-    {
-      inner = tree_node ();
-      DECL_TEMPLATE_RESULT (decl) = inner;
-      TREE_TYPE (decl) = TREE_TYPE (inner);
-      dump (dumper::TREE)
-	&& dump ("Read alias template %C:%N", TREE_CODE (inner), inner);
-      inner = NULL_TREE;
-    }
 
   if (type && (!tree_node_vals (type)
 	       || (stub_decl && !tree_node_vals (stub_decl))))
@@ -8009,8 +7977,7 @@  trees_in::decl_value ()
   bool installed = install_entity (existing);
   bool is_new = existing == decl;
 
-  if (inner
-      && VAR_OR_FUNCTION_DECL_P (inner)
+  if (VAR_OR_FUNCTION_DECL_P (inner)
       && DECL_LANG_SPECIFIC (inner)
       && DECL_MODULE_ATTACHMENTS_P (inner))
     {
@@ -8039,7 +8006,7 @@  trees_in::decl_value ()
   /* Regular typedefs will have a NULL TREE_TYPE at this point.  */
   unsigned tdef_flags = 0;
   bool is_typedef = false;
-  if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
+  if (!type && TREE_CODE (inner) == TYPE_DECL)
     {
       tdef_flags = u ();
       if (tdef_flags & 1)
@@ -8056,15 +8023,9 @@  trees_in::decl_value ()
 
       if (installed)
 	{
-	  /* Mark the entity as imported and add it to the entity
-	     array and map.  */
-	  retrofit_lang_decl (decl);
-	  DECL_MODULE_IMPORT_P (decl) = true;
-	  if (inner_tag)
-	    {
-	      retrofit_lang_decl (inner);
-	      DECL_MODULE_IMPORT_P (inner) = true;
-	    }
+	  /* Mark the entity as imported.  */
+	  retrofit_lang_decl (inner);
+	  DECL_MODULE_IMPORT_P (inner) = true;
 	}
 
       if (spec.spec)
@@ -8158,7 +8119,7 @@  trees_in::decl_value ()
       if (!is_matching_decl (existing, decl, is_typedef))
 	unmatched_duplicate (existing);
 
-      if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+      if (TREE_CODE (inner) == FUNCTION_DECL)
 	{
 	  tree e_inner = STRIP_TEMPLATE (existing);
 	  for (auto parm = DECL_ARGUMENTS (inner);
@@ -8211,8 +8172,7 @@  trees_in::decl_value ()
 	}
     }
 
-  if (inner
-      && !NAMESPACE_SCOPE_P (inner)
+  if (!NAMESPACE_SCOPE_P (inner)
       && ((TREE_CODE (inner) == TYPE_DECL
 	   && !is_typedef
 	   && TYPE_NAME (TREE_TYPE (inner)) == inner)
@@ -8550,7 +8510,8 @@  trees_out::decl_node (tree decl, walk_kind ref)
   else if (TREE_CODE (ctx) != FUNCTION_DECL
 	   || TREE_CODE (decl) == TEMPLATE_DECL
 	   || (dep_hash->sneakoscope && DECL_IMPLICIT_TYPEDEF_P (decl))
-	   || (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl)))
+	   || (DECL_LANG_SPECIFIC (decl)
+	       && DECL_MODULE_IMPORT_P (decl)))
     {
       auto kind = (TREE_CODE (decl) == NAMESPACE_DECL
 		   && !DECL_NAMESPACE_ALIAS (decl)
@@ -8607,6 +8568,7 @@  trees_out::decl_node (tree decl, walk_kind ref)
       else
 	{
 	  tree o = get_originating_module_decl (decl);
+	  o = STRIP_TEMPLATE (o);
 	  kind = (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o)
 		  ? "purview" : "GMF");
 	}
@@ -10371,7 +10333,7 @@  trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 		gcc_checking_assert
 		  (match_mergeable_specialization (false, entry)
 		   == TREE_TYPE (existing));
-	      else if (mk & MK_tmpl_tmpl_mask)
+	      if (mk & MK_tmpl_tmpl_mask)
 		existing = DECL_TI_TEMPLATE (existing);
 	    }
 	  else
@@ -10401,7 +10363,7 @@  trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	  if (IDENTIFIER_CONV_OP_P (name))
 	    name = conv_op_identifier;
 
-	  if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+	  if (TREE_CODE (inner) == FUNCTION_DECL)
 	    {
 	      /* Functions are distinguished by parameter types.  */
 	      tree fn_type = TREE_TYPE (inner);
@@ -10737,7 +10699,7 @@  trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	key.ret = tree_node ();
       else if (mk == MK_partial
 	       || ((mk == MK_named || mk == MK_friend_spec)
-		   && inner && TREE_CODE (inner) == FUNCTION_DECL))
+		   && TREE_CODE (inner) == FUNCTION_DECL))
 	{
 	  key.ret = tree_node ();
 	  tree arg, *arg_ptr = &key.args;
@@ -10760,11 +10722,8 @@  trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 	  DECL_NAME (decl) = name;
 	  DECL_CONTEXT (decl) = FROB_CONTEXT (container);
 	}
-      if (inner)
-	{
-	  DECL_NAME (inner) = DECL_NAME (decl);
-	  DECL_CONTEXT (inner) = DECL_CONTEXT (decl);
-	}
+      DECL_NAME (inner) = DECL_NAME (decl);
+      DECL_CONTEXT (inner) = DECL_CONTEXT (decl);
 
       if (mk == MK_partial)
 	{
@@ -12383,20 +12342,9 @@  depset::hash::make_dependency (tree decl, entity_kind ek)
     gcc_checking_assert (TREE_CODE (decl) == OVERLOAD);
 
   if (TREE_CODE (decl) == TEMPLATE_DECL)
-    {
-      /* The template should have copied these from its result decl.  */
-      tree res = DECL_TEMPLATE_RESULT (decl);
-
-      gcc_checking_assert (DECL_MODULE_EXPORT_P (decl)
-			   == DECL_MODULE_EXPORT_P (res));
-      if (DECL_LANG_SPECIFIC (res))
-	{
-	  gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl)
-			       == DECL_MODULE_PURVIEW_P (res));
-	  gcc_checking_assert ((DECL_MODULE_IMPORT_P (decl)
-				== DECL_MODULE_IMPORT_P (res)));
-	}
-    }
+    /* The template should have copied these from its result decl.  */
+    gcc_checking_assert (DECL_MODULE_EXPORT_P (decl)
+			 == DECL_MODULE_EXPORT_P (DECL_TEMPLATE_RESULT (decl)));
 
   depset **slot = entity_slot (decl, true);
   depset *dep = *slot;
@@ -12444,11 +12392,6 @@  depset::hash::make_dependency (tree decl, entity_kind ek)
 
 	      *slot = redirect;
 
-	      if (DECL_LANG_SPECIFIC (decl))
-		{
-		  DECL_MODULE_IMPORT_P (partial) = DECL_MODULE_IMPORT_P (decl);
-		  DECL_MODULE_PURVIEW_P (partial) = DECL_MODULE_PURVIEW_P (decl);
-		}
 	      depset *tmpl_dep = make_dependency (partial, EK_PARTIAL);
 	      gcc_checking_assert (tmpl_dep->get_entity_kind () == EK_PARTIAL);
 
@@ -12478,46 +12421,48 @@  depset::hash::make_dependency (tree decl, entity_kind ek)
 				   && !(*eslot)->deps.length ());
 	}
 
-      if (ek != EK_USING
-	  && DECL_LANG_SPECIFIC (decl)
-	  && DECL_MODULE_IMPORT_P (decl))
+      if (ek != EK_USING)
 	{
-	  /* Store the module number and index in cluster/section, so
-	     we don't have to look them up again.  */
-	  unsigned index = import_entity_index (decl);
-	  module_state *from = import_entity_module (index);
-	  /* Remap will be zero for imports from partitions, which we
-	     want to treat as-if declared in this TU.  */
-	  if (from->remap)
+	  tree not_tmpl = STRIP_TEMPLATE (decl);
+
+	  if (DECL_LANG_SPECIFIC (not_tmpl)
+	      && DECL_MODULE_IMPORT_P (not_tmpl))
 	    {
-	      dep->cluster = index - from->entity_lwm;
-	      dep->section = from->remap;
-	      dep->set_flag_bit<DB_IMPORTED_BIT> ();
+	      /* Store the module number and index in cluster/section,
+		 so we don't have to look them up again.  */
+	      unsigned index = import_entity_index (decl);
+	      module_state *from = import_entity_module (index);
+	      /* Remap will be zero for imports from partitions, which
+		 we want to treat as-if declared in this TU.  */
+	      if (from->remap)
+		{
+		  dep->cluster = index - from->entity_lwm;
+		  dep->section = from->remap;
+		  dep->set_flag_bit<DB_IMPORTED_BIT> ();
+		}
 	    }
-	}
 
-      if (ek == EK_DECL
-	  && !dep->is_import ()
-	  && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL
-	  && !(TREE_CODE (decl) == TEMPLATE_DECL
-	       && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)))
-	{
-	  tree ctx = CP_DECL_CONTEXT (decl);
-	  tree not_tmpl = STRIP_TEMPLATE (decl);
-
-	  if (!TREE_PUBLIC (ctx))
-	    /* Member of internal namespace.  */
-	    dep->set_flag_bit<DB_IS_INTERNAL_BIT> ();
-	  else if (VAR_OR_FUNCTION_DECL_P (not_tmpl)
-		   && DECL_THIS_STATIC (not_tmpl))
+	  if (ek == EK_DECL
+	      && !dep->is_import ()
+	      && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL
+	      && !(TREE_CODE (decl) == TEMPLATE_DECL
+		   && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)))
 	    {
-	      /* An internal decl.  This is ok in a GM entity.  */
-	      if (!(header_module_p ()
-		    || !DECL_LANG_SPECIFIC (not_tmpl)
-		    || !DECL_MODULE_PURVIEW_P (not_tmpl)))
+	      tree ctx = CP_DECL_CONTEXT (decl);
+
+	      if (!TREE_PUBLIC (ctx))
+		/* Member of internal namespace.  */
 		dep->set_flag_bit<DB_IS_INTERNAL_BIT> ();
+	      else if (VAR_OR_FUNCTION_DECL_P (not_tmpl)
+		       && DECL_THIS_STATIC (not_tmpl))
+		{
+		  /* An internal decl.  This is ok in a GM entity.  */
+		  if (!(header_module_p ()
+			|| !DECL_LANG_SPECIFIC (not_tmpl)
+			|| !DECL_MODULE_PURVIEW_P (not_tmpl)))
+		    dep->set_flag_bit<DB_IS_INTERNAL_BIT> ();
+		}
 	    }
-
 	}
 
       if (!dep->is_import ())
@@ -18394,15 +18339,16 @@  int
 get_originating_module (tree decl, bool for_mangle)
 {
   tree owner = get_originating_module_decl (decl);
+  tree not_tmpl = STRIP_TEMPLATE (owner);
 
-  if (!DECL_LANG_SPECIFIC (owner))
+  if (!DECL_LANG_SPECIFIC (not_tmpl))
     return for_mangle ? -1 : 0;
 
   if (for_mangle
-      && (DECL_MODULE_EXPORT_P (owner) || !DECL_MODULE_PURVIEW_P (owner)))
+      && (DECL_MODULE_EXPORT_P (owner) || !DECL_MODULE_PURVIEW_P (not_tmpl)))
     return -1;
 
-  if (!DECL_MODULE_IMPORT_P (owner))
+  if (!DECL_MODULE_IMPORT_P (not_tmpl))
     return 0;
 
   return get_importing_module (owner);
@@ -18426,7 +18372,8 @@  module_may_redeclare (tree decl)
 {
   module_state *me = (*modules)[0];
   module_state *them = me;
-  if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl))
+  tree not_tmpl = STRIP_TEMPLATE (decl);
+  if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_IMPORT_P (not_tmpl))
     {
       /* We can be given the TEMPLATE_RESULT.  We want the
 	 TEMPLATE_DECL.  */
@@ -18468,15 +18415,15 @@  module_may_redeclare (tree decl)
     }
 
   if (me == them)
-    return ((DECL_LANG_SPECIFIC (decl) && DECL_MODULE_PURVIEW_P (decl))
+    return ((DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_PURVIEW_P (not_tmpl))
 	    == module_purview_p ());
 
   if (!me->name)
     me = me->parent;
 
   /* We can't have found a GMF entity from a named module.  */
-  gcc_checking_assert (DECL_LANG_SPECIFIC (decl)
-		       && DECL_MODULE_PURVIEW_P (decl));
+  gcc_checking_assert (DECL_LANG_SPECIFIC (not_tmpl)
+		       && DECL_MODULE_PURVIEW_P (not_tmpl));
 
   return me && get_primary (them) == get_primary (me);
 }
@@ -18500,20 +18447,16 @@  set_instantiating_module (tree decl)
   if (!modules_p ())
     return;
 
+  decl = STRIP_TEMPLATE (decl);
+
   if (!DECL_LANG_SPECIFIC (decl) && module_purview_p ())
     retrofit_lang_decl (decl);
+
   if (DECL_LANG_SPECIFIC (decl))
     {
       DECL_MODULE_PURVIEW_P (decl) = module_purview_p ();
       /* If this was imported, we'll still be in the entity_hash.  */
       DECL_MODULE_IMPORT_P (decl) = false;
-      if (TREE_CODE (decl) == TEMPLATE_DECL)
-	{
-	  tree res = DECL_TEMPLATE_RESULT (decl);
-	  retrofit_lang_decl (res);
-	  DECL_MODULE_PURVIEW_P (res) = DECL_MODULE_PURVIEW_P (decl);
-	  DECL_MODULE_IMPORT_P (res) = false;
-	}
     }
 }
 
@@ -18547,7 +18490,6 @@  set_defining_module (tree decl)
 		  gcc_checking_assert (!use_tpl);
 		  /* Get to the TEMPLATE_DECL.  */
 		  decl = TI_TEMPLATE (ti);
-		  gcc_checking_assert (!DECL_MODULE_IMPORT_P (decl));
 		}
 
 	      /* Record it on the class_members list.  */
diff --git c/gcc/cp/name-lookup.c w/gcc/cp/name-lookup.c
index f4263f15f62..3bce3d597dc 100644
--- c/gcc/cp/name-lookup.c
+++ w/gcc/cp/name-lookup.c
@@ -1666,8 +1666,9 @@  name_lookup::search_adl (tree fns, vec<tree, va_gc> *args)
 		continue;
 
 	      tree origin = get_originating_module_decl (TYPE_NAME (scope));
-	      if (!DECL_LANG_SPECIFIC (origin)
-		  || !DECL_MODULE_IMPORT_P (origin))
+	      tree not_tmpl = STRIP_TEMPLATE (origin);
+	      if (!DECL_LANG_SPECIFIC (not_tmpl)
+		  || !DECL_MODULE_IMPORT_P (not_tmpl))
 		/* Not imported.  */
 		continue;
 
@@ -3680,6 +3681,7 @@  do_pushdecl (tree decl, bool hiding)
 	if (iter.using_p ())
 	  ; /* Ignore using decls here.  */
 	else if (iter.hidden_p ()
+		 && TREE_CODE (*iter) == FUNCTION_DECL
 		 && DECL_LANG_SPECIFIC (*iter)
 		 && DECL_MODULE_IMPORT_P (*iter))
 	  ; /* An undeclared builtin imported from elsewhere.  */
diff --git c/gcc/cp/pt.c w/gcc/cp/pt.c
index 2736bb43299..a056ecefd1d 100644
--- c/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -4930,16 +4930,8 @@  build_template_decl (tree decl, tree parms, bool member_template_p)
   DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl);
   DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p;
 
-  if (modules_p ())
-    {
-      /* Propagate module information from the decl.  */
-      DECL_MODULE_EXPORT_P (tmpl) = DECL_MODULE_EXPORT_P (decl);
-      if (DECL_LANG_SPECIFIC (decl))
-	{
-	  DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (decl);
-	  gcc_checking_assert (!DECL_MODULE_IMPORT_P (decl));
-	}
-    }
+  /* Propagate module information from the decl.  */
+  DECL_MODULE_EXPORT_P (tmpl) = DECL_MODULE_EXPORT_P (decl);
 
   return tmpl;
 }
@@ -10167,25 +10159,7 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	}
 
       /* Build template info for the new specialization.  */
-      if (TYPE_ALIAS_P (t))
-	{
-	  /* This is constructed during instantiation of the alias
-	     decl.  But for member templates of template classes, that
-	     is not correct as we need to refer to the partially
-	     instantiated template, not the most general template.
-	     The incorrect knowledge will not have escaped this
-	     instantiation process, so we're good just updating the
-	     template_info we made then.  */
-	  tree ti = DECL_TEMPLATE_INFO (TYPE_NAME (t));
-	  gcc_checking_assert (template_args_equal (TI_ARGS (ti), arglist));
-	  if (TI_TEMPLATE (ti) != found)
-	    {
-	      gcc_checking_assert (DECL_TI_TEMPLATE (found) == TI_TEMPLATE (ti));
-	      TI_TEMPLATE (ti) = found;
-	    }
-	}
-      else
-	SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
+      SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
 
       elt.spec = t;
       slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
@@ -14297,8 +14271,7 @@  tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
     }
   else
     {
-      if (TREE_CODE (decl) != TYPE_DECL || !TYPE_DECL_ALIAS_P (decl))
-	DECL_TI_TEMPLATE (inner) = r;
+      DECL_TI_TEMPLATE (inner) = r;
       DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
     }
 
@@ -14311,17 +14284,13 @@  tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
       /* Propagate module information from the decl.  */
       DECL_MODULE_EXPORT_P (r) = DECL_MODULE_EXPORT_P (inner);
       if (DECL_LANG_SPECIFIC (inner))
-	{
-	  DECL_MODULE_PURVIEW_P (r) = DECL_MODULE_PURVIEW_P (inner);
-	  /* If this is a constrained template, the above tsubst of
-	     inner can find the unconstrained template, which may have
-	     come from an import.  This is ok, because we don't
-	     register this instantiation (see below).  */
-	  gcc_checking_assert (!DECL_MODULE_IMPORT_P (inner)
-			       || (TEMPLATE_PARMS_CONSTRAINTS
-				   (DECL_TEMPLATE_PARMS (t))));
-	  DECL_MODULE_IMPORT_P (r) = false;
-	}
+	/* If this is a constrained template, the above tsubst of
+	   inner can find the unconstrained template, which may have
+	   come from an import.  This is ok, because we don't
+	   register this instantiation (see below).  */
+	gcc_checking_assert (!DECL_MODULE_IMPORT_P (inner)
+			     || (TEMPLATE_PARMS_CONSTRAINTS
+				 (DECL_TEMPLATE_PARMS (t))));
     }
 
   DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-2_a.H w/gcc/testsuite/g++.dg/modules/pr99283-2_a.H
new file mode 100644
index 00000000000..c5faf1d6205
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-2_a.H
@@ -0,0 +1,12 @@ 
+// PR 99283 part 2 ICE on definition with qualified-name
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+inline namespace __cxx11 {
+
+template<typename _CharT>
+class collate;
+
+}
+       
+
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-2_b.H w/gcc/testsuite/g++.dg/modules/pr99283-2_b.H
new file mode 100644
index 00000000000..a1b7d603ff7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-2_b.H
@@ -0,0 +1,22 @@ 
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+import  "pr99283-2_a.H";
+
+inline namespace __cxx11 {
+template<typename _CharT>
+class collate
+{
+};
+}
+
+template<typename _CharT>
+void Check ()
+{
+  typedef collate<char> __collate_type;
+}
+
+
+
+
+
+
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-2_c.H w/gcc/testsuite/g++.dg/modules/pr99283-2_c.H
new file mode 100644
index 00000000000..82639282f07
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-2_c.H
@@ -0,0 +1,20 @@ 
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+import  "pr99283-2_a.H";
+
+template<typename _CharT>
+class __cxx11::collate
+{
+};
+
+template<typename _CharT>
+void Check ()
+{
+  typedef collate<char> __collate_type;
+}
+
+
+
+
+
+
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-3_a.H w/gcc/testsuite/g++.dg/modules/pr99283-3_a.H
new file mode 100644
index 00000000000..5926b9d2672
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-3_a.H
@@ -0,0 +1,31 @@ 
+// PR 99283 part 2 ICE on definition with qualified-name
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<bool, typename _Tp>
+struct enable_if;
+
+template<typename _Tp>
+struct enable_if<true, _Tp>
+{ typedef _Tp type; };
+
+template<typename _CharT>
+class basic_string;
+
+typedef basic_string<char> string;
+
+template<typename _CharT>
+class basic_string
+{
+private:
+  template<typename _Tp>
+  using _If_sv = typename enable_if<true, int>::type;
+
+public:
+  const _CharT *c_str() const noexcept;
+};
+
+inline void stoi(const string& __str)
+{
+  __str.c_str ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-3_b.H w/gcc/testsuite/g++.dg/modules/pr99283-3_b.H
new file mode 100644
index 00000000000..cb14de613e3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-3_b.H
@@ -0,0 +1,9 @@ 
+// { dg-additional-options {-fmodule-header -fno-module-lazy} }
+// { dg-module-cmi {} }
+
+template<typename _CharT>
+class basic_string;
+
+typedef basic_string<char> string;
+
+import  "pr99283-3_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/pr99283-4.H w/gcc/testsuite/g++.dg/modules/pr99283-4.H
new file mode 100644
index 00000000000..d15ccc440b7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99283-4.H
@@ -0,0 +1,20 @@ 
+// PR 99283 part 3, ICE with template alias as default template parm
+// of member template
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename _Traits>
+struct _Insert
+{
+  using size_type = int;
+  
+  template<typename _Pair>
+  using _IFconsp = bool;
+
+  template<typename _Pair, typename = _IFconsp<_Pair>>
+  int insert (_Pair&& __v);
+};
+
+void Foo (typename _Insert<int>::size_type);
+
+
diff --git c/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
index 502a649c74d..37002ee9ae1 100644
--- c/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
+++ w/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
@@ -3,7 +3,7 @@ 
 
 #include "tpl-alias-1.h"
 
-// { dg-final { scan-lang-dump {Writing named:-[0-9]* template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
-// { dg-final { scan-lang-dump {Writing decl spec:-[0-9]* type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
-// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
-// { dg-final { scan-lang-dump {Wrote\(-[0-9]*\) alias template type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
+// { 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 } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C
index 59fd09c0454..cc9499f54fc 100644
--- c/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C
+++ w/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C
@@ -3,7 +3,8 @@ 
 #include "tpl-alias-1.h"
 import "tpl-alias-1_a.H";
 
-// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc'} module } }
-// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl spec merge key \(matched\) type_decl:'::allocator_traits<::allocator<_Tp>>::rebind_alloc'} module } }
-// { dg-final { scan-lang-dump {Read alias template type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump {Deduping '::allocator_traits<::allocator<_Tp>>::template rebind_alloc'} module } }
+// { dg-final { scan-lang-dump {Deduping '::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump {Deduping '::allocator_traits<::allocator<long int>>::rebind_alloc<long int>'} module } }
+
 // { dg-final { scan-lang-dump-not {merge key \(new\)} module } }