Describe the bug
TL;DR: LLVM-60293 is likely not a bug and we may need to change move_iterator's default constructor to make Clang happy.
In cases like views::join_with(r1 | views::as_rvalue, r2 | views::as_rvalue) (already occur in test file due to #3359), the iterator type of the resulted join_with_view wraps an move_iterator and default_initializable<move_iterator<It>> is detected, where It is the iterator type of r1. When It is a non-default-initializable input_iterator type (more precisely, when It{} is ill-formed), MSVC STL's implementation of move_iteratorresults in weird behavior of Clang.
MSVC STL's move_iterator has a defaulted default constructor:
|
_CONSTEXPR17 move_iterator() = default;
|
And the required value-initialization is performed via default member initializer:
|
iterator_type _Current{};
|
Per [class.default.ctor]/2.3, the default member initializer makes the default constructor of move_iterator never deleted (which is decided in CWG-927). Given a non-default-initializable It, default_initializable<move_iterator<It>> ask whether is_constructible_v<move_iterator<It>> is true, which may make the program ill-formed per this note, and implementation divergence seems (unfortunately) permitted (discussed in llvm/llvm-project#60293).
There're many iterator-related facilities using default_initializable to constrain their default constructors. We may need to change move_iterator's default constructor to make them usable with move_iterator and non-default-initializable input iterators when compiling with Clang.
The current approach has some benefits:
- the exception specification is automatically strengthened;
- the default constructor can be sometimes implicitly
constexpr in C++14 mode, although this makes little sense because most operations are only constexpr since C++17.
Possible resolutions (may be only applied for Clang):
- Just making the default constructor non-defaulted. Cons:
- either we need a non-conforming
constexpr in C++14 mode, or we'll break some non-portable constexpr uses of move_iterator in C++14;
- exception specification strengthening may be preferable, but throughput might be (sightly) damaged.
- Adding base classes to make the default constructor conditionally deleted and otherwise defaulted. Cons:
- also damages throughput;
- the adapted iterator may be designed in such way that asking whether it satisfies
is_default_constructible is ill-formed, while neither input_iterator nor Cpp17InputIterator cares default-initializability.
Describe the bug
TL;DR: LLVM-60293 is likely not a bug and we may need to change
move_iterator's default constructor to make Clang happy.In cases like
views::join_with(r1 | views::as_rvalue, r2 | views::as_rvalue)(already occur in test file due to #3359), the iterator type of the resultedjoin_with_viewwraps anmove_iteratoranddefault_initializable<move_iterator<It>>is detected, whereItis the iterator type ofr1. WhenItis a non-default-initializableinput_iteratortype (more precisely, whenIt{}is ill-formed), MSVC STL's implementation ofmove_iteratorresults in weird behavior of Clang.MSVC STL's
move_iteratorhas a defaulted default constructor:STL/stl/inc/xutility
Line 3942 in f8b8ad6
And the required value-initialization is performed via default member initializer:
STL/stl/inc/xutility
Line 4165 in f8b8ad6
Per [class.default.ctor]/2.3, the default member initializer makes the default constructor of
move_iteratornever deleted (which is decided in CWG-927). Given a non-default-initializableIt,default_initializable<move_iterator<It>>ask whetheris_constructible_v<move_iterator<It>>istrue, which may make the program ill-formed per this note, and implementation divergence seems (unfortunately) permitted (discussed in llvm/llvm-project#60293).There're many iterator-related facilities using
default_initializableto constrain their default constructors. We may need to changemove_iterator's default constructor to make them usable withmove_iteratorand non-default-initializable input iterators when compiling with Clang.The current approach has some benefits:
constexprin C++14 mode, although this makes little sense because most operations are onlyconstexprsince C++17.Possible resolutions (may be only applied for Clang):
constexprin C++14 mode, or we'll break some non-portableconstexpruses ofmove_iteratorin C++14;is_default_constructibleis ill-formed, while neitherinput_iteratornor Cpp17InputIterator cares default-initializability.