Describe the bug
TL; DR: IIUC VSO-1308657 points to a bug of MSVC STL, not of the compiler.
The operator() of ranges::iter_move's type (std::ranges::_Iter_move::_Cpo) currently uses deduced return type:
|
template <class _Ty>
|
|
requires (_Choice<_Ty>._Strategy != _St::_None)
|
|
_NODISCARD _STATIC_CALL_OPERATOR constexpr decltype(auto) operator()(_Ty&& _Val) _CONST_CALL_OPERATOR
|
|
noexcept(_Choice<_Ty>._No_throw) {
|
|
constexpr _St _Strat = _Choice<_Ty>._Strategy;
|
|
|
|
if constexpr (_Strat == _St::_Custom) {
|
|
return iter_move(static_cast<_Ty&&>(_Val)); // intentional ADL
|
|
} else if constexpr (_Strat == _St::_Fallback) {
|
|
using _Ref = decltype(*static_cast<_Ty&&>(_Val));
|
|
if constexpr (is_lvalue_reference_v<_Ref>) {
|
|
return _STD move(*static_cast<_Ty&&>(_Val));
|
|
} else {
|
|
return *static_cast<_Ty&&>(_Val);
|
|
}
|
|
} else {
|
|
_STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy
|
|
}
|
|
}
|
Such strategy unexpectedly interacts with projected, as:
- many
ranges algorithms check concepts for projected<I, Proj>, and then
- these concepts eventually (via
indirectly-readable-impl) check the result type of ranges::iter_move on projected<I, Proj>, however,
- when
ranges::iter_move uses deduced return type, the body of its operator() needs to be instantiated, and hence projected::operator* also needs to be instantiated.
According to the Standard wording, projected::operator* is not defined, and thus such instantiation renders the program ill-formed, no diagnostic required. The known issue VSO-1308657 "Standard Library Header Units: std::projected::operator*() error LNK2019: unresolved external symbol" seems because of this.
MSVC STL adds the function body to projected::operator* as a workaround, which is arguably conforming under the IFNDR umbrella. But such extraneous instantiations seem undesired.
Command-line test case
Not reproducible because STL has the aforementioned workaround.
However, when I attempt to diagnose misuse of projected::operator* by adding static_assert(false); (as implementation of a potential LWG issue; already mailed to LWG Chair -> is LWG-4270 now), the undesired error can be raised from every use of ranges::equal (and many other ranges algorithms).
Expected behavior
No undesired instantiation happens. Call to projected::operator* can be rejected at compile time.
STL version
Every existing version since #565 (which implemented projected).
Additional context
Other implementations have already switched not to use deduced return type for ranges::iter_move:
Other related PRs:
Describe the bug
TL; DR: IIUC VSO-1308657 points to a bug of MSVC STL, not of the compiler.
The
operator()ofranges::iter_move's type (std::ranges::_Iter_move::_Cpo) currently uses deduced return type:STL/stl/inc/xutility
Lines 888 to 906 in 7841cf8
Such strategy unexpectedly interacts with
projected, as:rangesalgorithms check concepts forprojected<I, Proj>, and thenindirectly-readable-impl) check the result type ofranges::iter_moveonprojected<I, Proj>, however,ranges::iter_moveuses deduced return type, the body of itsoperator()needs to be instantiated, and henceprojected::operator*also needs to be instantiated.According to the Standard wording,
projected::operator*is not defined, and thus such instantiation renders the program ill-formed, no diagnostic required. The known issue VSO-1308657 "Standard Library Header Units:std::projected::operator*()error LNK2019: unresolved external symbol" seems because of this.MSVC STL adds the function body to
projected::operator*as a workaround, which is arguably conforming under the IFNDR umbrella. But such extraneous instantiations seem undesired.Command-line test case
Not reproducible because STL has the aforementioned workaround.
However, when I attempt to diagnose misuse of
projected::operator*by addingstatic_assert(false);(as implementation of a potential LWG issue; already mailed to LWG Chair -> is LWG-4270 now), the undesired error can be raised from every use ofranges::equal(and many otherrangesalgorithms).Expected behavior
No undesired instantiation happens. Call to
projected::operator*can be rejected at compile time.STL version
Every existing version since #565 (which implemented
projected).Additional context
Other implementations have already switched not to use deduced return type for
ranges::iter_move:Other related PRs:
ranges::iter_move)projected::operator*)chunk_by_view's helper lambda returnsbool#2890 (removed the non-workaround code)