Skip to content

PL250 22.07.3.2 [span.cons] size mismatch for fixed-sized span #246

@wg21bot

Description

@wg21bot

The resolution of the LWG3101 prevents accidental undefined behavior caused by size mismatch between the range and constructed span, e.g.:

void processFixed(span<int, 5>);
void processDynamic(span<int>);
std::vector<int> v;
processFixed(v); // ILL-FORMED after 3103, UB if v.size() != 5 before
processDynamic(v); // OK

However, the resolution does not prevent similar problems in the situation when the (ptr, len) or (ptr, ptr) constructor is used:

processFixed({v.data(), v.size()});  // WELL-FORMED, UB if v.size() != 5
processFixed({v.data(), v.data() + v.size()});  // WELL-FORMED, UB if v.size() != 5

Morover, currently, the code remains ill-formed even if explicit cast is performed by the user:

processFixed(span<int, 5>(v));  // ILL-FORMED

To resolve the issue, the construction of fixed-size span from dynamic-sized range should be explicit:

processFixed(v); // ILL-FORMED
processFixed({v.data(), v.size()}); // ILL-FORMED
processFixed({v.data(), v.data() + v.size()});  // ILL-FORMED
processFixed(span(v));  // WELL-FORMED
processFixed(span{v.data(), v.size()});  // WELL-FORMED
processFixed(span{v.data(), v.data() + v.size()});  // WELL-FORMED

To summarize:
Source | Destination | Constructor
Fixed | Fixed | Implicit, ill-formed if size-mismatch
Fixed | Dynamic | Implicit
Dynamic | Dynamic | Implicit
Dynamic | Fixed | Explicit

Proposed change:
Add 'explicit(extent != dynamic_extent)' specifier to the following constructors in [span.cons]:

constexpr span(pointer ptr, index_type count);
constexpr span(pointer first, pointer last);

In the specification of constructors:
template<class Container> constexpr span(Container& cont);
template<class Container> constexpr span(const Container& cont);

  • Add 'explicit(extent != dynamic_extent)' specifier.
  • Remove 'extent == dynamic_extent is true' ([span.cons]p 14.1) from Constrains element.
  • Add 'If extent is not equal to dynamic_extent, then size(cont) is equal to extent.' to Expects element.

In the specification of constructor:

template<class OtherElementType, size_t OtherExtent>
constexpr span(const span<OtherElementType, OtherExtent>& s) noexcept;
  • Add 'explicit(extent != dynamic_extent && OtherExtent == dynamic_extent)' specifier.
  • Replace the 'Extent == dynamic_extent || Extent == OtherExtent is true' constrain with 'Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent is true'.
  • Add 'If extent is not equal to dynamic_extent, then s.size() is equal to extent.' to Expects element.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions