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. 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.