-
Notifications
You must be signed in to change notification settings - Fork 4
Description
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.