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