<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/109456>109456</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [libc++] std::prev(it) should not compile for a non-bidi iterator
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            libc++
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          ldionne
      </td>
    </tr>
</table>

<pre>
    `std::prev(it, n)` could conceivably be well-formed for a non-bidirectional `it` if `n` is negative, however `std::prev(it)` is always UB, and we can easily diagnose it at compile-time. Right now `std::prev(non_bidi)` is a no-op, which is absolutely vexing.

https://godbolt.org/z/zaG3jTEqP

Potential patch:

```diff
diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h
index e950d8dc4147..98883188312a 100644
--- a/libcxx/include/__iterator/prev.h
+++ b/libcxx/include/__iterator/prev.h
@@ -26,7 +26,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
-prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
+prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n) {
   // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
   // Note that this check duplicates the similar check in `std::advance`.
   _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
@@ -35,6 +35,12 @@ prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n =
   return __x;
 }
 
+template <class _BidirectionalIterator,
+ __enable_if_t<__has_bidirectional_iterator_category<_BidirectionalIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _BidirectionalIterator prev(_BidirectionalIterator __it) {
+  return std::prev(std::move(__it), 1);
+}
+
 #if _LIBCPP_STD_VER >= 20
 
 // [range.iter.op.prev]

```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0Vl-P4jYQ_zTmZUSUOCTAAw8Q4IrU20PLtro3yzgD8dWx09iBpZ--cgJZdstJd5VOIhuvnZn5zZ-fZ7i18qgRZyRZkGQ54I0rTD1TuTRa42Bv8suMpKF1OYnnJJ5XNZ4InUhHaAaa0ClJQxCmUTkIowXKE9-rC-wRzqjU8GDqEnM4mBo4aKOHe5nLGoWTRnMFJA2l8xrkwa91u7Sg8cidPKG3UZgznrCG74CYXkW4OvOLhT8WXobrHM4IgmtAbqW6QC75URuLIB1wB8KUlVQ4dLLEAJ7lsXCgzfmREW0086DvTIE2Q1N5Q-dCiqLd21ujGofqAid8lfoYkHBJwnn3t3Cusl4rXRO6Ppp8b5QLTH0kdP2Pf_in-NvL6u_tvdDWONROcgUVd6Lw4nenJA27Xy4Ph27Lr2A4PHoXCV0ruRevr4SupRaqyZHQNWPSYc2dqQlde_-CAvY__GlnReocXwGnSZhPcjGKRuMgmE4mkzjyD-UQhWE6GnUfD4fDn8By9Ywuut9PQyOjkIxCGNKU0GwMhC5uq-6A_b5ZZNstW6w-bZ7Y0_zzaredZyu2e1l2CuD6clhWijsEEmdCcWuBbXTVuI3D2qedMdR8r5DJA3MkzhgruGXSf9JjY4I7PJr64s_fpONVV10nrpq2vqV2JF4BiZcQ-tMOgdRKauwR_7ZZrtj6-ctnNl9s-t3sy9PuZfV1-8x2m6dsxbKvX6PxPdQuB9dCftsHxl69aXepUPPSk-KK2dVcOvsYsS8vrFELZF4QGNMt6ojQKZDxos_er7P3zhIAdHyCjCsl9dGzl-cnrgV6pp6lKzxXr3cJtBEHox9eRDdEd_wGqcEVCKKpa9QOZFkpLFE77mWCjyCejENwBXfgCmlBFCj-gryplPSFYFtVVpZS8fp6KPW7--YN-pvuW6bnu93q-YVtV8v508sm89Fto5-1ZQNknJGxL0tfhu8c-9lyfE-kOCE0Sz2R2lVEb0z6tSXVu1-ja2rd6o5vWSfj92QldPGArov7IGz66yLrZb7D4R8I3mPVP8ZrQhf_i9IPbfZZeHzqr8mP1OxD-rHL9f-XxrfdyVXYO-L53Yff38y3BPj1NRM0lofeh93Lkv25eoY2Jkug4fvL9coXkixqro8Y-CAHpgpaJMnyYZMb5LM4n8ZTPsBZNKbpJEnHUTooZlTk0zjnIU1GhzxFkUyn8SQR8UGgGOfpYSBnNKSjcErDaEKTKA2iKOHxaBLnhwPihEZkFGLJpQqUOpW-Jw-ktQ3OonA6StKB4ntUtp2OKPXN6NaeqJ-W6pmXGu6boyWjUEnr7JseJ51q56o7sWT5n9B3WbJFO0Np0w8nH4amnlGDplazDxOFdEWzD4QpfcdUp9trWNXmGwrn26d3yhK6vvp1mtF_AwAA___eVhok">