Skip to content

<spanstream>: The span constructed by basic_ispanstream's range constructor may be ill-formed #4879

@hewillk

Description

@hewillk

This range constructor is specified in [ispanstream.cons] as:

template<class ROS> explicit basic_ispanstream(ROS&& s)

-3- Constraints: ROS models ranges​::​borrowed_range. !convertible_to<ROS, std​::​span<charT>> && convertible_to<ROS, std​::​span<charT const>> is true.

-4- Effects: Let sp be std​::​span<const charT>(std​::​forward<ROS>(s)). Equivalent to:
basic_ispanstream(std::span<charT>(const_cast<charT*>(sp.data()), sp.size()))

Here, only std​::​span<const charT>(std​::​forward<ROS>(s)) is required, but MSVC always constructs span via std​::​span<const charT>(ranges:: data(s)), ranges::size(s)), which is not always well-formed (for example, when s is not a sized_range or contiguous_range):

#include <spanstream>

struct R {
  int* begin();
  std::unreachable_sentinel_t end();
  operator std::span<const int>() const;
};

int main() {
  R r{};
  std::basic_ispanstream<int> is{r}; // error
  is.span(r); // error
}

https://godbolt.org/z/Trv8d8qd3

The above example seems contrived, but libstdc++ accepts it as the standard guarantees it. (Whether this is worthy of LWG may be arguable).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!rangesC++20/23 ranges

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions