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