Hi! This patch proposes a solution to the include cycle mentioned in https://gcc.gnu.org/pipermail/libstdc++/2026-September/067823.html. Ideally after the merge of this patch the P3052R2 paper can be naturally implemented.
Fully tested on x86_64, ok for trunk? Thanks, Yuao
From 03aea6c4b54da8a33ed4eb2c081b7d3331ec9347 Mon Sep 17 00:00:00 2001 From: Yuao Ma <[email protected]> Date: Mon, 5 Oct 2026 20:40:54 +0800 Subject: [PATCH] libstdc++: separate std::ranges::subrange declarations from ranges_util.h This PR will resolve the include cycle mentioned in https://gcc.gnu.org/pipermail/libstdc++/2026-September/067805.html. libstdc++-v3/ChangeLog: * include/Makefile.am: Add subrangefwd.h. * include/Makefile.in: Regenerate. * include/bits/ranges_util.h: Include <bits/subrangefwd.h>. (subrange_kind): Move to <bits/subrangefwd.h>. (subrange): Remove default template arguments, now on the declaration in <bits/subrangefwd.h>. (get): Use non-deduced return type. (__is_subrange, __is_tuple_like_v, tuple_size, tuple_element): Move specializations for subrange to <bits/subrangefwd.h>. * include/bits/stl_pair.h: Reference <bits/subrangefwd.h>. * include/std/tuple: Include <bits/subrangefwd.h> instead of <bits/ranges_util.h>. * include/bits/subrangefwd.h: New file. gcc/testsuite/ChangeLog: * g++.dg/modules/inst-8_a.C: Include <new> for placement new, previously included transitively via <tuple>. --- gcc/testsuite/g++.dg/modules/inst-8_a.C | 1 + libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/ranges_util.h | 46 ++-------- libstdc++-v3/include/bits/stl_pair.h | 2 +- libstdc++-v3/include/bits/subrangefwd.h | 109 ++++++++++++++++++++++++ libstdc++-v3/include/std/tuple | 2 +- 7 files changed, 119 insertions(+), 43 deletions(-) create mode 100644 libstdc++-v3/include/bits/subrangefwd.h diff --git a/gcc/testsuite/g++.dg/modules/inst-8_a.C b/gcc/testsuite/g++.dg/modules/inst-8_a.C index 1b0a47978cb..da8afd35bea 100644 --- a/gcc/testsuite/g++.dg/modules/inst-8_a.C +++ b/gcc/testsuite/g++.dg/modules/inst-8_a.C @@ -5,6 +5,7 @@ module; #include <coroutine> +#include <new> #include <tuple> #include <typeinfo> export module std; diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 3c30aa21d6b..ebdb3410df1 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -185,6 +185,7 @@ bits_freestanding = \ ${bits_srcdir}/stl_raw_storage_iter.h \ ${bits_srcdir}/stl_relops.h \ ${bits_srcdir}/stl_uninitialized.h \ + ${bits_srcdir}/subrangefwd.h \ ${bits_srcdir}/text_encoding-data.h \ ${bits_srcdir}/version.h \ ${bits_srcdir}/string_view.tcc \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index d081481293f..333d17cb6c1 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -543,6 +543,7 @@ bits_freestanding = \ ${bits_srcdir}/stl_raw_storage_iter.h \ ${bits_srcdir}/stl_relops.h \ ${bits_srcdir}/stl_uninitialized.h \ + ${bits_srcdir}/subrangefwd.h \ ${bits_srcdir}/text_encoding-data.h \ ${bits_srcdir}/version.h \ ${bits_srcdir}/string_view.tcc \ diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index e6c02aa1d92..6e56596c0b7 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -35,6 +35,7 @@ # include <bits/utility.h> # include <bits/invoke.h> # include <bits/cpp_type_traits.h> // __can_use_memchr_for_find +# include <bits/subrangefwd.h> // subrange, get, tuple_size #if __glibcxx_tuple_like // >= C++23 # include <bits/stl_pair.h> // __pair_like, __is_tuple_like_v #endif @@ -259,12 +260,8 @@ namespace ranges namespace views { struct _Drop; } // defined in <ranges> - enum class subrange_kind : bool { unsized, sized }; - - /// The ranges::subrange class template - template<input_or_output_iterator _It, sentinel_for<_It> _Sent = _It, - subrange_kind _Kind = sized_sentinel_for<_Sent, _It> - ? subrange_kind::sized : subrange_kind::unsized> + template<input_or_output_iterator _It, sentinel_for<_It> _Sent, + subrange_kind _Kind> requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _It>) class subrange : public view_interface<subrange<_It, _Sent, _Kind>> { @@ -450,7 +447,7 @@ namespace ranges // constrain I to be copyable when N == 0 template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> requires ((_Num == 0 && copyable<_It>) || _Num == 1) - constexpr auto + constexpr __conditional_t<_Num == 0, _It, _Sent> get(const subrange<_It, _Sent, _Kind>& __r) { if constexpr (_Num == 0) @@ -461,7 +458,7 @@ namespace ranges template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> requires (_Num < 2) - constexpr auto + constexpr __conditional_t<_Num == 0, _It, _Sent> get(subrange<_It, _Sent, _Kind>&& __r) { if constexpr (_Num == 0) @@ -478,18 +475,8 @@ namespace ranges using borrowed_subrange_t = __conditional_t<borrowed_range<_Range>, subrange<iterator_t<_Range>>, dangling>; - - // __is_subrange is defined in <bits/utility.h>. - template<typename _Iter, typename _Sent, subrange_kind _Kind> - inline constexpr bool __detail::__is_subrange<subrange<_Iter, _Sent, _Kind>> = true; } // namespace ranges -#if __glibcxx_tuple_like // >= C++23 - // __is_tuple_like_v is defined in <bits/stl_pair.h>. - template<typename _It, typename _Sent, ranges::subrange_kind _Kind> - inline constexpr bool __is_tuple_like_v<ranges::subrange<_It, _Sent, _Kind>> = true; -#endif - // The following ranges algorithms are used by <ranges>, and are defined here // so that <ranges> can avoid including all of <bits/ranges_algo.h>. namespace ranges @@ -827,29 +814,6 @@ namespace ranges } // namespace ranges - using ranges::get; - - template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> - struct tuple_size<ranges::subrange<_Iter, _Sent, _Kind>> - : integral_constant<size_t, 2> - { }; - - template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> - struct tuple_element<0, ranges::subrange<_Iter, _Sent, _Kind>> - { using type = _Iter; }; - - template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> - struct tuple_element<1, ranges::subrange<_Iter, _Sent, _Kind>> - { using type = _Sent; }; - - template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> - struct tuple_element<0, const ranges::subrange<_Iter, _Sent, _Kind>> - { using type = _Iter; }; - - template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> - struct tuple_element<1, const ranges::subrange<_Iter, _Sent, _Kind>> - { using type = _Sent; }; - template<typename _Tp, typename _IndexType> class _Repeat_iterator; diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index ccff8691206..586e954211c 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -258,7 +258,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, size_t _Nm> inline constexpr bool __is_tuple_like_v<array<_Tp, _Nm>> = true; - // __is_tuple_like_v<subrange> is defined in <bits/ranges_util.h>. + // __is_tuple_like_v<subrange> is defined in <bits/subrangefwd.h>. template<typename _Tp> concept __tuple_like = __is_tuple_like_v<remove_cvref_t<_Tp>>; diff --git a/libstdc++-v3/include/bits/subrangefwd.h b/libstdc++-v3/include/bits/subrangefwd.h new file mode 100644 index 00000000000..2a7c83b54f5 --- /dev/null +++ b/libstdc++-v3/include/bits/subrangefwd.h @@ -0,0 +1,109 @@ +// Forward declarations for std::ranges::subrange -*- C++ -*- + +// Copyright (C) 2026 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/subrangefwd.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{ranges} + */ + +#ifndef _SUBRANGEFWD_H +#define _SUBRANGEFWD_H 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#include <bits/version.h> + +#ifdef __glibcxx_ranges // C++ >= 20 && concepts +#include <bits/stl_iterator_base_types.h> +#include <bits/utility.h> +#if __glibcxx_tuple_like // >= C++23 +# include <bits/stl_pair.h> +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace ranges +{ + enum class subrange_kind : bool { unsized, sized }; + + /// The ranges::subrange class template. + template<input_or_output_iterator _It, sentinel_for<_It> _Sent = _It, + subrange_kind _Kind = sized_sentinel_for<_Sent, _It> + ? subrange_kind::sized : subrange_kind::unsized> + requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _It>) + class subrange; + + template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> + requires ((_Num == 0 && copyable<_It>) || _Num == 1) + constexpr __conditional_t<_Num == 0, _It, _Sent> + get(const subrange<_It, _Sent, _Kind>& __r); + + template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> + requires (_Num < 2) + constexpr __conditional_t<_Num == 0, _It, _Sent> + get(subrange<_It, _Sent, _Kind>&& __r); + + // __is_subrange is defined in <bits/utility.h>. + template<typename _Iter, typename _Sent, subrange_kind _Kind> + inline constexpr bool + __detail::__is_subrange<subrange<_Iter, _Sent, _Kind>> = true; +} // namespace ranges + + using ranges::get; + +#if __glibcxx_tuple_like // >= C++23 + // __is_tuple_like_v is defined in <bits/stl_pair.h>. + template<typename _It, typename _Sent, ranges::subrange_kind _Kind> + inline constexpr bool + __is_tuple_like_v<ranges::subrange<_It, _Sent, _Kind>> = true; +#endif + + template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> + struct tuple_size<ranges::subrange<_Iter, _Sent, _Kind>> + : integral_constant<size_t, 2> + { }; + + template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> + struct tuple_element<0, ranges::subrange<_Iter, _Sent, _Kind>> + { using type = _Iter; }; + + template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> + struct tuple_element<1, ranges::subrange<_Iter, _Sent, _Kind>> + { using type = _Sent; }; + + template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> + struct tuple_element<0, const ranges::subrange<_Iter, _Sent, _Kind>> + { using type = _Iter; }; + + template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> + struct tuple_element<1, const ranges::subrange<_Iter, _Sent, _Kind>> + { using type = _Sent; }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_ranges +#endif // _SUBRANGEFWD_H diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index d73cefcbca8..c39ec35b9db 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -43,7 +43,7 @@ #include <bits/invoke.h> // for std::__invoke #if __cplusplus > 201703L # include <compare> -# include <bits/ranges_util.h> // for std::ranges::subrange +# include <bits/subrangefwd.h> // for std::ranges::subrange #endif #define __glibcxx_want_constexpr_tuple -- 2.54.0
