https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127251
Bug ID: 127251
Summary: contracts: unrelated precondition changes linkage of
std::source_location
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: ivan.lazaric.gcc at gmail dot com
Target Milestone: ---
A simplified version of my actual use case that ran into this:
```
$ for f in {{foo,bar}.hpp,main.cpp}; do echo "// $f"; cat $f; echo; done
// foo.hpp
void fn() pre(true) {}
// bar.hpp
#include <source_location>
struct bar { std::source_location loc; };
// main.cpp
#include "foo.hpp"
#include "bar.hpp"
int main() {}
$ g++ -std=c++26 -fcontracts main.cpp
In file included from main.cpp:2:
bar.hpp:2:8: warning: 'bar' has a field 'std::source_location bar::loc' whose
type has internal linkage [-Wsubobject-linkage]
2 | struct bar { std::source_location loc; };
| ^~~
```
Following transformations remove the warning
(meaning the linkage of `std::source_location` becomes external):
* Removing the `fn` function definition from `foo.hpp`
* Removing the precondition on `fn`
* Flipping the order of includes in `main.cpp`
We can test this behaviour a bit easier via reflection,
as a single source file:
```cpp
// flags: -std=c++26 -O3 -fcontracts -freflection
// minimal fragment of <meta> we care about
namespace std::meta {
using info = decltype(^^int);
consteval bool has_external_linkage(info);
}
void fn() pre(true) {}
#include <source_location>
static_assert(has_external_linkage(^^std::source_location)); // fails
```
Godbolt: https://godbolt.org/z/7dYooaWaa
Trying to minimize further I reach:
```cpp
// flags: -std=c++26 -O3 -fcontracts -freflection
namespace std::meta {
using info = decltype(^^int);
consteval bool has_external_linkage(info);
} // namespace std::meta
void fn() pre(true) {}
namespace std {
struct source_location {};
} // namespace std
static_assert(has_external_linkage(^^std::source_location));
```
Godbolt: https://godbolt.org/z/ssKGx31hP
It seems to be rather specific to `std::source_location` ,
changing the namespace to `std2` or class name to `source_location2`
makes it have external linkage.