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.

Reply via email to