Skip to content

<xutility>: default_initializable<move_iterator<It>> may be problematic for Clang #3377

Description

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcompilerCompiler work involvedfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions