|
| 1 | +<?xml version='1.0' encoding='utf-8' standalone='no'?> |
| 2 | +<!DOCTYPE issue SYSTEM "lwg-issue.dtd"> |
| 3 | + |
| 4 | +<issue num="4394" status="New"> |
| 5 | +<title>`simd::unchecked_load(I first, S last)` construct `span` maybe ill-formed</title> |
| 6 | +<section><sref ref="[simd.loadstore]"/></section> |
| 7 | +<submitter>Hewill Kang</submitter> |
| 8 | +<date>30 Sep 2025</date> |
| 9 | +<priority>99</priority> |
| 10 | + |
| 11 | +<discussion> |
| 12 | +<p> |
| 13 | +Currently, `simd::unchecked_load`/`partial_load`/`unchecked_store`/`partial_store` |
| 14 | +constructs a `span` via `span(first, last)` when taking an iterator-sentinel pair |
| 15 | +`first` and `last`. |
| 16 | +<p/> |
| 17 | +However, the construction may not be well-behaved or well-formed when the sentinel type |
| 18 | +can be implicitly converted to an integer type. Consider: |
| 19 | +</p> |
| 20 | +<blockquote><pre> |
| 21 | +struct I { |
| 22 | + using value_type = int; |
| 23 | + using difference_type = int; |
| 24 | + using iterator_category = std::contiguous_iterator_tag; |
| 25 | + // contiguous iterator operators |
| 26 | + // ... |
| 27 | + |
| 28 | + operator int() const; |
| 29 | +}; |
| 30 | + |
| 31 | +int main() { |
| 32 | + std::simd::unchecked_load(I{}, I{}); |
| 33 | +} |
| 34 | +</pre></blockquote> |
| 35 | +<p> |
| 36 | +Above, `unchecked_load` invokes `unchecked_load(I first, S last)` and we attempt to |
| 37 | +construct `span` through `span(first, last)`. |
| 38 | +However, this is invalid because the constructor requires that the sentinel type should not be convertible to |
| 39 | +`size_t`, so we fall back into `span(first, n)` via implicitly converting `I` to `size_t`. Such |
| 40 | +behavior is subtle and likely unintended. |
| 41 | +<p/> |
| 42 | +Now consider: |
| 43 | +</p> |
| 44 | +<blockquote><pre> |
| 45 | +struct I { |
| 46 | + using value_type = int; |
| 47 | + using difference_type = int; |
| 48 | + using iterator_category = std::contiguous_iterator_tag; |
| 49 | + // contiguous iterator operators |
| 50 | + // ... |
| 51 | + |
| 52 | + operator int() &&; |
| 53 | +}; |
| 54 | + |
| 55 | +int main() { |
| 56 | + std::simd::unchecked_load(I{}, I{}); |
| 57 | +} |
| 58 | +</pre></blockquote> |
| 59 | +<p> |
| 60 | +We still attempt to construct the `span` by calling `span(first, last)`, which is invalid, |
| 61 | +but because the lvalue sentinel cannot be converted to `size_t`, the call of `span(first, n)` |
| 62 | +is also invalid. This makes the construction of the `span` ill-formed and leads to a hard error in |
| 63 | +the function body. |
| 64 | +</p> |
| 65 | +</discussion> |
| 66 | + |
| 67 | +<resolution> |
| 68 | +<p> |
| 69 | +This wording is relative to <paper num="N5014"/>. |
| 70 | +</p> |
| 71 | + |
| 72 | +<ol> |
| 73 | + |
| 74 | + |
| 75 | +<li><p>In subclause <sref ref="[simd.loadstore]"/> replace all occurrences of |
| 76 | +</p> |
| 77 | +<blockquote><pre> |
| 78 | +R(first, last) |
| 79 | +</pre></blockquote> |
| 80 | +<p> |
| 81 | +by |
| 82 | +</p> |
| 83 | +<blockquote><pre> |
| 84 | +R(first, <ins>static_cast<size_t>(</ins>last<ins> - first)</ins>) |
| 85 | +</pre></blockquote> |
| 86 | +</li> |
| 87 | +</ol> |
| 88 | + |
| 89 | +</resolution> |
| 90 | + |
| 91 | +</issue> |
0 commit comments