[PATCH] libstdc++: Define std::nothrow as inline variable
Jonathan Wakely
jwakely@redhat.com
Tue Jul 15 10:36:47 GMT 2025
On Tue, 15 Jul 2025 at 08:10, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
>
> On Mon, Jul 14, 2025 at 10:43 PM Jonathan Wakely <jwakely@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.
More information about the Libstdc++
mailing list