TLDR: I propose we allow std::ranges::subrange, with a note that if authors want the code to enforce that the underlying memory is contiguous, they should probably prefer base::span.
Background: Multiple users (on chromium-dev@, Slack #base, etc.) have asked about how to handle pair-of-iterators/iterator+sentinel cases. While base::span is a good default choice, some use cases don't care whether the underlying data happens to be contiguous (e.g. for data stored in a base::flat_map, that might just as well be in a std::map someday) or actually have non-contiguous data. In these cases we offer no ergonomic choice today.
The ideal long-term solution here is unclear. Memory safety folks note that pair-of-iterators datatypes risk UNSAFE_BUFFERS issues. Dana filed
an llvm bug seeking clarity on unsafe buffer annotations in libc++.
In the meantime, I think subrange is an OK view to carve out support for. It doesn't make things worse than status quo -- it's a slim wrapper around a pair of iterators, so it doesn't have lazy eval and some of the other issues with STL view types. It doesn't require us to support chaining via pipes. If we want to replace it with a base::subrange that has more qualifiers on it, our API would probably look similar, and having people using the STL type directly will encapsulate the callsites so we can understand the scope of any such transform.
To me the biggest question is whether we also guide people to prefer span where feasible. I think the answer should be "yes, but base it not on 'does it compile' but on whether you want to enforce that the underlying data remains contiguous." Using span in other cases poses a refactoring hazard in the future, while giving no guidance at all probably sacrifices some level of safety.
PK