As a side note, I think the linkage model that is used for class-scope static constexpr variables is matching what we want to achieve here, i.e. we could have: struct X {}; struct S { static constexpr X x = 10; };
And then, in the source file. const X S::x; Maybe we could achieve a similar result for inline constexpr variables, by putting some compiler specific attributes on them? On Tue, Jul 15, 2025 at 1:37 PM Jonathan Wakely <jwak...@redhat.com> wrote: > On Tue, 15 Jul 2025 at 12:06, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > > > > > On Tue, Jul 15, 2025 at 12:37 PM Jonathan Wakely <jwak...@redhat.com> > wrote: > >> > >> On Tue, 15 Jul 2025 at 08:10, Tomasz Kaminski <tkami...@redhat.com> > wrote: > >> > > >> > > >> > > >> > On Mon, Jul 14, 2025 at 10:43 PM Jonathan Wakely <jwak...@redhat.com> > wrote: > >> >> > >> >> This makes it possible to use `new(std::nothrow) X` without linking > to > >> >> libsupc++ or libstdc++. > >> >> > >> >> To ensure we still export the symbol from the library we need to > >> >> suppress the inline variable in libsupc++/new_handler.cc which is > done > >> >> by defining a macro. > >> >> > >> >> libstdc++-v3/ChangeLog: > >> >> > >> >> * libsupc++/new (nothrow): Define as inline variable. > >> >> * libsupc++/new_handler.cc (_GLIBCXX_DEFINE_NOTHROW_OBJ): > >> >> Define. > >> >> --- > >> >> > >> >> Tested powerpc64le-linux. > >> >> > >> >> libstdc++-v3/libsupc++/new | 4 ++++ > >> >> libstdc++-v3/libsupc++/new_handler.cc | 2 ++ > >> >> 2 files changed, 6 insertions(+) > >> >> > >> >> diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new > >> >> index fb36dae25a6d..85d28ff40769 100644 > >> >> --- a/libstdc++-v3/libsupc++/new > >> >> +++ b/libstdc++-v3/libsupc++/new > >> >> @@ -125,7 +125,11 @@ namespace std > >> >> #endif > >> >> }; > >> >> > >> >> +#if defined __cpp_inline_variables && ! defined > _GLIBCXX_DEFINE_NOTHROW_OBJ > >> >> + inline constexpr nothrow_t nothrow{}; > >> >> +#else > >> >> extern const nothrow_t nothrow; > >> >> +#endif > >> > > >> > If you move variable definition before include, this would become: > >> > +#ifndef _GLIBCXX_DEFINE_NOTHROW_OBJ > >> > +# ifdef __cpp_inline_variables > >> > + inline constexpr nothrow_t nothrow{}; > >> > + # else > >> > extern const nothrow_t nothrow; > >> > +# endif > >> > +#endif > >> > > >> > GCC and clang also accepts, i.e. version when we always have extern > declaration: > >> > +#if defined __cpp_inline_variables && ! defined > _GLIBCXX_DEFINE_NOTHROW_OBJ > >> > + inline constexpr nothrow_t nothrow{}; > >> > +#endif > >> > extern const nothrow_t nothrow; > >> > > >> > > >> >> > >> >> /** If you write your own error handler to be called by @c new, > it must > >> >> * be of this type. */ > >> >> diff --git a/libstdc++-v3/libsupc++/new_handler.cc > b/libstdc++-v3/libsupc++/new_handler.cc > >> >> index 7cd3e5a69fde..96dfb796c64a 100644 > >> >> --- a/libstdc++-v3/libsupc++/new_handler.cc > >> >> +++ b/libstdc++-v3/libsupc++/new_handler.cc > >> >> @@ -23,6 +23,8 @@ > >> >> // see the files COPYING3 and COPYING.RUNTIME respectively. If > not, see > >> >> // <http://www.gnu.org/licenses/>. > >> >> > >> >> +#define _GLIBCXX_DEFINE_NOTHROW_OBJ 1 > >> > > >> > Could we also move the definition of nothrow here (before including > new), > >> > so entities in header new always see it's definition when it is > constexpr? > >> > I do not think there is any (even bening) ODR violation possibility > here, but > >> > we can avoid the risk that way., > >> > >> We would need to also move the definition of the nothrow_t type there, > >> otherwise you can't declare the variable. > >> > >> And wouldn't it have internal linkage if it's defined as constexpr > >> const in new_handler.cc? > >> It only has external linkage because the extern declaration in <new> > >> was already seen. > >> > >> So in the <new> header we would need: > >> > >> #ifndef _GLIBCXX_DEFINED_NOTHROW_OBJ // defined by new_handler.cc > >> struct nothrow_t > >> { > >> #if __cplusplus >= 201103L > >> explicit nothrow_t() = default; > >> #endif > >> }; > >> > >> #if defined __cpp_inline_variables > >> // Define as an inline variable when possible, so that std::nothrow > can > >> // be used without linking to libsupc++. > >> inline constexpr nothrow_t nothrow{}; > >> #endif > >> extern const nothrow_t nothrow; > >> #endif > >> > >> > >> And then in new_handler.cc: > >> > >> namespace std > >> { > >> struct nothrow_t > >> { > >> explicit nothrow_t() = default; > >> }; > >> > >> #ifdef __cpp_inline_variables > >> // purposely match when header defines it as inline+constexpr > >> constexpr > >> #endif > >> extern const nothrow_t nothrow{}; > >> } > >> > >> // Prevent <new> from defining it again: > >> #define _GLIBCXX_DEFINED_NOTHROW_OBJ 1 > >> > >> #include "new" > >> > >> > >> But then I get multiple definition errors when linking libstdc++, so > >> something is wrong here. > > > > We could define the nothrow in header if > _GLIBCXX_DEFINE_NOTHROW_OBJ_IN_NEW is defined: > > #ifdef _GLIBCXX_DEFINE_NOTHROW_OBJ_IN_NEW > > extern _GLIBCXX17_CONSTEXPR const nothrow_t nothrow = nothrow_t(); > > #elifdef __cpp_inline_variables > > // Define as an inline variable when possible, so that std::nothrow can > > // be used without linking to libsupc++. > > inline constexpr nothrow_t nothrow{}; > > #else > > extern const nothrow_t nothrow; > > #endif > > > > And then in new_handler.cc, do: > > // instruct <new> to provide definition of nothrow. > > #define _GLIBCXX_DEFINE_NOTHROW_OBJ 1 > > #include "new" > > Ah yes, that's much cleaner and avoid repeating the type. I'll see if > that works as expected. > > > >> > >> > >> If all you're trying to do is ensure that 'constexpr' is seen > >> consistently, I don't think it's worth it. It's already not going to > >> be constexpr when combining C++98 and C++17 objects, because it can > >> never be constexpr in C++98. > > > > That's true, so you can ship the original as is. > > > > Regards, > > Tomasz > >