https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126209
Bug ID: 126209
Summary: [16/17 regression] [modules] anonymous-namespace
variable in a module partition → ICE in
append_imported_binding_slot (checking) / segfault in
read_namespaces after minutes-long spin (release)
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: stefan_heinzmann at gmx dot de
Target Milestone: ---
**Known to work:** 15.2 / 15.3 (both release and checking builds)
**Host/target:** x86_64 (Fedora 44, Compiler Explorer); also arm-none-eabi
cross
## Short testcase (4 files, 7 lines — ICEs on checking builds)
// k_event.cppm
export module kernel:event;
namespace { int anchor = 0; }
// k_memories.cppm
export module kernel:memories;
import :event;
// kernel.cppm
export module kernel;
export import :event;
export import :memories;
// main.cpp
import kernel;
int main() { return 0; }
Compile in that order with `-std=c++20 -fmodules-ts`. On checking-enabled
builds of 16.1 and trunk (17.0 20260705), compiling `main.cpp` fails:
main.cpp:1:15: internal compiler error: in append_imported_binding_slot,
at cp/name-lookup.cc:353
Live demo (Compiler Explorer CMake project, gcc 16.1-assertions + trunk):
https://godbolt.org/z/zhe8GfnW5
gcc 15.2/15.3 assertion builds compile the same tree cleanly (regression).
All three ingredients are needed: the anonymous-namespace variable in the
partition, a sibling partition importing it, and a consumer importing the
primary. Remove any one → compiles cleanly.
## Release-build manifestation (large graph): runaway spin + segfault
On release-checking builds (Fedora 16.0.1; also the arm-none-eabi cross
compiler) the same inconsistency instead surfaces when reading a larger
import graph: cc1plus spins at 100 % CPU for 2–4 minutes, then segfaults.
`repro.py` (attached) generates 67 tiny module files mirroring the real code
base this was reduced from (module `kernel`: 36 partitions, three of them
with the minimal contents above; module `vfs`: 21 empty partitions importing
kernel; a 6-module stack on top) and compiles them in dependency order:
python3 repro.py workdir # exit 0 = ICE reproduced (~5 min)
GXX=g++-15 python3 repro.py w2 # exit 1 = clean on 15.2.1
Symbolized backtrace (16.0.1-0.fc44, gdb on cc1plus):
#0 get_originating_module_decl(tree_node*)
#1 get_originating_module(tree_node*, bool)
#2 init_global_partition(binding_cluster*, tree_node*)
#3 get_fixed_binding_slot(tree_node**, tree_node*, unsigned int, int)
#4 append_imported_binding_slot(tree_node**, tree_node*, unsigned int)
#5 add_imported_namespace(tree_node*, tree_node*, unsigned long, unsigned
int, bool, bool)
#6 module_state::read_namespaces(unsigned int)
#7 module_state::read_language(bool)
#8 direct_import(module_state*, cpp_reader*)
#9 cp_parser_module_declaration(cp_parser*, module_parse, bool)
#10 c_parse_file()
Frame #4 is the function whose assertion fires in checking builds, so both
manifestations appear to be the same underlying inconsistency (presumably a
binding slot for the anonymous-namespace entity's namespace being appended
out of order / duplicated).
Bisection notes on the large-graph segfault (why the generated repro is 67
files): the release-build crash is extremely sensitive to graph size —
dropping any one of the 21 vfs partitions, or more than 4 of the 33 empty
kernel filler partitions, makes the crash disappear (memory-layout/ordering
sensitivity). It reproduces with `-std=c++20` and `-std=gnu++23`, with and
without `-O0 -fno-exceptions -w`, and both via a plain `gcm.cache` build and
via CMake's module-mapper path. The minutes-long spin before the crash is
itself anomalous — 15.2 compiles the same reader in well under a second.
## Suspect
r16-3613 (PR121702 rework of read/write_namespaces and using-directive
streaming, Sept 2025) touches exactly this code path; not bisected.
## Attachments
- repro.py — self-contained generator + build driver for the 67-file variant
(the 4-file testcase + CMakeLists.txt is found at the godbolt link)