diff mbox series

[1/4] c++/modules: Don't emit unused GMF partial specializations [PR114630]

Message ID 6632129e.050a0220.c5fe4.327c@mx.google.com
State New
Headers show
Series c++/modules: Fix missed GMF discarding | expand

Commit Message

Nathaniel Shead May 1, 2024, 9:59 a.m. UTC
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >8 --

The change in r14-8408 to also emit partial specializations in the
global module fragment caused the regression in the linked PR; this
patch fixes this by restricting emitted GM partial specializations to
those that are actually used.

	PR c++/114630

gcc/cp/ChangeLog:

	* module.cc (depset::hash::add_partial_entities): Mark GM
	specializations as unreached.
	(depset::hash::find_dependencies): Also reach entities in the
	DECL_TEMPLATE_SPECIALIZATIONS list.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/partial-3.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                         | 75 +++++++++++++++---------
 gcc/testsuite/g++.dg/modules/partial-3.C | 20 +++++++
 2 files changed, 66 insertions(+), 29 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/partial-3.C

Comments

Jason Merrill May 1, 2024, 3:29 p.m. UTC | #1
On 5/1/24 02:59, Nathaniel Shead wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

OK.

> -- >8 --
> 
> The change in r14-8408 to also emit partial specializations in the
> global module fragment caused the regression in the linked PR; this
> patch fixes this by restricting emitted GM partial specializations to
> those that are actually used.
> 
> 	PR c++/114630
> 
> gcc/cp/ChangeLog:
> 
> 	* module.cc (depset::hash::add_partial_entities): Mark GM
> 	specializations as unreached.
> 	(depset::hash::find_dependencies): Also reach entities in the
> 	DECL_TEMPLATE_SPECIALIZATIONS list.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/partial-3.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/module.cc                         | 75 +++++++++++++++---------
>   gcc/testsuite/g++.dg/modules/partial-3.C | 20 +++++++
>   2 files changed, 66 insertions(+), 29 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/modules/partial-3.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index fac0301d80e..02b0ab3d687 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -13304,14 +13304,22 @@ depset::hash::add_partial_entities (vec<tree, va_gc> *partial_classes)
>         depset *dep = make_dependency (inner, depset::EK_DECL);
>   
>         if (dep->get_entity_kind () == depset::EK_REDIRECT)
> -	/* We should have recorded the template as a partial
> -	   specialization.  */
> -	gcc_checking_assert (dep->deps[0]->get_entity_kind ()
> -			     == depset::EK_PARTIAL);
> +	{
> +	  dep = dep->deps[0];
> +	  /* We should have recorded the template as a partial
> +	     specialization.  */
> +	  gcc_checking_assert (dep->get_entity_kind ()
> +			       == depset::EK_PARTIAL);
> +	}
>         else
>   	/* It was an explicit specialization, not a partial one.  */
>   	gcc_checking_assert (dep->get_entity_kind ()
>   			     == depset::EK_SPECIALIZATION);
> +
> +      /* Only emit GM entities if reached.  */
> +      if (!DECL_LANG_SPECIFIC (inner)
> +	  || !DECL_MODULE_PURVIEW_P (inner))
> +	dep->set_flag_bit<DB_UNREACHED_BIT> ();
>       }
>   }
>   
> @@ -13632,31 +13640,40 @@ depset::hash::find_dependencies (module_state *module)
>   	      if (!walker.is_key_order ()
>   		  && TREE_CODE (decl) == TEMPLATE_DECL
>   		  && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
> -		/* Mark all the explicit & partial specializations as
> -		   reachable.  */
> -		for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
> -		     cons; cons = TREE_CHAIN (cons))
> -		  {
> -		    tree spec = TREE_VALUE (cons);
> -		    if (TYPE_P (spec))
> -		      spec = TYPE_NAME (spec);
> -		    int use_tpl;
> -		    node_template_info (spec, use_tpl);
> -		    if (use_tpl & 2)
> -		      {
> -			depset *spec_dep = find_dependency (spec);
> -			if (spec_dep->get_entity_kind () == EK_REDIRECT)
> -			  spec_dep = spec_dep->deps[0];
> -			if (spec_dep->is_unreached ())
> -			  {
> -			    reached_unreached = true;
> -			    spec_dep->clear_flag_bit<DB_UNREACHED_BIT> ();
> -			    dump (dumper::DEPEND)
> -			      && dump ("Reaching unreached specialization"
> -				       " %C:%N", TREE_CODE (spec), spec);
> -			  }
> -		      }
> -		  }
> +		{
> +		  /* Mark all the explicit & partial specializations as
> +		     reachable.  We search both specialization lists as some
> +		     constrained partial specializations for class types are
> +		     only found in DECL_TEMPLATE_SPECIALIZATIONS.  */
> +		  auto mark_reached = [this](tree spec)
> +		    {
> +		      if (TYPE_P (spec))
> +			spec = TYPE_NAME (spec);
> +		      int use_tpl;
> +		      node_template_info (spec, use_tpl);
> +		      if (use_tpl & 2)
> +			{
> +			  depset *spec_dep = find_dependency (spec);
> +			  if (spec_dep->get_entity_kind () == EK_REDIRECT)
> +			    spec_dep = spec_dep->deps[0];
> +			  if (spec_dep->is_unreached ())
> +			    {
> +			      reached_unreached = true;
> +			      spec_dep->clear_flag_bit<DB_UNREACHED_BIT> ();
> +			      dump (dumper::DEPEND)
> +				&& dump ("Reaching unreached specialization"
> +					 " %C:%N", TREE_CODE (spec), spec);
> +			    }
> +			}
> +		    };
> +
> +		  for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
> +		       cons; cons = TREE_CHAIN (cons))
> +		    mark_reached (TREE_VALUE (cons));
> +		  for (tree cons = DECL_TEMPLATE_SPECIALIZATIONS (decl);
> +		       cons; cons = TREE_CHAIN (cons))
> +		    mark_reached (TREE_VALUE (cons));
> +		}
>   
>   	      dump.outdent ();
>   	      current = NULL;
> diff --git a/gcc/testsuite/g++.dg/modules/partial-3.C b/gcc/testsuite/g++.dg/modules/partial-3.C
> new file mode 100644
> index 00000000000..0d498dad1bd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/partial-3.C
> @@ -0,0 +1,20 @@
> +// PR c++/114630
> +// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module -fdump-lang-module" }
> +// { dg-module-cmi M }
> +
> +module;
> +
> +template <typename T> struct S {};
> +
> +template <typename T> struct S<T*> {};
> +template <typename T> requires (sizeof(T) == 4) struct S<T*> {};
> +
> +template <typename T> int V = 0;
> +
> +template <typename T> int V<T*> = 1;
> +template <typename T> requires (sizeof(T) == 4) int V<T*> = 2;
> +
> +export module M;
> +
> +// The whole GMF should be discarded here
> +// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }
diff mbox series

Patch

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index fac0301d80e..02b0ab3d687 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13304,14 +13304,22 @@  depset::hash::add_partial_entities (vec<tree, va_gc> *partial_classes)
       depset *dep = make_dependency (inner, depset::EK_DECL);
 
       if (dep->get_entity_kind () == depset::EK_REDIRECT)
-	/* We should have recorded the template as a partial
-	   specialization.  */
-	gcc_checking_assert (dep->deps[0]->get_entity_kind ()
-			     == depset::EK_PARTIAL);
+	{
+	  dep = dep->deps[0];
+	  /* We should have recorded the template as a partial
+	     specialization.  */
+	  gcc_checking_assert (dep->get_entity_kind ()
+			       == depset::EK_PARTIAL);
+	}
       else
 	/* It was an explicit specialization, not a partial one.  */
 	gcc_checking_assert (dep->get_entity_kind ()
 			     == depset::EK_SPECIALIZATION);
+
+      /* Only emit GM entities if reached.  */
+      if (!DECL_LANG_SPECIFIC (inner)
+	  || !DECL_MODULE_PURVIEW_P (inner))
+	dep->set_flag_bit<DB_UNREACHED_BIT> ();
     }
 }
 
@@ -13632,31 +13640,40 @@  depset::hash::find_dependencies (module_state *module)
 	      if (!walker.is_key_order ()
 		  && TREE_CODE (decl) == TEMPLATE_DECL
 		  && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
-		/* Mark all the explicit & partial specializations as
-		   reachable.  */
-		for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
-		     cons; cons = TREE_CHAIN (cons))
-		  {
-		    tree spec = TREE_VALUE (cons);
-		    if (TYPE_P (spec))
-		      spec = TYPE_NAME (spec);
-		    int use_tpl;
-		    node_template_info (spec, use_tpl);
-		    if (use_tpl & 2)
-		      {
-			depset *spec_dep = find_dependency (spec);
-			if (spec_dep->get_entity_kind () == EK_REDIRECT)
-			  spec_dep = spec_dep->deps[0];
-			if (spec_dep->is_unreached ())
-			  {
-			    reached_unreached = true;
-			    spec_dep->clear_flag_bit<DB_UNREACHED_BIT> ();
-			    dump (dumper::DEPEND)
-			      && dump ("Reaching unreached specialization"
-				       " %C:%N", TREE_CODE (spec), spec);
-			  }
-		      }
-		  }
+		{
+		  /* Mark all the explicit & partial specializations as
+		     reachable.  We search both specialization lists as some
+		     constrained partial specializations for class types are
+		     only found in DECL_TEMPLATE_SPECIALIZATIONS.  */
+		  auto mark_reached = [this](tree spec)
+		    {
+		      if (TYPE_P (spec))
+			spec = TYPE_NAME (spec);
+		      int use_tpl;
+		      node_template_info (spec, use_tpl);
+		      if (use_tpl & 2)
+			{
+			  depset *spec_dep = find_dependency (spec);
+			  if (spec_dep->get_entity_kind () == EK_REDIRECT)
+			    spec_dep = spec_dep->deps[0];
+			  if (spec_dep->is_unreached ())
+			    {
+			      reached_unreached = true;
+			      spec_dep->clear_flag_bit<DB_UNREACHED_BIT> ();
+			      dump (dumper::DEPEND)
+				&& dump ("Reaching unreached specialization"
+					 " %C:%N", TREE_CODE (spec), spec);
+			    }
+			}
+		    };
+
+		  for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
+		       cons; cons = TREE_CHAIN (cons))
+		    mark_reached (TREE_VALUE (cons));
+		  for (tree cons = DECL_TEMPLATE_SPECIALIZATIONS (decl);
+		       cons; cons = TREE_CHAIN (cons))
+		    mark_reached (TREE_VALUE (cons));
+		}
 
 	      dump.outdent ();
 	      current = NULL;
diff --git a/gcc/testsuite/g++.dg/modules/partial-3.C b/gcc/testsuite/g++.dg/modules/partial-3.C
new file mode 100644
index 00000000000..0d498dad1bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/partial-3.C
@@ -0,0 +1,20 @@ 
+// PR c++/114630
+// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module -fdump-lang-module" }
+// { dg-module-cmi M }
+
+module;
+
+template <typename T> struct S {};
+
+template <typename T> struct S<T*> {};
+template <typename T> requires (sizeof(T) == 4) struct S<T*> {};
+
+template <typename T> int V = 0;
+
+template <typename T> int V<T*> = 1;
+template <typename T> requires (sizeof(T) == 4) int V<T*> = 2;
+
+export module M;
+
+// The whole GMF should be discarded here
+// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }