On Wed, 13 May 2026 at 15:29, Patrick Palka <[email protected]> wrote:
>
> On Fri, 8 May 2026, Dragon Archer wrote:
>
> > PR libstdc++/125228
> >
> > This patch replaces the uses of `assert` in ryu and debug.cc with
> > `__glibcxx_assert`, and removed their direct dependency on `<cassert>`.
> > To avoid modifying the third-party ryu headers, this patch use
> > `#pragma push_macro` / `#pragma pop_macro` to locally
> > redefine `assert` to `__glibcxx_assert` when including the ryu headers.
> >
> > libstdc++-v3/ChangeLog:
> >
> > PR libstdc++/125228
> > * src/c++11/debug.cc: Replace assert with __glibcxx_assert,
> > and remove the include of <cassert>.
> > * src/c++17/floating_to_chars.cc: Likewise, but redefine
> > assert as __glibcxx_assert using pragma push/pop_macro.
> >
> > --
> >
> > From 76f866652f9a7e2fc4faf012f6b356e9a85ecb8d Mon Sep 17 00:00:00 2001
> > From: dragon-archer <[email protected]>
> > Date: Fri, 8 May 2026 19:14:49 +0800
> > Subject: [PATCH] libstdc++: Use __glibcxx_assert instead of assert
> >
> > Unlike `__glibcxx_assert` which is guarded
> > by `_GLIBCXX_ASSERTIONS` and enabled only in Debug
> > build of libstdc++, `assert` is either always enabled, or
> > always disabled if manually defining `NDEBUG` before
> > `#include <cassert>` or `#include <assert.h>`. This not
> > only makes `assert` inflexible, but also introduces extra
> > runtime overhead and/or increased binary size in Release
> > builds.
> >
> > Uses of `assert` without `NDEBUG` introduces `__FILE__`
> > into the final library, and can be easily found using
> > `string`
>
> Seems reasonable to me (though pragma push/pop_macro don't seem strictly
> necessary as Jonathan pointed out).
I'm a little concerned that the use of the push/pop_macro pragmas
gives the impression that we do expect 'assert' to be used elsewhere
in that file, which isn't true.
I think it would be sufficient and express the intent better to do:
#define assert __glibcxx_assert
... include the ryu files ...
#undef assert
If for some reason assert has already been defined at that point,
we'll get "warning: 'assert' redefined" to tell us something
unexpected is happening, and we can investigate.
>
> Though in theory I guess there's a risk of a performance regression by
> removing an assert in Ryu, if the compiler relies on an assert condition
> to be true in order to safely apply an important optimization.
>
> Just wondering, is there a legit problem/concern with __FILE__ appearing
> in the final library or is it a matter of QoI (which I agree with)?
>
> >
> > This is a long standing issue, dating from at least GCC
> > 8.5.0 to latest GCC 16.1.0
> > ---
> > libstdc++-v3/src/c++11/debug.cc | 33 ++++++++++-----------
> > libstdc++-v3/src/c++17/floating_to_chars.cc | 5 +++-
> > 2 files changed, 20 insertions(+), 18 deletions(-)
> >
> > diff --git a/libstdc++-v3/src/c++11/debug.cc
> > b/libstdc++-v3/src/c++11/debug.cc
> > index 7049d5f1238..9a36bdfabb9 100644
> > --- a/libstdc++-v3/src/c++11/debug.cc
> > +++ b/libstdc++-v3/src/c++11/debug.cc
> > @@ -33,7 +33,6 @@
> > #include <debug/safe_local_iterator.h>
> > #include <debug/vector>
> >
> > -#include <cassert>
> > #include <cstdio> // for std::fprintf, stderr
> > #include <cstdlib> // for std::abort
> > #include <cctype> // for std::isspace.
> > @@ -888,7 +887,7 @@ namespace
> > void
> > print_named_name(PrintContext& ctx, const _Parameter::_Named& named)
> > {
> > - assert(named._M_name);
> > + __glibcxx_assert(named._M_name);
> > pretty_print(ctx, named._M_name, print_word);
> > }
> >
> > @@ -985,7 +984,7 @@ namespace
> > print_iterator_state(ctx, iterator);
> > else if (__builtin_strcmp(fname, "sequence") == 0)
> > {
> > - assert(iterator._M_sequence);
> > + __glibcxx_assert(iterator._M_sequence);
> > print_address(ctx, iterator._M_sequence);
> > }
> > else if (__builtin_strcmp(fname, "seq_type") == 0)
> > @@ -999,43 +998,43 @@ namespace
> > void
> > print_field(PrintContext& ctx, const _Parameter& param, const char*
> > fname)
> > {
> > - assert(param._M_kind != _Parameter::__unused_param);
> > + __glibcxx_assert(param._M_kind != _Parameter::__unused_param);
> >
> > const auto& variant = param._M_variant;
> > switch (param._M_kind)
> > {
> > case _Parameter::__iterator:
> > if (!print_iterator_field(ctx, fname, variant._M_iterator))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > case _Parameter::__sequence:
> > if (!print_instance_field(ctx, fname, variant._M_sequence))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > case _Parameter::__integer:
> > if (!print_named_field(ctx, fname, variant._M_integer))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > case _Parameter::__string:
> > if (!print_named_field(ctx, fname, variant._M_string))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > case _Parameter::__instance:
> > if (!print_instance_field(ctx, fname, variant._M_instance))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > case _Parameter::__iterator_value_type:
> > if (!print_type_field(ctx, fname, variant._M_iterator_value_type))
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> >
> > default:
> > - assert(false);
> > + __glibcxx_assert(false);
> > break;
> > }
> > }
> > @@ -1198,9 +1197,9 @@ namespace
> > }
> >
> > // Get the parameter number
> > - assert(*str >= '1' && *str <= '9');
> > + __glibcxx_assert(*str >= '1' && *str <= '9');
> > size_t param_index = *str - '0' - 1;
> > - assert(param_index < num_parameters);
> > + __glibcxx_assert(param_index < num_parameters);
> > const auto& param = parameters[param_index];
> >
> > // '.' separates the parameter number from the field
> > @@ -1208,7 +1207,7 @@ namespace
> > ++str;
> > if (*str != '.')
> > {
> > - assert(*str == ';');
> > + __glibcxx_assert(*str == ';');
> > ++str;
> > if (param._M_kind == _Parameter::__integer)
> > print_integer(ctx, param._M_variant._M_integer._M_value);
> > @@ -1226,8 +1225,8 @@ namespace
> > ++str;
> > while (*str != ';')
> > {
> > - assert(*str);
> > - assert(field_idx < max_field_len - 1);
> > + __glibcxx_assert(*str);
> > + __glibcxx_assert(field_idx < max_field_len - 1);
> > field[field_idx++] = *str++;
> > }
> > ++str;
> > @@ -1382,7 +1381,7 @@ namespace __gnu_debug
> > print_literal(ctx, "Error: ");
> >
> > // Print the error message
> > - assert(_M_text);
> > + __glibcxx_assert(_M_text);
> > print_string(ctx, _M_text, -1, _M_parameters, _M_num_parameters);
> > print_literal(ctx, ".\n");
> >
> > diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc
> > b/libstdc++-v3/src/c++17/floating_to_chars.cc
> > index 9bddffd70ff..264e520e187 100644
> > --- a/libstdc++-v3/src/c++17/floating_to_chars.cc
> > +++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
> > @@ -26,7 +26,6 @@
> >
> > #include <bit>
> > #include <cfenv>
> > -#include <cassert>
> > #include <cmath>
> > #include <cstdio>
> > #include <cstring>
> > @@ -106,6 +105,9 @@ namespace
> >
> > namespace ryu
> > {
> > +#pragma push_macro("assert")
> > +#undef assert
> > +#define assert __glibcxx_assert
> > #include "ryu/common.h"
> > #include "ryu/digit_table.h"
> > #include "ryu/d2s_intrinsics.h"
> > @@ -123,6 +125,7 @@ namespace
> > # include "ryu/ryu_generic_128.h"
> > # include "ryu/generic_128.c"
> > } // namespace generic128
> > +#pragma pop_macro("assert")
> >
> > using generic128::floating_decimal_128;
> > using generic128::generic_binary_to_decimal;
> > --
> > 2.54.0.windows.1
> >
> >
> >
>