---
title: "Fix LWG4470: Fix integer-from in [simd]"
document: P3932R0
date: 2026-02-13
audience: LWG
reply-to:
  - "Matthias Kretz < <m.kretz@gsi.de>"
paper-type: proposal
---

| Document Number: | P3932R0 |
| --- | --- |
| Date: | 2026-02-13 |
| Reply-to: | Matthias Kretz <m.kretz@gsi.de> |
| Audience: | LWG |
| Target: | C++26 |

# Fix LWG4470: Fix integer-from in [simd]

[This paper resolves LWG4470. Since the resolution needs to modify wording that LWG4414 and](https://cplusplus.github.io/LWG/issue4414) [LWG4518 also need to modify, this paper additionally resolves LWG4414 and LWG4518.](https://cplusplus.github.io/LWG/issue4518)

### 1

#### (placeholder)

### 2

#### 2.1

[In the discussion of LWG4238, Tim noted that](https://cplusplus.github.io/LWG/issue4238) `integer-from``<Bytes>` does not work as intended because `Bytes` can be 16 after `complex<double>` became a vectorizable type.1 [I then opened LWG4470,](https://cplusplus.github.io/LWG/issue4470) [which this paper aims to resolve. LWG4470:](https://cplusplus.github.io/LWG/issue4470)

##### After the introduction of `complex<double>` to the set ofvectorizable types, the `integer-`

`from``<Bytes>` trait does not work as intended anymore. All uses of `integer-from` need to be reviewed and the wording needs to be adjusted to work for `Bytes=16`.

This issue is a question on how we define masks and their ABIs. I sketched a potential solution in `https://lists.isocpp.org/lib/2025/04/31251.php`.

###### 2.2

Later I noticed that a surprising change in ABI can happen on `std::simd::cat`[. This is LWG4518:](https://cplusplus.github.io/LWG/issue4518)

###### The return type of `simd::cat` is defined using `deduce-abi-t` rather than `resize_t`.

```cpp
basic_vec <T, Abi > x = ...
auto [...vs] = simd::chunk <2>(x);
auto y = simd::cat(vs...);
static_assert(is_same_v <decltype(x), decltype(y)>); // can fail
```

This happens when bit-mask and vec-mask types are mixed, and can also happen (in my implementation) with complex value types. `simd::cat` should try to be conservative wrt. the resulting ABI tag. However, `simd::cat` allows different ABI tags on its arguments (to allow different width). If the user gives mixed input, there’s no obvious correct answer. I suggest the simple heuristic of using the first argument with

###### `resize_t`.

Since the `simd::cat` wording currently uses `integer-from` it makes sense to resolve the two issues together.

1 It was not intended to require conforming implementations to now provide a 128-bit signed integer type.

####### 2.3

####### 4414: §[simd.expos.abi] `deduce-abi-t` is underspecified and incorrectly referenced

####### from `rebind` and `resize`

[Finally, since LWG4414 changes the same wording we need to change for LWG4470, I incorporated](https://cplusplus.github.io/LWG/issue4470) [the proposed resolution into the wording of this paper. LWG4414:](https://cplusplus.github.io/LWG/issue4414)

###### In 29.10.2.2 [simd.expos.abi], `deduce-abi-t` is specified to be defined for some arguments.

###### The wording needs to clarify what happens in those cases.

###### In 29.10.4 [simd.traits], `rebind` and `resize` say ”`deduce-abi-t``<T,` `V::size()>` has a

### 3

| 3.1 | feature test macro |
| --- | --- |
| Bump? There are minor behavior changes, but I recommend no change to the macro.3.2 | modify [simd.expos] |

#### In [simd.expos], add:

:::wording-add

[simd.expos] using simd-size-type = see below; // exposition only template<size_t Bytes> using integer-from = see below; // exposition only template<class T, class Abi> constexpr simd-size-type simd-size-v = see below; // exposition only <ins>template<size_t Bytes, class Abi></ins> <ins>constexpr simd-size-type mask-size-v = see below;</ins> <ins>// exposition only</ins> template<class T> constexpr size_t mask-element-size = see below; // exposition only

:::

##### 3.3

###### In [simd.expos.defn], change:

[simd.expos.defn] `template<class` `T``,` `class` `Abi``>` `constexpr` `simd-size-type` `simd-size-v` `=` `see` `below``;`

3 `simd-size-v``<T,` `Abi>` denotes the width of `basic_vec<T,` `Abi>` if the specialization `basic_vec<T,` `Abi>` is enabled, or `0` otherwise.

:::wording-add

<ins>template<size_t Bytes, class Abi></ins> <ins>constexpr simd-size-type mask-size-v = see below;</ins>

:::

:::wording-add

<ins>-?mask-size-v</ins> <ins><Bytes, Abi> denotes the width of basic_mask<Bytes, Abi> if the specialization basic_mask<Bytes,</ins> <ins>Abi> is enabled, or 0 otherwise.</ins>

:::

```cpp
template<class T> constexpr size_t mask-element-size = see below;
```

####### 3.4

###### In [simd.expos.abi], change:

[simd.expos.abi]

:::wording

4 deduce-abi-t<T, N> <del>is defined</del><ins>names an ABI tag type if and only</ins> if

:::

* `T` is a vectorizable type,

* `N` is greater than zero, and

* `N` is not larger than an implementation-defined maximum.

:::wording-add

<ins>Otherwise, deduce-abi-t<T, N> names an unspecified type.</ins>

:::

The implementation-defined maximum for `N` is not smaller than 64 and can differ depending on `T`.

:::wording

5 <del>Where present,</del><ins>If</ins> deduce-abi-t<T, N> names an ABI tag type <del>such that</del><ins>, the following is true:</ins>

:::

:::wording-add

• simd-size-v<T, deduce-abi-t<T, N>> equals N, <ins>and</ins>

:::

:::wording-remove

• basic_vec<T, deduce-abi-t<T, N>> is enabled ([simd.overview]), <del>and</del>

:::

:::wording-remove

<del>• basic_mask<sizeof(T), deduce-abi-t<integer-from<sizeof(T)>, N> is enabled</del>.

:::

####### 3.5

###### In [simd.syn], change:

:::wording

[simd.syn] template<class T, class... Abis> constexpr <del>basic_vec<T, deduce-abi-t<T,</del> <ins>resize_t<(basic_vec<T, Abis>::size() + ...), basic_vec<T,</ins> <ins>Abis...[0]</ins>>> cat(const basic_vec<T, Abis>&...) noexcept; template<size_t Bytes, class... Abis> constexpr <del>basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>,</del><ins>resize_t<</ins>

:::

:::wording-add

(basic_mask<Bytes, Abis>::size() + ...)<ins>, basic_mask<Bytes, Abis...[0]</ins>>> cat(const basic_mask<Bytes, Abis>&...) noexcept; […]

:::

:::wording

// [simd.mask.class], class template basic_mask template<size_t Bytes, class Abi <del>= native-abi<integer-from<Bytes>></del>> class basic_mask; template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>> using mask = <del>basic_mask<sizeof(T), deduce-abi-t<T, N>></del><ins>vec<T, N>::mask_type</ins>;

:::

####### 3.6

[simd.traits] `template<class` `T``,` `class` `V``>` `struct` `rebind` `{` `using` `type` `=` `see` `below``;` `};`

4 The member `type` is present if and only if

* `V` is a data-parallel type,

* `T` is a vectorizable type, and

:::wording

• deduce-abi-t<T, V::size()> <del>has a member type type</del><ins>names an ABI tag type</ins>.

:::

5 If `V` is a specialization of `basic_vec`, let `Abi1` denote an ABI tag such that `basic_vec<T,` `Abi1>::size()` equals `V::size()`. If `V` is a specialization of `basic_mask`, let `Abi1` denote an ABI tag such that `basic_mask<sizeof(T),` `Abi1>::size()` equals `V::size()`.

6 Where present, the member typedef `type` names `basic_vec<T,` `Abi1>` if `V` is a specialization of `basic_vec` or `basic_mask<sizeof(T),` `Abi1>` if `V` is a specialization of `basic_mask`.

```cpp
template<simd-size-type N, class V> struct resize { using type = see below; };
```

:::wording

7 Let <del>T</del><ins>Abi1 denote an ABI tag</ins>

:::

:::wording

• <del>typename V::value_type</del><ins>such that simd-size-v<typename V::value_type, Abi1> equals N</ins> if V is a specialization of basic_vec,

:::

:::wording

• otherwise <del>integer-from<mask-element-size<V></del><ins>such that mask-size-v<mask-element-size<V>, Abi1></ins> <ins>equals N</ins> if V is a specialization of basic_mask.

:::

8 The member `type` is present if and only if

* `V` is a data-parallel type, and

:::wording

• <del>deduce-abi-t<T, N> has a member type type</del><ins>there exists at least one ABI tag that satisfies the</ins> <ins>above constraints for Abi1</ins>.

:::

:::wording-remove

9 <del>If V is a specialization of basic_vec, let Abi1 denote an ABI tag such that basic_vec<T, Abi1>::</del> size( <del>equals N. If V is a specialization of basic_mask, let Abi1 denote an ABI tag such that basic_mask<sizeof(T),</del> <del>Abi1>::size() equals N</del>.

:::

:::wording

10 Where present, the member typedef type names basic_vec<<del>T</del><ins>typename V::value_type</ins>, Abi1> if V is a specialization of basic_vec or basic_mask<<del>sizeof(T)</del><ins>mask-element-size<V></ins>, Abi1> if V is a specialization of basic_mask.

:::

####### 3.7

[simd.overview]

1 Every specialization of `basic_vec` is a complete type. The specialization of `basic_vec<T,` `Abi>` is

:::wording

• enabled, if T is a vectorizable type, and there exists value N in the range [1, 64], such that Abi <del>is</del><ins>names</ins> <ins>the ABI tag type denoted by</ins> deduce-abi-t<T, N>,

:::

* otherwise, disabled, if `T` is not a vectorizable type,

* otherwise, it is implementation-defined if such a specialization is enabled.

If `basic_vec<T,` `Abi>` is disabled, then the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment. In addition only the `value_type`, `abi_type`, and `mask_type` members are present. If `basic_vec<T,` `Abi>` is enabled, then

:::wording-add

<ins>•</ins> basic_vec<T, Abi> is trivially copyable,

:::

:::wording

<ins>•</ins> default-initialization of an object of such a type default-initializes all elements, <del>and</del>

:::

:::wording-add

<ins>• value-initialization value-initializes all elements ([dcl.init.general]),</ins>

:::

:::wording-add

<ins>• basic_vec<T, Abi>::mask_type is an alias for an enabled specialization of basic_mask, and</ins>

:::

:::wording-add

<ins>• basic_vec<T, Abi>::size() is equal to basic_vec<T, Abi>::mask_type::size()</ins>.

:::

####### 3.8

:::wording

[simd.creation] template<class T, class... Abis> constexpr <del>vec<T,</del> <ins>resize_t<(basic_vec<T, Abis>::size() + ...), basic_vec<T, Abis...[0]></ins>> cat(const basic_vec<T, Abis>&... xs) noexcept; template<size_t Bytes, class... Abis> constexpr <del>basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>,</del><ins>resize_t<</ins>

:::

:::wording-add

(basic_mask<Bytes, Abis>::size() + ...)<ins>, basic_mask<Bytes, Abis...[0]</ins>>> cat(const basic_mask<Bytes, Abis>&... xs) noexcept;

:::

:::wording-remove

6 <del>Constraints:</del>

:::

:::wording-remove

<del>• For the first overload vec<T, (basic_vec<T, Abis>::size() + ...)> is enabled.</del>

:::

:::wording-remove

<del>• For the second overload basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_mask<Bytes,</del> <del>Abis>::size() + ...)> is enabled.</del>

:::

######## 7

######### 3.9

:::wording

[simd.mask.overview] constexpr default_sentinel_t cend() const noexcept { return {}; } static constexpr integral_constant<simd-size-type, <del>simd</del><ins>mask</ins>-size-v<<del>integer-from<Bytes></del>, Abi>> size {}; constexpr basic_mask() noexcept = default; […]

:::

1 Every specialization of `basic_mask` is a complete type. The specialization of `basic_mask<Bytes,` `Abi>` is:

* disabled, if there is no vectorizable type `T` such that `Bytes` is equal to `sizeof(T)`,

:::wording

• otherwise, enabled, if there exists a vectorizable type T and a value N in the range [1, 64] such that Bytes is equal to sizeof(T) and Abi <del>is</del><ins>names the ABI tag type denoted by</ins> deduce-abi-t<T, N>,

:::

* otherwise, it is implementation-defined if such a specialization is enabled.

If `basic_mask<Bytes,` `Abi>` is disabled, the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment. In addition only the `value_type` and `abi_type` members are present. If `basic_mask<Bytes,` `Abi>` is enabled, `basic_mask<Bytes,` `Abi>` is trivially copyable.
