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

            Bug ID: 127346
           Summary: [16/17 Regression] [modules] "conflicting declaration"
                    when redeclaring an extern "C++" class whose
                    definition is reachable but not visible
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: samuelgardner101 at gmail dot com
  Target Milestone: ---

Created attachment 65570
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65570&action=edit
c++ files and sh runner

1. module `a` defines a class attached to the global module (via `export extern
"C++"`).
2. module `b` imports `a` without re-exporting it.
3. module `c` imports only `b`, so the definition of `A` is reachable in `c`
but not visible. when `c` redeclares `A`, GCC reports a conflict with a's
definition. it then drops c's declaration, so the name is unusable for the rest
of the TU. both declarations attach to the global module, so they declare the
same entity, and the redeclaration should make `A` visible in `c`.

```c++
// a.ixx
export module a;
export extern "C++" struct A { int x = 42; };  // a declaration alone (no
definition) does not trigger it
```

```c++
// b.ixx
export module b;
import a;  // not re-exported: A is reachable from importers of b, but not
visible
export int b_fn();
```

```c++
// c.ixx
export module c;
import b;  // add "import a;" and it compiles
export extern "C++" struct A;  // same result without "export"
export A *c_ptr();
```

```sh
$ for f in a.ixx b.ixx c.ixx; do g++ -std=c++26 -fmodules -x c++ -c $f -o $f.o;
done
c.ixx:3:28: error: conflicting declaration ‘struct A’
    3 | export extern "C++" struct A;  // same result without "export"
      |                            ^
In module a, imported at b.ixx:2,
of module b, imported at c.ixx:2:
a.ixx:2:28: note: previous declaration as ‘struct A’
    2 | export extern "C++" struct A { int x = 42; };  // a declaration alone
(no definition) does not trigger it
      |                            ^
c.ixx:4:8: error: ‘A’ does not name a type
    4 | export A *c_ptr();
      |        ^
```

it compiles if any of these changes is made:

- c imports a directly (the definition becomes visible)
- a only declares A (`export extern "C++" struct A;`), with no definition
- b uses `export import a;`

it still fails if c's redeclaration drops `export` (`extern "C++" struct A;`),
or if the redeclaration is a definition that uses A through a template from b.

regression:
  - GCC 15.1.0 OK
  - GCC 15.2.0 OK
  - GCC 16.1.0 FAIL
  - GCC 17.0.0 FAIL
  - clang++ 23.1.0 accepts it (-std=c++2c, --precompile each unit).

workaround: import the module that defines the class directly. it is already in
the import closure, so obvs this doesn't/can't create an import cycle.
  • [Bug c++/127346] New: [16/1... samuelgardner101 at gmail dot com via Gcc-bugs

Reply via email to