Loads of a string pointer from an inline const variable are emitted as an independent local constant in each TU
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Compiling this C++ code with clang version 22.1.1 as a shared library:
```c++
// test.cpp
inline const char *const str = "abc";
const char *str2 = str;
```
linking it into this program:
```c++
// main.cpp
#include
inline const char *const str = "abc";
extern const char *str2;
int main() { std::printf("str = %p, str2 = %p\n", str, str2); }
```
and running the program produces output like this ([Compiler Explorer](https://godbolt.org/z/9nbqzGcKf)):
```
str = 0x561691a6e019, str2 = 0x7f24b5452000
```
The final program contains two copies of the string `"abc"`, with `str` and `str2` each pointing to a different copy. According to my (limited) understanding of the C++ standard, this is not permitted - although it is unspecified whether successive evaluations of a string literal yield the same or a different object, here the address of such an object is assigned to a single (inline) global variable, and it should be impossible for a single variable to have multiple values at the same time. There doesn't seem to be any ODR violation, because both definitions of `str` consist of the same sequence of tokens and there are no names that could be resolved differently.
The reason for the different addresses is that when the value of `str` is used, clang emits code like this:
```llvm
@.str = private unnamed_addr constant [4 x i8] c"abc\00", align 1
@str2 = global ptr @.str, align 8
```
Notice that the string literal is emitted as `private unnamed_addr constant`, not `linkonce_odr constant`, even though it is part of the inline constant.
The broken assumption here is that each definition of an inline constant must have the same value. This would be normally guaranteed by the One Definition Rule, but the wording in the standard (requiring identical sequence of tokens and that name lookup finds the same entities) is (by my interpretation) insufficient in the presence of string literals, which may result in a different value when evaluated in different translation units.
GCC is affected too and produces pretty much equivalent assembly.
You may also compare this situation to the case of reference temporaries. In this code:
```c++
inline const int &i = 42;
const int &j = i;
```
a separate `linkonce_odr` symbol is generated for the temporary ([Compiler Explorer](https://godbolt.org/z/s5ch3xTh8)), which guarantees it will have the same value in every translation unit, unlike string literals.
Contributor guide
Assessment
This issue has not been assessed yet.