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