llvm / llvm/llvm-project

[C++ Modules] False "definition with same mangled name as another definition" error for a static inline function reached via two different wrapper paths across two module interface units

Open
#219,657 17 comments 0 reactions 0 assignees View on GitHub
clang:modules
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

### Description

Clang emits a spurious ODR-violation-style error (`definition with same mangled name '...' as another definition`) for a single `static inline` function defined in a header, when that header is textually included (via the global module fragment) into two different module interface units that both end up imported into the same translation unit — but only when the importing module reaches the function through a *different* call path than the imported module does.

There is exactly one definition of the function in the source. Clang appears to fail to merge/deduplicate the two textual copies of it pulled in through the two module BMIs, and instead treats them as conflicting definitions with the same mangled name.

### Environment

```
clang version 23.1.0 (https://github.com/llvm/llvm-project ea7d852a70e8bdfaf601d6626a760f9771b2c4b4)
Target: x86_64-pc-windows-msvc
```

### Minimal reproducer

**common.h**
```cpp
static inline void static_fn() {
}
inline void helper1() {
static_fn();
}
inline void helper2() {
static_fn();
}
```

**ModB.cppm**
```cpp
module;
#include "common.h"
export module ModB;
export inline void use_b() {
helper1();
}
```

**ModA.cppm**
```cpp
module;
#include "common.h"
export module ModA;
import ModB;
export inline void use_a() {
helper1();
helper2();
}
```

**main.cpp**
```cpp
import ModA;
int main() {
use_a();
}
```

### Build commands

```
clang++ -std=c++23 -fmodule-output=ModB.pcm -c ModB.cppm -o ModB.o
clang++ -std=c++23 -fmodule-output=ModA.pcm -fmodule-file=ModB=ModB.pcm -c ModA.cppm -o ModA.o
clang++ -std=c++23 -fmodule-file=ModA=ModA.pcm -fmodule-file=ModB=ModB.pcm -c main.cpp -o main.o
```

The first two invocations succeed with no diagnostics. The third fails with:

```
In module 'ModA' imported from main.cpp:1:
common.h:1:20: error: definition with same mangled name '?static_fn@@YAXXZ' as another definition
1 | static inline void static_fn() {
| ^
common.h:1:20: note: previous definition is here
1 | static inline void static_fn() {
| ^
1 error generated.
```

### Expected behavior

The build should succeed. `static_fn` has a single, identical definition; it is only reached multiple times because `ModA` and `ModB` each `#include "common.h"` in their global module fragments, and `ModA` also `import`s `ModB`. Sharing an internal header helper across module interface units this way should not trigger an ODR/mangled-name conflict.

Contributor guide

Open the contributing guide

Research direction

Reproduce the diagnostic with common.h, ModA.cppm, ModB.cppm, and main.cpp using the three build commands, starting with the failing main.cpp compilation. Trace how the two module BMIs handle the duplicated static inline definition reached through different wrapper paths; done means the final command succeeds without the mangled-name conflict.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.