IIUC, the whole +1-1 is here so that for a valueless variant, index_type(-1)
becomes size_t(-1). I think there are cases where we could do better. For
instance, for a never valueless type, we could just return _M_index. If there
are fewer than 128 alternatives, we could use a sign extension: "return (signed
char)_M_index;". Maybe some well-placed __builtin_unreachable to specify the
range of _M_index would work as well.
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
Last reconfirmed| |2019-09-23
Ever confirmed|0 |1
--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Marc Glisse from comment #0)
> IIUC, the whole +1-1 is here so that for a valueless variant, index_type(-1)
> becomes size_t(-1).
You do understand correctly :-)
> I think there are cases where we could do better. For
> instance, for a never valueless type, we could just return _M_index. If
> there are fewer than 128 alternatives, we could use a sign extension:
> "return (signed char)_M_index;".
I think we can do that more generically. Does this look right?
And in many (most?) cases the static assert is unnecessary because we already
check something like:
static_assert(_Np < sizeof...(_Types),
"The index must be in [0, number of alternatives)");
Anywhere we test equality of index() with a value that is known to be in range,
it's OK to use index_type(-1) directly instead of extending it to size_t(-1).
(The downside would be that many more functions might need to be friends to
The relational operators need a bit more thought and I don't think we can
change the calls to index() in __do_visit without breaking the implied contract
with the _M_access functions in the "vtable".
If __index_type is a smaller type than size_t, then the result of
size_t(__index_type(-1)) is not equal to size_t(-1), but to an incorrect
value such as size_t(255) or size_t(65535). The old implementation of
variant<T...>::index() uses (size_t(__index_type(_M_index + 1)) - 1)
which is always correct, but generates suboptimal code for many common
When the __index_type is size_t or valueless variants are not possible
we can just return the value directly.
When the number of alternatives is sufficiently small the result of
converting the _M_index value to the corresponding signed type will be
either non-negative or -1. In those cases converting to the signed type
and then to size_t will either produce the correct positive value or
will sign extend -1 to (size_t)-1 as desired.
For the remaining case we keep the existing arithmetic operations to
ensure the correct result.
PR libstdc++/91788 (partial)
* include/std/variant (variant::index()): Improve codegen for cases
where conversion to size_t already works correctly.