[1/2] libstdc++: Add always_inline to ranges iterator ops and access functions

Message ID 20250911121739.1538375-1-jwakely@redhat.com
State New
Headers
Series [1/2] libstdc++: Add always_inline to ranges iterator ops and access functions |

Commit Message

Jonathan Wakely Sept. 11, 2025, 12:16 p.m. UTC
  Most of the basis operations for ranges such as ranges::begin and
ranges::next are trivial one-line function bodies, so can be made
always_inline to reduce the abstraction penalty for -O0 code.

Now that we no longer need to support the -fconcepts-ts grammar, we can
also move some [[nodiscard]] attributes to the more natural position
before the function declaration, instead of between the declarator-id
and the function parameters, e.g. we can use:

  template<typename T> requires C<T> [[nodiscard]] auto operator()(T&&)

instead of:

  template<typename T> requires C<T> auto operator() [[nodiscard]] (T&&)

The latter form was necessary because -fconcepts-ts used a different
grammar for the requires-clause, parsing 'C<T>[[x]]' as a subscripting
operator with an ill-formed argument '[x]'. In the C++20 grammar you
would need to use parentheses to use a subscript in a constraint, so
without parentheses it's parsed as an attribute.

libstdc++-v3/ChangeLog:

	* include/bits/ranges_base.h (__detail::__to_unsigned_like)
	(__access::__possible_const_range, __access::__as_const)
	(__distance_fn::operator(), __next_fn::operator())
	(__prev_fn::operator()): Add always_inline attribute.
	(_Begin::operator(), _End::operator(), _RBegin::operator())
	(_REnd::operator(), _Size::operator(), _SSize::operator())
	(_Empty::operator(), _Data::operator(), _SSize::operator()):
	Likewise. Move nodiscard attribute to start of declaration.
---

This change was inspired when I was adding more uses of ranges::next and
ranges::prev to fix the iterator arithmetic not using difference_type.

Tested powerpc64-linux.

 libstdc++-v3/include/bits/ranges_base.h | 47 ++++++++++++++++---------
 1 file changed, 30 insertions(+), 17 deletions(-)
  

Comments

Tomasz Kaminski Sept. 11, 2025, 12:32 p.m. UTC | #1
On Thu, Sep 11, 2025 at 2:18 PM Jonathan Wakely <jwakely@redhat.com> wrote:

> Most of the basis operations for ranges such as ranges::begin and
> ranges::next are trivial one-line function bodies, so can be made
> always_inline to reduce the abstraction penalty for -O0 code.
>
> Now that we no longer need to support the -fconcepts-ts grammar, we can
> also move some [[nodiscard]] attributes to the more natural position
> before the function declaration, instead of between the declarator-id
> and the function parameters, e.g. we can use:
>
>   template<typename T> requires C<T> [[nodiscard]] auto operator()(T&&)
>
> instead of:
>
>   template<typename T> requires C<T> auto operator() [[nodiscard]] (T&&)
>
> The latter form was necessary because -fconcepts-ts used a different
> grammar for the requires-clause, parsing 'C<T>[[x]]' as a subscripting
> operator with an ill-formed argument '[x]'. In the C++20 grammar you
> would need to use parentheses to use a subscript in a constraint, so
> without parentheses it's parsed as an attribute.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/ranges_base.h (__detail::__to_unsigned_like)
>         (__access::__possible_const_range, __access::__as_const)
>         (__distance_fn::operator(), __next_fn::operator())
>         (__prev_fn::operator()): Add always_inline attribute.
>         (_Begin::operator(), _End::operator(), _RBegin::operator())
>         (_REnd::operator(), _Size::operator(), _SSize::operator())
>         (_Empty::operator(), _Data::operator(), _SSize::operator()):
>         Likewise. Move nodiscard attribute to start of declaration.
> ---
>
> This change was inspired when I was adding more uses of ranges::next and
> ranges::prev to fix the iterator arithmetic not using difference_type.
>
LGTM.

>
> Tested powerpc64-linux.
>
>  libstdc++-v3/include/bits/ranges_base.h | 47 ++++++++++++++++---------
>  1 file changed, 30 insertions(+), 17 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/ranges_base.h
> b/libstdc++-v3/include/bits/ranges_base.h
> index 02e13a2027d1..c1a9f6a90009 100644
> --- a/libstdc++-v3/include/bits/ranges_base.h
> +++ b/libstdc++-v3/include/bits/ranges_base.h
> @@ -61,29 +61,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  namespace ranges
>  {
>    template<typename>
>      inline constexpr bool disable_sized_range = false;
>
>    template<typename _Tp>
>      inline constexpr bool enable_borrowed_range = false;
>
>    namespace __detail
>    {
> +    [[__gnu__::__always_inline__]]
>      constexpr __max_size_type
>      __to_unsigned_like(__max_size_type __t) noexcept
>      { return __t; }
>
> +    [[__gnu__::__always_inline__]]
>      constexpr __max_size_type
>      __to_unsigned_like(__max_diff_type __t) noexcept
>      { return __max_size_type(__t); }
>
>      template<integral _Tp>
> +      [[__gnu__::__always_inline__]]
>        constexpr auto
>        __to_unsigned_like(_Tp __t) noexcept
>        { return static_cast<make_unsigned_t<_Tp>>(__t); }
>
>      template<typename _Tp>
>        using __make_unsigned_like_t
>         = decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
>
>      // Part of the constraints of ranges::borrowed_range
>      template<typename _Tp>
> @@ -111,22 +114,23 @@ namespace ranges
>           else if constexpr (__member_begin<_Tp>)
>             return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
>           else
>             return
> noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
>         }
>
>      public:
>        template<__maybe_borrowed_range _Tp>
>         requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
>           || __adl_begin<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> +       operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (is_array_v<remove_reference_t<_Tp>>)
>             {
>               static_assert(is_lvalue_reference_v<_Tp>);
>               return __t + 0;
>             }
>           else if constexpr (__member_begin<_Tp>)
>             return __t.begin();
>           else
>             return begin(__t);
> @@ -161,22 +165,23 @@ namespace ranges
>           else if constexpr (__member_end<_Tp>)
>             return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
>           else
>             return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
>         }
>
>      public:
>        template<__maybe_borrowed_range _Tp>
>         requires is_bounded_array_v<remove_reference_t<_Tp>>
>           || __member_end<_Tp> || __adl_end<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> +       operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
>             {
>               static_assert(is_lvalue_reference_v<_Tp>);
>               return __t + extent_v<remove_reference_t<_Tp>>;
>             }
>           else if constexpr (__member_end<_Tp>)
>             return __t.end();
>           else
>             return end(__t);
> @@ -225,22 +230,23 @@ namespace ranges
>                   return is_nothrow_copy_constructible_v<_It>;
>                 }
>               else
>                 return false;
>             }
>         }
>
>      public:
>        template<__maybe_borrowed_range _Tp>
>         requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> ||
> __reversable<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> +       operator()(_Tp&& __t) const
>         noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (__member_rbegin<_Tp>)
>             return __t.rbegin();
>           else if constexpr (__adl_rbegin<_Tp>)
>             return rbegin(__t);
>           else
>             return std::make_reverse_iterator(_End{}(__t));
>         }
>      };
> @@ -282,22 +288,23 @@ namespace ranges
>                   return is_nothrow_copy_constructible_v<_It>;
>                 }
>               else
>                 return false;
>             }
>         }
>
>      public:
>        template<__maybe_borrowed_range _Tp>
>         requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> +       operator()(_Tp&& __t) const
>         noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (__member_rend<_Tp>)
>             return __t.rend();
>           else if constexpr (__adl_rend<_Tp>)
>             return rend(__t);
>           else
>             return std::make_reverse_iterator(_Begin{}(__t));
>         }
>      };
> @@ -346,42 +353,44 @@ namespace ranges
>             return
> noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
>           else if constexpr (__sentinel_size<_Tp>)
>             return noexcept(_End{}(std::declval<_Tp&>())
>                             - _Begin{}(std::declval<_Tp&>()));
>         }
>
>      public:
>        template<typename _Tp>
>         requires is_bounded_array_v<remove_reference_t<_Tp>>
>           || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> +       operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
>             return extent_v<remove_reference_t<_Tp>>;
>           else if constexpr (__member_size<_Tp>)
>             return __t.size();
>           else if constexpr (__adl_size<_Tp>)
>             return size(__t);
>           else if constexpr (__sentinel_size<_Tp>)
>             return __detail::__to_unsigned_like(_End{}(__t) -
> _Begin{}(__t));
>         }
>      };
>
>      struct _SSize
>      {
>        // _GLIBCXX_RESOLVE_LIB_DEFECTS
>        // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
>        template<typename _Tp>
>         requires requires (_Tp& __t) { _Size{}(__t); }
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(noexcept(_Size{}(__t)))
> +       operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
>         {
>           auto __size = _Size{}(__t);
>           using __size_type = decltype(__size);
>           // Return the wider of ptrdiff_t and
> make-signed-like-t<__size_type>.
>           if constexpr (integral<__size_type>)
>             {
>               using __gnu_cxx::__int_traits;
>               if constexpr (__int_traits<__size_type>::__digits
>                             < __int_traits<ptrdiff_t>::__digits)
>                 return static_cast<ptrdiff_t>(__size);
> @@ -422,22 +431,23 @@ namespace ranges
>             return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
>           else
>             return noexcept(bool(_Begin{}(std::declval<_Tp&>())
>                 == _End{}(std::declval<_Tp&>())));
>         }
>
>      public:
>        template<typename _Tp>
>         requires __member_empty<_Tp> || __size0_empty<_Tp>
>           || __eq_iter_empty<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr bool
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp&>())
> +       operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
>         {
>           if constexpr (__member_empty<_Tp>)
>             return bool(__t.empty());
>           else if constexpr (__size0_empty<_Tp>)
>             return _Size{}(__t) == 0;
>           else
>             return bool(_Begin{}(__t) == _End{}(__t));
>         }
>      };
>
> @@ -463,22 +473,23 @@ namespace ranges
>         {
>           if constexpr (__member_data<_Tp>)
>             return
> noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
>           else
>             return noexcept(_Begin{}(std::declval<_Tp&>()));
>         }
>
>      public:
>        template<__maybe_borrowed_range _Tp>
>         requires __member_data<_Tp> || __begin_data<_Tp>
> +       [[nodiscard, __gnu__::__always_inline__]]
>         constexpr auto
> -       operator()[[nodiscard]](_Tp&& __t) const
> noexcept(_S_noexcept<_Tp>())
> +       operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
>         {
>           if constexpr (__member_data<_Tp>)
>             return __t.data();
>           else
>             return std::to_address(_Begin{}(__t));
>         }
>      };
>
>    } // namespace __access
>
> @@ -625,33 +636,35 @@ namespace ranges
>  #if __glibcxx_ranges_as_const // >= C++23
>    template<typename _Tp>
>      concept constant_range
>        = input_range<_Tp> &&
> std::__detail::__constant_iterator<iterator_t<_Tp>>;
>  #endif
>
>    namespace __access
>    {
>  #if __glibcxx_ranges_as_const // >= C++23
>      template<input_range _Range>
> +      [[__gnu__::__always_inline__]]
>        constexpr auto&
>        __possibly_const_range(_Range& __r) noexcept
>        {
>         // _GLIBCXX_RESOLVE_LIB_DEFECTS
>         // 4027. possibly-const-range should prefer returning const R&
>         if constexpr (input_range<const _Range>)
>           return const_cast<const _Range&>(__r);
>         else
>           return __r;
>        }
>  #else
>      // If _To is an lvalue-reference, return const _Tp&, otherwise const
> _Tp&&.
>      template<typename _To, typename _Tp>
> +      [[__gnu__::__always_inline__]]
>        constexpr decltype(auto)
>        __as_const(_Tp& __t) noexcept
>        {
>         static_assert(std::is_same_v<_To&, _Tp&>);
>
>         if constexpr (is_lvalue_reference_v<_To>)
>           return const_cast<const _Tp&>(__t);
>         else
>           return static_cast<const _Tp&&>(__t);
>        }
> @@ -960,106 +973,106 @@ namespace ranges
>         iter_difference_t<_It> __n = 0;
>         while (__first != __last)
>           {
>             ++__first;
>             ++__n;
>           }
>         return __n;
>        }
>
>      template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr iter_difference_t<decay_t<_It>>
>        operator()(_It&& __first, _Sent __last) const
>        { return __last - static_cast<const decay_t<_It>&>(__first); }
>
>      template<range _Range>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr range_difference_t<_Range>
>        operator()(_Range&& __r) const
>        {
>         if constexpr (sized_range<_Range>)
>           return
> static_cast<range_difference_t<_Range>>(ranges::size(__r));
>         else
>           return (*this)(ranges::begin(__r), ranges::end(__r));
>        }
>
>      void operator&() const = delete;
>    };
>
>    inline constexpr __distance_fn distance{};
>
>    struct __next_fn final
>    {
>      template<input_or_output_iterator _It>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x) const
>        {
>         ++__x;
>         return __x;
>        }
>
>      template<input_or_output_iterator _It>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x, iter_difference_t<_It> __n) const
>        {
>         ranges::advance(__x, __n);
>         return __x;
>        }
>
>      template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x, _Sent __bound) const
>        {
>         ranges::advance(__x, __bound);
>         return __x;
>        }
>
>      template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
>        {
>         ranges::advance(__x, __n, __bound);
>         return __x;
>        }
>
>      void operator&() const = delete;
>    };
>
>    inline constexpr __next_fn next{};
>
>    struct __prev_fn final
>    {
>      template<bidirectional_iterator _It>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x) const
>        {
>         --__x;
>         return __x;
>        }
>
>      template<bidirectional_iterator _It>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x, iter_difference_t<_It> __n) const
>        {
>         ranges::advance(__x, -__n);
>         return __x;
>        }
>
>      template<bidirectional_iterator _It>
> -      [[nodiscard]]
> +      [[nodiscard, __gnu__::__always_inline__]]
>        constexpr _It
>        operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
>        {
>         ranges::advance(__x, -__n, __bound);
>         return __x;
>        }
>
>      void operator&() const = delete;
>    };
>
> --
> 2.51.0
>
>
  

Patch

diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index 02e13a2027d1..c1a9f6a90009 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -61,29 +61,32 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 namespace ranges
 {
   template<typename>
     inline constexpr bool disable_sized_range = false;
 
   template<typename _Tp>
     inline constexpr bool enable_borrowed_range = false;
 
   namespace __detail
   {
+    [[__gnu__::__always_inline__]]
     constexpr __max_size_type
     __to_unsigned_like(__max_size_type __t) noexcept
     { return __t; }
 
+    [[__gnu__::__always_inline__]]
     constexpr __max_size_type
     __to_unsigned_like(__max_diff_type __t) noexcept
     { return __max_size_type(__t); }
 
     template<integral _Tp>
+      [[__gnu__::__always_inline__]]
       constexpr auto
       __to_unsigned_like(_Tp __t) noexcept
       { return static_cast<make_unsigned_t<_Tp>>(__t); }
 
     template<typename _Tp>
       using __make_unsigned_like_t
 	= decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
 
     // Part of the constraints of ranges::borrowed_range
     template<typename _Tp>
@@ -111,22 +114,23 @@  namespace ranges
 	  else if constexpr (__member_begin<_Tp>)
 	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
 	  else
 	    return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
 	  || __adl_begin<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
 	    {
 	      static_assert(is_lvalue_reference_v<_Tp>);
 	      return __t + 0;
 	    }
 	  else if constexpr (__member_begin<_Tp>)
 	    return __t.begin();
 	  else
 	    return begin(__t);
@@ -161,22 +165,23 @@  namespace ranges
 	  else if constexpr (__member_end<_Tp>)
 	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
 	  else
 	    return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
 	  || __member_end<_Tp> || __adl_end<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    {
 	      static_assert(is_lvalue_reference_v<_Tp>);
 	      return __t + extent_v<remove_reference_t<_Tp>>;
 	    }
 	  else if constexpr (__member_end<_Tp>)
 	    return __t.end();
 	  else
 	    return end(__t);
@@ -225,22 +230,23 @@  namespace ranges
 		  return is_nothrow_copy_constructible_v<_It>;
 		}
 	      else
 		return false;
 	    }
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const
+	operator()(_Tp&& __t) const
 	noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_rbegin<_Tp>)
 	    return __t.rbegin();
 	  else if constexpr (__adl_rbegin<_Tp>)
 	    return rbegin(__t);
 	  else
 	    return std::make_reverse_iterator(_End{}(__t));
 	}
     };
@@ -282,22 +288,23 @@  namespace ranges
 		  return is_nothrow_copy_constructible_v<_It>;
 		}
 	      else
 		return false;
 	    }
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const
+	operator()(_Tp&& __t) const
 	noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_rend<_Tp>)
 	    return __t.rend();
 	  else if constexpr (__adl_rend<_Tp>)
 	    return rend(__t);
 	  else
 	    return std::make_reverse_iterator(_Begin{}(__t));
 	}
     };
@@ -346,42 +353,44 @@  namespace ranges
 	    return noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
 	  else if constexpr (__sentinel_size<_Tp>)
 	    return noexcept(_End{}(std::declval<_Tp&>())
 			    - _Begin{}(std::declval<_Tp&>()));
 	}
 
     public:
       template<typename _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
 	  || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    return extent_v<remove_reference_t<_Tp>>;
 	  else if constexpr (__member_size<_Tp>)
 	    return __t.size();
 	  else if constexpr (__adl_size<_Tp>)
 	    return size(__t);
 	  else if constexpr (__sentinel_size<_Tp>)
 	    return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
 	}
     };
 
     struct _SSize
     {
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
       template<typename _Tp>
 	requires requires (_Tp& __t) { _Size{}(__t); }
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
+	operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
 	{
 	  auto __size = _Size{}(__t);
 	  using __size_type = decltype(__size);
 	  // Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
 	  if constexpr (integral<__size_type>)
 	    {
 	      using __gnu_cxx::__int_traits;
 	      if constexpr (__int_traits<__size_type>::__digits
 			    < __int_traits<ptrdiff_t>::__digits)
 		return static_cast<ptrdiff_t>(__size);
@@ -422,22 +431,23 @@  namespace ranges
 	    return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
 	  else
 	    return noexcept(bool(_Begin{}(std::declval<_Tp&>())
 		== _End{}(std::declval<_Tp&>())));
 	}
 
     public:
       template<typename _Tp>
 	requires __member_empty<_Tp> || __size0_empty<_Tp>
 	  || __eq_iter_empty<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr bool
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_empty<_Tp>)
 	    return bool(__t.empty());
 	  else if constexpr (__size0_empty<_Tp>)
 	    return _Size{}(__t) == 0;
 	  else
 	    return bool(_Begin{}(__t) == _End{}(__t));
 	}
     };
 
@@ -463,22 +473,23 @@  namespace ranges
 	{
 	  if constexpr (__member_data<_Tp>)
 	    return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
 	  else
 	    return noexcept(_Begin{}(std::declval<_Tp&>()));
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_data<_Tp> || __begin_data<_Tp>
+	[[nodiscard, __gnu__::__always_inline__]]
 	constexpr auto
-	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
 	{
 	  if constexpr (__member_data<_Tp>)
 	    return __t.data();
 	  else
 	    return std::to_address(_Begin{}(__t));
 	}
     };
 
   } // namespace __access
 
@@ -625,33 +636,35 @@  namespace ranges
 #if __glibcxx_ranges_as_const // >= C++23
   template<typename _Tp>
     concept constant_range
       = input_range<_Tp> && std::__detail::__constant_iterator<iterator_t<_Tp>>;
 #endif
 
   namespace __access
   {
 #if __glibcxx_ranges_as_const // >= C++23
     template<input_range _Range>
+      [[__gnu__::__always_inline__]]
       constexpr auto&
       __possibly_const_range(_Range& __r) noexcept
       {
 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
 	// 4027. possibly-const-range should prefer returning const R&
 	if constexpr (input_range<const _Range>)
 	  return const_cast<const _Range&>(__r);
 	else
 	  return __r;
       }
 #else
     // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
     template<typename _To, typename _Tp>
+      [[__gnu__::__always_inline__]]
       constexpr decltype(auto)
       __as_const(_Tp& __t) noexcept
       {
 	static_assert(std::is_same_v<_To&, _Tp&>);
 
 	if constexpr (is_lvalue_reference_v<_To>)
 	  return const_cast<const _Tp&>(__t);
 	else
 	  return static_cast<const _Tp&&>(__t);
       }
@@ -960,106 +973,106 @@  namespace ranges
 	iter_difference_t<_It> __n = 0;
 	while (__first != __last)
 	  {
 	    ++__first;
 	    ++__n;
 	  }
 	return __n;
       }
 
     template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr iter_difference_t<decay_t<_It>>
       operator()(_It&& __first, _Sent __last) const
       { return __last - static_cast<const decay_t<_It>&>(__first); }
 
     template<range _Range>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr range_difference_t<_Range>
       operator()(_Range&& __r) const
       {
 	if constexpr (sized_range<_Range>)
 	  return static_cast<range_difference_t<_Range>>(ranges::size(__r));
 	else
 	  return (*this)(ranges::begin(__r), ranges::end(__r));
       }
 
     void operator&() const = delete;
   };
 
   inline constexpr __distance_fn distance{};
 
   struct __next_fn final
   {
     template<input_or_output_iterator _It>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x) const
       {
 	++__x;
 	return __x;
       }
 
     template<input_or_output_iterator _It>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x, iter_difference_t<_It> __n) const
       {
 	ranges::advance(__x, __n);
 	return __x;
       }
 
     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x, _Sent __bound) const
       {
 	ranges::advance(__x, __bound);
 	return __x;
       }
 
     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
       {
 	ranges::advance(__x, __n, __bound);
 	return __x;
       }
 
     void operator&() const = delete;
   };
 
   inline constexpr __next_fn next{};
 
   struct __prev_fn final
   {
     template<bidirectional_iterator _It>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x) const
       {
 	--__x;
 	return __x;
       }
 
     template<bidirectional_iterator _It>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x, iter_difference_t<_It> __n) const
       {
 	ranges::advance(__x, -__n);
 	return __x;
       }
 
     template<bidirectional_iterator _It>
-      [[nodiscard]]
+      [[nodiscard, __gnu__::__always_inline__]]
       constexpr _It
       operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
       {
 	ranges::advance(__x, -__n, __bound);
 	return __x;
       }
 
     void operator&() const = delete;
   };