This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3433. `subrange::advance(n)` has UB when `n < 0`

Section: 26.5.4.3 [range.subrange.access] Status: WP Submitter: Casey Carter Opened: 2020-04-21 Last modified: 2021-02-26

Priority: 2

View all issues with WP status.

Discussion:

`subrange::advance(n)` is specified to call `ranges::advance(begin_, n, end_)` in both `StoreSize` and `!StoreSize` cases (26.5.4.3 [range.subrange.access]/9). Unfortunately, `ranges::advance(begin_, n, end_)` has undefined behavior when `n < 0` unless `[end_, begin_)` denotes a valid range (25.4.4.2 [range.iter.op.advance]/5). This would all be perfectly fine — the UB is exposed to the caller via effects-equivalent-to — were it not the design intent that `subrange::advance(-n)` be usable to reverse the effects of `subrange::advance(n)` when the `subrange` has a bidirectional iterator type. That is, however, clearly the design intent: `subrange::prev()`, for example, is equivalent to `subrange::advance(-1)`.

[2020-05-11; Reflector prioritization]

Set priority to 2 after reflector discussions.

[2021-01-15; Issue processing telecon]

Set status to Tentatively Ready after discussion and poll.

F | A | N
--- | --- | ---
7 | 0 | 3

[2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

1. Modify 26.5.4.3 [range.subrange.access] as indicated:

   >     constexpr subrange& advance(iter_difference_t<I> n);

   > > -9- Effects: Equivalent to:

   > > 1. (9.1) — If `StoreSize` is `true`,

   > >    >     auto d = n - ranges::advance(begin_, n, end_);
   > >    >     if (d >= 0)
   > >    >       size_ -= to-unsigned-like(d);
   > >    >     else
   > >    >       size_ += to-unsigned-like(-d);
   > >    >     return *this;

   > > 2. (9.2) — Otherwise,

   > >    >     ranges::advance(begin_, n, end_);
   > >    >     return *this;

   > > >     if constexpr (bidirectional_iterator<I>) {
   > > >       if (n < 0) {
   > > >         ranges::advance(begin_, n);
   > > >         if constexpr (StoreSize)
   > > >           size_ += to-unsigned-like(-n);
   > > >         return *this;
   > > >       }
   > > >     }

   > > >     auto d = n - ranges::advance(begin_, n, end_);
   > > >     if constexpr (StoreSize)
   > > >       size_ -= to-unsigned-like(d);
   > > >     return *this;