https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99426

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ppalka at gcc dot gnu.org
   Last reconfirmed|2021-03-30 00:00:00         |2024-2-21

--- Comment #6 from Patrick Palka <ppalka at gcc dot gnu.org> ---
I've observed a similar error on trunk when compiling our xtreme-header
testcase without -fno-module-lazy:

$ g++ -fmodules-ts -std=c++20
gcc/testsuite/g++.dg/modules/xtreme-header_{a.H,b.C}
In module imported at gcc/testsuite/g++.dg/modules/xtreme-header_b.C:4:1:
./gcc/testsuite/g++.dg/modules/xtreme-header_a.H: At global scope:
./gcc/testsuite/g++.dg/modules/xtreme-header_a.H: error: failed to read
compiled module cluster 5541: Bad file data
./gcc/testsuite/g++.dg/modules/xtreme-header_a.H: note: compiled module file is
‘gcm.cache/,/gcc/testsuite/g++.dg/modules/xtreme-header_a.H.gcm’
In file included from
/scratchpad/gcc-build-prefix/include/c++/14.0.1/string:54,
                 from
/scratchpad/gcc-build-prefix/include/c++/14.0.1/bitset:52,
                 from gcc/testsuite/g++.dg/modules/xtreme-header.h:9:
/scratchpad/gcc-build-prefix/include/c++/14.0.1/bits/basic_string.h:4249:33:
fatal error: failed to load pendings for ‘std::__cxx11::basic_string’

Although this manifests as a serialization error, it's really a GC issue: a
streamed-in local class from entity_ary (which is not a GC root) gets
prematurely GC'd (since it's only reachable from entity_ary), and later when
resolving a reference to this GC'd local class the tt_entity case of
trees_in::tree_node fails.

In order to achieve a small reproducer, it seems setting
--param=ggc-min-heapsize/expand=0 is not enough, we need to add more collection
points:

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2803824d11e..44c205b2529 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -27367,6 +27367,7 @@ instantiate_pending_templates (int retries)
        {
          tree instantiation = reopen_tinst_level ((*t)->tinst);
          bool complete = false;
+         ggc_collect (GGC_COLLECT_FORCE);

          if (TYPE_P (instantiation))
            {

With this patch to force GC after every instantiation, the following small
testcase can reproduce the issue:

$ cat xtreme-header.ii
struct string {
  template <typename T> void g(T) {
    struct _Local { };
  }
};

template <typename _Tp> void f(_Tp) { }

inline void foo() {
  string s;
  f(s);
  s.g(0);
}

$ cat xtreme-header_a.H
#include "xtreme-header.ii"

$ cat xtreme-header_b.C
#include "xtreme-header.ii"
import "xtreme-header_a.H";

$ g++ -fmodules-ts xtreme_header_{a.H,b.C}
./xtreme-header_a.H: error: failed to read compiled module cluster 4: Bad file
data
./xtreme-header_a.H: note: compiled module file is
‘gcm.cache/,/xtreme-header_a.H.gcm’
In file included from xtreme-header_b.C:1:
xtreme-header.ii:12:6: fatal error: failed to load pendings for ‘::string’

Another way to observe this GC issue by forcing a GC right before we clear
entity_ary and checking if any trees within entity_ary have been freed:

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 106af7bdb3e..a6edc9b033a 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20460,6 +20460,12 @@ fini_modules (cpp_reader *reader, void *cookie, bool
has_inits)
   /* No need to lookup modules anymore.  */
   modules_hash = NULL;

+  ggc_collect (GGC_COLLECT_FORCE);
+  if (entity_ary)
+    for (binding_slot& t : *entity_ary)
+      if (!t.is_lazy () && (tree)t && TREE_CODE ((tree)t) == 0xa5a5)
+       printf ("XXX\n");
+
   /* Or entity array.  We still need the entity map to find import numbers. 
*/
   vec_free (entity_ary);
   entity_ary = NULL;

With that the following minimal testcase demonstrates the GC issue:

$ cat xtreme-header.ii
template <typename> void _M_construct() { struct A { }; }

$ g++ -fmodules-ts xtreme-header_{a.H,b.C}
XXX

Reply via email to