Skip to content

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

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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