Title
Making istream_iterator copy constructor trivial is an ABI break
Status
c++23
Section
[istream.iterator.cons]
Submitter
Jonathan Wakely

Created on 2021-09-23.00:00:00 last changed 4 months ago

Messages

Date: 2022-11-17.00:42:33

Proposed resolution:

This wording is relative to N4917.

  1. Modify the class synopsis in [istream.iterator.general] as indicated:

    constexpr istream_iterator();
    constexpr istream_iterator(default_sentinel_t);
    istream_iterator(istream_type& s);
    constexpr istream_iterator(const istream_iterator& x) noexcept(see below) = default;
    ~istream_iterator() = default;
    istream_iterator& operator=(const istream_iterator&) = default;
    
  2. Modify [istream.iterator.cons] as indicated:

      constexpr istream_iterator(const istream_iterator& x) noexcept(see below) = default;
    

    -5- Postconditions: in_stream == x.in_stream is true.

    -?- Effects: Initializes in_stream with x.in_stream and initializes value with x.value.

    -6- Remarks: If is_trivially_copy_constructible_v<T> is true, then this constructor is trivial. An invocation of this constructor may be used in a core constant expression if and only if the initialization of value from x.value is a constant subexpression ([defns.const.subexpr]). The exception specification is equivalent to is_nothrow_copy_constructible_v<T>.

Date: 2022-11-12.00:00:00

[ 2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP. ]

Date: 2022-11-15.00:00:00

[ 2022-11-07; Reflector poll ]

Set status to Tentatively Ready after six votes in favour during reflector poll.

Date: 2022-10-15.00:00:00

[ 2022-10-13; Jonathan revises wording to add a noexcept-specifier ]

Date: 2022-10-15.00:00:00

[ 2022-10-12; Jonathan provides improved wording ]

Discussed on the reflector September 2021.

Date: 2021-10-15.00:00:00

[ 2021-10-14; Reflector poll ]

Set priority to 3 after reflector poll.

Previous resolution [SUPERSEDED]:

This wording is relative to N4892.

  1. Modify the class synopsis in [istream.iterator.general] as indicated:

    constexpr istream_iterator();
    constexpr istream_iterator(default_sentinel_t);
    istream_iterator(istream_type& s);
    constexpr istream_iterator(const istream_iterator& x) = default;
    ~istream_iterator() = default;
    istream_iterator& operator=(const istream_iterator&) = default;
    
  2. Modify [istream.iterator.cons] as indicated:

      constexpr istream_iterator(const istream_iterator& x) = default;
    

    -5- Postconditions: in_stream == x.in_stream is true.

    -6- Remarks: If is_trivially_copy_constructible_v<T> is true, then this constructor is trivial. If the initializer T(x.value) in the declaration auto val = T(x.value); is a constant initializer ([expr.const]), then this constructor is a constexpr constructor.

Date: 2021-09-15.00:00:00

[ 2021-09-30; Jonathan revises wording after reflector discussion ]

A benefit of triviality is that it is constexpr, want to preserve that.

Date: 2022-10-13.08:07:10

Libstdc++ never implemented this change made between C++03 and C++11 (by N2994):

24.6.1.1 [istream.iterator.cons] p3:
istream_iterator(const istream_iterator<T,charT,traits,Distance>& x) = default;

-3- Effects: Constructs a copy of x. If T is a literal type, then this constructor shall be a trivial copy constructor.

This breaks our ABI, as it changes the argument passing convention for the type, meaning this function segfaults if compiled with today's libstdc++ and called from one that makes the triviality change:

#include <iterator>
#include <istream>

int f(std::istream_iterator<int> i)
{
  return *i++;
}

As a result, it's likely that libstdc++ will never implement the change.

There is no reason to require this constructor to be trivial. It was required for C++0x at one point, so the type could be literal, but that is not true in the current language. We should strike the requirement, to reflect reality. MSVC and libc++ are free to continue to define it as defaulted (and so trivial when appropriate) but we should not require it from libstdc++. The cost of an ABI break is not worth the negligible benefit from making it trivial.

Previous resolution [SUPERSEDED]:

This wording is relative to N4892.

  1. Modify [istream.iterator.cons] as indicated:

    istream_iterator(const istream_iterator& x) = default;
    

    -5- Postconditions: in_stream == x.in_stream is true.

    -6- Remarks: If is_trivially_copy_constructible_v<T> is true, then this constructor is trivial.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-11-17 00:42:33adminsetmessages: + msg13049
2022-11-17 00:42:33adminsetstatus: voting -> wp
2022-11-08 03:46:49adminsetstatus: ready -> voting
2022-11-07 17:36:29adminsetmessages: + msg12949
2022-11-07 17:36:29adminsetstatus: new -> ready
2022-10-13 19:57:03adminsetmessages: + msg12869
2022-10-12 20:15:20adminsetmessages: + msg12866
2021-10-14 11:35:36adminsetmessages: + msg12156
2021-09-30 15:42:42adminsetmessages: + msg12078
2021-09-24 16:37:49adminsetmessages: + msg12068
2021-09-23 00:00:00admincreate