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"

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

Reply via email to