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

            Bug ID: 127694
           Summary: [modules] segfault in read_cluster with a partition
                    re-exported by a primary interface
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: me at davud dot io
  Target Milestone: ---

Created attachment 65737
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65737&action=edit
Repro code and module dumps

Reproduced on:

- g++ (GCC) 14.3.1 20260214
- g++ (GCC) 15.3.0
- g++ (GCC) 16.2.1 20260810
- g++ (GCC) 17.0.0 20260918 (experimental), commit a87de1ad7, configured with
  `--disable-bootstrap --enable-checking=yes --enable-languages=c,c++
--disable-multilib`

Target is x86_64-pc-linux-gnu
Flags are `-std=gnu++23 -fmodules-ts -fmodule-only`

# Description

In `baz.cppm`, a module partition `mod1:part` declares:
- a function template `Conversion` whose return type is an alias template
specialization that depends on the function parameter
- a struct `Bar` with a member function template whose parameter type mentions
`Conversion`.

The primary interface `mod1` in file `bar.cppm` re-exports the partition and
declares `using Foo = Bar;`.

With the checking build, compiling `bar.cppm` results in an assertion inside
`trees_out::type_node`.
With a release build, `bar.cppm` compiles, but `foo.cppm` (the file containing
some `mod2`) segfaults while reading the CMI. `foo.cppm` imports `mod1` and
uses `Namespace::Foo`.

In both cases `baz.cppm` will compile fine.

# Reproduction code

`baz.cppm`
```
module;
template <typename> struct enable_if;
template <typename _Cond> using enable_if_t = enable_if<_Cond>;
template <typename T> auto Conversion(T v) -> enable_if_t<decltype(v)>;
export module mod1:part;

export namespace Namespace {
  struct Bar {
    template <typename Args>
    void Func(decltype(Conversion<Args>));
  };
}
```
Note that `baz.cppm` has to be a partition. If it's a separate module that
`bar.cppm` imports and re-exports, no crash happens

`bar.cppm`
```
export module mod1;
export import :part;

export namespace Namespace {
    using Foo = Bar;
}
```

`foo.cppm`
```
export module mod2;
import mod1;

Namespace::Foo make() { return {}; }
```

Variant of `baz.cppm` without a GMF. Here, the crash depends on the function's
name. In my case, the name `Conversion` compiled, but renaming the function to
`q` caused the same crash, in both release and checking.

```
export module mod1:part;

export namespace Namespace {
  template <typename> struct enable_if;
  template <typename _Cond> using enable_if_t = enable_if<_Cond>;
  template <typename T> auto q(T v) -> enable_if_t<decltype(v)>;

  struct Bar {
    template <typename Args>
    void Func(decltype(q<Args>));
  };
}
```

Compiled using:
```
for f in baz bar foo; do
  g++ -std=gnu++23 -fmodules-ts -fmodule-only -x c++ -c $f.cppm
done
```
With the declarations written directly in the GMF there is a `-Wglobal-module`
warning. The result is the same when they come from an `#include`d header.

# Compiler output

GCC 16.2.1 release, compiling `foo.cppm`:

```
foo.cppm:4:12: internal compiler error: Segmentation fault
    4 | Namespace::Foo make() { return {}; }
      |            ^~~
0x19317d8 internal_error(char const*, ...)
0x19deee2 build_function_type(tree_node*, tree_node*, bool)
0x1260254 module_state::read_cluster(unsigned int)
0x1265465 module_state::load_section(unsigned int, binding_slot*)
0x1265552 module_state::lazy_load(unsigned int, binding_slot*)
0x125fd8a module_state::read_cluster(unsigned int)
0x1265465 module_state::load_section(unsigned int, binding_slot*)
0x1265552 module_state::lazy_load(unsigned int, binding_slot*)
0x125fd8a module_state::read_cluster(unsigned int)
0x1265465 module_state::load_section(unsigned int, binding_slot*)
0x12657f4 lazy_load_binding(unsigned int, tree_node*, tree_node*,
binding_slot*)
0x1ba460d lookup_qualified_name(tree_node*, tree_node*, LOOK_want, bool)
0x27a2619 c_parse_file()
0x2778050 c_common_parse_file()
```

On 14.3.1 and 15.3.0 the top frame is `module_state::read_cluster` instead of
`build_function_type`. The rest of the backtrace is the same.

GCC 17 checking build, compiling `bar.cppm`:

```
bar.cppm:1:8: internal compiler error: in type_node, at cp/module.cc:9735
    1 | export module mod1;
      |        ^~~~~~
0x12c138c type_node
        ../../gcc/gcc/cp/module.cc:9735
0x12c4243 tree_node
        ../../gcc/gcc/cp/module.cc:10333
0x12cd15b key_mergeable
        ../../gcc/gcc/cp/module.cc:12087
0x12ba4df decl_value
        ../../gcc/gcc/cp/module.cc:8527
0x12be80a decl_node
        ../../gcc/gcc/cp/module.cc:9258
0x12c473c tree_node
        ../../gcc/gcc/cp/module.cc:10391
0x12c0333 decl_node
        ../../gcc/gcc/cp/module.cc:9538
0x12c473c tree_node
        ../../gcc/gcc/cp/module.cc:10391
0x12be99d decl_node
        ../../gcc/gcc/cp/module.cc:9280
0x12c473c tree_node
        ../../gcc/gcc/cp/module.cc:10391
0x12c1ba8 type_node
        ../../gcc/gcc/cp/module.cc:9835
0x12c4243 tree_node
        ../../gcc/gcc/cp/module.cc:10333
0x12b3766 core_vals
        ../../gcc/gcc/cp/module.cc:6838
0x12b7d3c tree_node_vals
        ../../gcc/gcc/cp/module.cc:7893
0x12c2a48 tree_value
        ../../gcc/gcc/cp/module.cc:9995
0x12c4767 tree_node
        ../../gcc/gcc/cp/module.cc:10396
0x12cbd4a key_mergeable
        ../../gcc/gcc/cp/module.cc:11869
0x12ba4df decl_value
        ../../gcc/gcc/cp/module.cc:8527
```

Reply via email to