-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
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:
Lines 888 to 906 in 7841cf8
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 forprojected<I, Proj>
, and then - these concepts eventually (via
indirectly-readable-impl
) check the result type ofranges::iter_move
onprojected<I, Proj>
, however, - when
ranges::iter_move
uses 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 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
:
- LLVM-D120417 (llvm/llvm-project@fbcd523)
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92894 (https://gcc.gnu.org/cgit/gcc/commit/?id=6fedf28c7921f125be75a9f688a7b845a1b5663b)
Other related PRs:
- Ranges <range> machinery #82 (added
ranges::iter_move
) - <format> Properly handle multibyte encodings in format strings #1815 (added the workaround to
projected::operator*
) chunk_by_view
's helper lambda returnsbool
#2890 (removed the non-workaround code)