https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94679
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Component|libstdc++ |c++
Ever confirmed|0 |1
Keywords| |link-failure
Last reconfirmed| |2020-04-21
Status|UNCONFIRMED |NEW
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
That function is intentionally not defined, and only used in unevaluated
contexts.
It seems to come from the sortable constraint on next_permutation, because
commenting out the requires-clause fixes the link failure:
template<bidirectional_range _Range, typename _Comp = ranges::less,
typename _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
The sortable concept uses projected as a template argument to another concept:
template<typename _Iter, typename _Rel = ranges::less,
typename _Proj = identity>
concept sortable = permutable<_Iter>
&& indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>;
That ends up being used with this constrained alias template:
template<__detail::__dereferenceable _Tp>
requires requires(_Tp& __t)
{ { ranges::iter_move(__t) } -> __detail::__can_reference; }
using iter_rvalue_reference_t
= decltype(ranges::iter_move(std::declval<_Tp&>()));
Which uses:
namespace ranges
{
namespace __cust_imove
{
void iter_move();
template<typename _Tp>
concept __adl_imove
= (std::__detail::__class_or_enum<remove_reference_t<_Tp>>)
&& requires(_Tp&& __t) { iter_move(static_cast<_Tp&&>(__t)); };
struct _IMove
{
// [...]
template<typename _Tp>
requires __adl_imove<_Tp> || requires(_Tp& __e) { *__e; }
constexpr decltype(auto)
operator()(_Tp&& __e) const
// noexcept([...])
{
if constexpr (__adl_imove<_Tp>)
return iter_move(static_cast<_Tp&&>(__e));
else if constexpr (is_reference_v<iter_reference_t<_Tp>>)
return std::move(*__e);
else
return *__e;
}
};
} // namespace __cust_imove
inline namespace __cust
{
inline constexpr __cust_imove::_IMove iter_move{};
} // inline namespace __cust
} // namespace ranges
So it appears that determining the return type of that function in an
unevaluated context causes its instantiation to be kept, leaving a reference to
the undefined projected::operator*() function.
We might be able to avoid using return type deduction for _IMove::operator()
but I wonder if this is really a compiler bug. I imagine this same problem
could occur for other uses of return type deduction.