[PATCH] libstdc++: replace assert with __glibcxx_assert (PR libstdc++/125228)
Jonathan Wakely
jwakely@redhat.com
Thu May 14 09:32:28 GMT 2026
On Thu, 14 May 2026 at 08:15, Dragon Archer <dragon-archer@outlook.com> wrote:
>
> On 2026/05/14 04:25, Jonathan Wakely wrote:
> > On Wed, 13 May 2026 at 15:29, Patrick Palka <ppalka@redhat.com> 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 <dragon-archer@outlook.com>
> >>> 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.
> >
>
> Sounds reasonable. I'v updated the patch below and adopt this change.
Great, thanks! I'll push this to git for you.
>
> ---
> From 7bcd2dcb248e22908cafa01bb412c7f3bad9bba2 Mon Sep 17 00:00:00 2001
> From: dragon-archer <dragon-archer@outlook.com>
> Date: Fri, 8 May 2026 19:14:49 +0800
> Subject: [PATCH] libstdc++: use __glibcxx_assert instead of assert
> [PR125228]
>
> 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 define
> `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 define assert
> as __glibcxx_assert to avoid modifying the ryu headers.
> ---
> libstdc++-v3/src/c++11/debug.cc | 33 ++++++++++-----------
> libstdc++-v3/src/c++17/floating_to_chars.cc | 3 +-
> 2 files changed, 18 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..c5dce2177e3 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,7 @@ namespace
>
> namespace ryu
> {
> +#define assert __glibcxx_assert
> #include "ryu/common.h"
> #include "ryu/digit_table.h"
> #include "ryu/d2s_intrinsics.h"
> @@ -123,6 +123,7 @@ namespace
> # include "ryu/ryu_generic_128.h"
> # include "ryu/generic_128.c"
> } // namespace generic128
> +#undef assert
>
> using generic128::floating_decimal_128;
> using generic128::generic_binary_to_decimal;
> --
> 2.54.0.windows.1
> >
> >>
> >> 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
> >>>
> >>>
> >>>
> >>
> >
>
More information about the Libstdc++
mailing list