3614. iota_view::size and the most negative signed integer values

Section: 25.6.4.2 [range.iota.view] Status: New Submitter: Jiang An Opened: 2021-10-01 Last modified: 2021-10-14

Priority: 3

View all other issues in [range.iota.view].

View all issues with New status.

Discussion:

According to 25.6.4.2 [range.iota.view]/15, when both W and Bound are integer-like, the expression in the return statement uses -value_ and -bound_. These operations result in undefined behavior when - is applied to the most negative integer value of a promoted type.

I believe that we can simply convert value_ and bound_ to the return type (make-unsigned-like-t<common_type_t<W, Bound>>) and then perform the subtraction. Such method should give the same results with UB eliminated.

Additionally, if we decide that iota_view<uint8_t, uint8_t>(uint8_t(1)).size() is well-defined (LWG 3597), it should give the correct result. We can truncate the result to fit the type W.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4892.

[Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A: Just fixes the most negative values

  1. Modify 25.6.4.2 [range.iota.view] as indicated:

    constexpr auto size() const requires see below;
    

    -15- Effects: Equivalent to:

    if constexpr (is-integer-like<W> && is-integer-like<Bound>) {
      return (value_ < 0)
        ? ((bound_ < 0)
          ? to-unsigned-like(-value_) - to-unsigned-like(-bound_)
          : to-unsigned-like(bound_) + to-unsigned-like(-value_))
        : to-unsigned-like(bound_) - to-unsigned-like(value_);
      using UC = make-unsigned-like-t<common_type_t<W, Bound>>;
      return UC(bound_) - UC(value_);
    } else
      return to-unsigned-like(bound_ - value_);
    

    -16- Remarks: […]

Option B: Also fixes pathological cases involving unsigned-integer-like types

  1. Modify 25.6.4.2 [range.iota.view] as indicated:

    constexpr auto size() const requires see below;
    

    -15- Effects: Equivalent to:

    if constexpr (is-integer-like<W> && is-integer-like<Bound>) {
      return (value_ < 0)
        ? ((bound_ < 0)
          ? to-unsigned-like(-value_) - to-unsigned-like(-bound_)
          : to-unsigned-like(bound_) + to-unsigned-like(-value_))
        : to-unsigned-like(bound_) - to-unsigned-like(value_);
      using UC = make-unsigned-like-t<common_type_t<W, Bound>>;
      if constexpr (is-signed-integer-like<W>)
        return UC(bound_) - UC(value_);
      else
        return UC(W(UC(bound_) - UC(value_)));
    } else
      return to-unsigned-like(bound_ - value_);
    

    -16- Remarks: […]