]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Don't emit unused GMF partial specializations [PR114630]
authorNathaniel Shead <nathanieloshead@gmail.com>
Thu, 11 Apr 2024 09:15:35 +0000 (19:15 +1000)
committerNathaniel Shead <nathanieloshead@gmail.com>
Thu, 2 May 2024 06:42:56 +0000 (16:42 +1000)
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
gcc/testsuite/g++.dg/modules/partial-3.C [new file with mode: 0644]

index f7725091f60fc5746aa99479354dc1b6873131f4..44dc81eed3e5167400341565771773ce652d9887 100644 (file)
@@ -13308,14 +13308,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> ();
     }
 }
 
@@ -13636,31 +13644,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 (file)
index 0000000..0d498da
--- /dev/null
@@ -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 } }