https://gcc.gnu.org/g:02917ac4528e32d1b2d0da5f45ef5937c56942cd

commit r15-101-g02917ac4528e32d1b2d0da5f45ef5937c56942cd
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Thu Apr 11 19:15:35 2024 +1000

    c++: Don't emit unused GMF partial specializations [PR114630]
    
    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 <nathanielosh...@gmail.com>

Diff:
---
 gcc/cp/module.cc                         | 75 ++++++++++++++++++++------------
 gcc/testsuite/g++.dg/modules/partial-3.C | 20 +++++++++
 2 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f7725091f60..44dc81eed3e 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -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
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 } }

Reply via email to