On Mon, Nov 17, 2025 at 11:55 AM Jakub Jelinek <[email protected]> wrote:

> On Mon, Nov 17, 2025 at 10:30:46AM +0100, Tomasz Kaminski wrote:
> > > --- a/libstdc++-v3/include/bits/iterator_concepts.h
> > > +++ b/libstdc++-v3/include/bits/iterator_concepts.h
> > > @@ -1008,7 +1008,7 @@ namespace ranges
> > >      // for use by __range_iter_t below.
> > >      template<typename _Tp>
> > >        requires is_array_v<_Tp> || __member_begin<_Tp&> ||
> > > __adl_begin<_Tp&>
> > > -      auto
> > > +      constexpr auto
> > >
> > This change seem like a fix for a pre-existing bug, and I would prefer to
> > land it as a separate commit,
> > using range_iter_t on any type with consteval begin/end members would
> cause
> > the same issue, I believe.
>
> I haven't managed to reproduce this outside of the reflection branch.
>
Yes, I was doing similar experiments, and reached the same conclusion: lack
of constexpr here
is not observable until consteval types get involved. So I retract my
suggestion to push it as separate
patch, as this change is strictly related to introduction of
std::meta::info and types composed out of it.

> The error without it is e.g.
> In file included from
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_iterator_base_types.h:73,
>                  from
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_algobase.h:65,
>                  from
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/array:45,
>                  from
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/meta:41,
>                  from
> /home/jakub/src/gcc-reflect/gcc/testsuite/g++.dg/reflect/can_substitute1.C:5:
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/iterator_concepts.h:
> In instantiation of 'auto std::ranges::__access::__begin(_Tp&) [with _Tp =
> std::initializer_list<std::meta::info>]':
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/iterator_concepts.h:1029:38:
>  required by substitution of 'template<class _Tp>  requires
> (__maybe_borrowed_range<_Tp>) && ((is_bounded_array_v<typename
> std::remove_reference<_Tp>::type>) || (__member_end<_Tp>) ||
> (__adl_end<_Tp>)) constexpr auto
> std::ranges::__access::_End::operator()(_Tp&&) const [with _Tp =
> std::initializer_list<std::meta::info>&]'
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ranges_base.h:513:13:
>  required by substitution of 'template<class R>  requires
> reflection_range<R> consteval bool could_substitute(std::meta::info, R&&)
> [with R = std::initializer_list<std::meta::info>]'
> /home/jakub/src/gcc-reflect/gcc/testsuite/g++.dg/reflect/can_substitute1.C:51:34:
>  required from here
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/iterator_concepts.h:1018:27:
> error: consteval-only expressions are only allowed in a constant-evaluated
> context
> /home/jakub/src/gcc-reflect/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/iterator_concepts.h:1013:7:
> error: function of consteval-only type must be declared 'consteval'
> which is on
> constexpr info null_reflection;
> ...
> template <reflection_range R = std::initializer_list <info>>
> consteval bool
> could_substitute (info r, R &&args)
> {
>   try { can_substitute (r, args); }
>   catch (std::meta::exception &) { return false; }
>   return true;
> }
>
> static_assert (!could_substitute (null_reflection, {}));
>
> I've tried to reproduce without info:
> #include <initializer_list>
> #include <ranges>
>
> using namespace std;
>
> template<class _Rg>
> concept my_range = ranges::input_range<_Rg>
>   && same_as<ranges::range_value_t<_Rg>, int>
>   && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, int>;
>
> template<my_range _Rg = initializer_list<int>>
>   consteval int foo(int x, _Rg&& y)
>   {
>     int r = x;
>     if constexpr (ranges::contiguous_range<_Rg>)
>       {
>         auto d = ranges::data(y);
>         auto s = ranges::size(y);
>         for (size_t i = 0; i < s; ++i)
>           r += d[i];
>       }
>     else
>       for (auto v : y)
>         r += v;
>     return r;
>   }
>
> int
> main ()
> {
>   static_assert (foo(42, { 1, 2, 3 }) == 48, "");
> }
> but that works just fine.
>
> I can reproduce with:
> #include <initializer_list>
> #include <ranges>
>
> using namespace std;
>
> template<class _Rg>
> concept my_range = ranges::input_range<_Rg>
>   && same_as<ranges::range_value_t<_Rg>, decltype(^^int)>
>   && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
> decltype(^^int)>;
>
> template<my_range _Rg = initializer_list<decltype(^^int)>>
>   consteval decltype(^^int) foo(decltype(^^int) x, _Rg&& y)
>   {
>     decltype(^^int) r = x;
>     if constexpr (ranges::contiguous_range<_Rg>)
>       {
>         auto d = ranges::data(y);
>         auto s = ranges::size(y);
>         for (size_t i = 0; i < s; ++i)
>           r = d[i];
>       }
>     else
>       for (auto v : y)
>         r = v;
>     return r;
>   }
>
> int
> main ()
> {
>   static_assert (foo(^^::, { ^^int, ^^short, ^^long }) == ^^long, "");
> }
> but that can't be committed separately because it won't work without
> reflection and reflection won't work properly without that.
>
> Or do you want to just commit that include/bits/stl_iterator_base_types.h
> hunk separately and then after the reflection branch goes in (if it does),
> commit incrementally a testcase like the above for it?
>
> Note, full list of failures on the branch is:
>
> FAIL: g++.dg/reflect/annotations5.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/can_substitute1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/common_reference1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/common_type1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/complete1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/substitute2.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/data_member_spec2.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_aggregate1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_aggregate2.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_aggregate3.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_aggregate4.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_aggregate5.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/define_static_array1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/eh4.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/eh5.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/eh6.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/type_trait11.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/serialize1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/serialize2.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/extract1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/has_c_language_linkage1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/has_default_argument1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/has_default_member_initializer1.C  -std=c++26 (test
> for excess errors)
> FAIL: g++.dg/reflect/has_ellipsis_parameter1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/has_external_linkage1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/has_internal_linkage1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/has_linkage1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/has_module_linkage1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/has_parent1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/has_template_arguments1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_accessible1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_alias_template1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_bit_field1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_class_member1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_class_template1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_complete_type1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_concept1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_constructible_type1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_constructible_type2.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_constructor_template1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_conversion_function1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_conversion_function_template1.C  -std=c++26 (test
> for excess errors)
> FAIL: g++.dg/reflect/is_data_member_spec1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_defaulted1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_deleted1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_enumerator1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_explicit_object_parameter1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_function1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_function_parameter1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_function_template1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_literal_operator1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_literal_operator_template1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_mutable_member1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_namespace1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_namespace_alias1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_namespace_member1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_nonstatic_data_member1.C  -std=c++26 (test for
> excess errors)
> FAIL: g++.dg/reflect/is_object1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_operator_function1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_operator_function_template1.C  -std=c++26 (test
> for excess errors)
> FAIL: g++.dg/reflect/is_override1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_static_member1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_template1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_type1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_type_alias1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_user_declared1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_user_provided1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/is_variable1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/is_variable_template1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/mangle1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/value_or_object1.C  -std=c++26 (test for excess
> errors)
> FAIL: g++.dg/reflect/members_of1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/members_of2.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/members_of3.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/splice1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/substitute1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/operator_of1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p2996-16.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p2996-17.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p2996-20.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p2996-21.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p3394-1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/p3491-1.C  -std=c++26 (test for excess errors)
> FAIL: g++.dg/reflect/parent_of1.C  -std=c++26 (test for excess errors)
>
>         Jakub
>
>

Reply via email to