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

Reply via email to