[PATCH] libstdc++: replace assert with __glibcxx_assert (PR libstdc++/125228)

Dragon Archer dragon-archer@outlook.com
Thu May 14 07:14:49 GMT 2026


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.

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