<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/68552>68552</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++] `std::expected` "has value" flag getting clobbered unexpectedly
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
jiixyj
</td>
</tr>
</table>
<pre>
In some situations it seems that the "has value" flag of a `std::expected` gets overwritten when the value is constructed. Example:
```c++
#undef NDEBUG
#include <cassert>
#include <expected>
#include <optional>
std::expected<std::optional<int>, long> f1()
{
return 0;
}
std::expected<std::optional<int>, int> f2()
{
return f1().transform_error([](auto) { return 0; });
}
int main()
{
auto r = f2();
assert(r.has_value());
```
Godbolt: <https://godbolt.org/z/nbcPr9e5f>
I would expect that the `assert` is not triggered, but it is. I'm testing with commit d408770c007896d84c3e8d80351bc0d4aeb4e229.
I strongly suspect code like this, i.e. where the call to `std::construct_at` happens _after_ setting the "has value" flag:
https://github.com/llvm/llvm-project/blob/7cc1bfaf371c4a816cf4e62fe31d8515bf8f6fbd/libcxx/include/__expected/expected.h#L252-L258
In the above example, `__has_val_` (a `bool`) and `__union_.__val_` (the `std::optional<int>`) overlap. I think `std::construct_at` is allowed to overwrite `__has_val_` in this case by the language rules as the `std::construct_at` has no idea that the `__has_val_` is there. It just assumes it has full 8 bytes to work with to construct the `std::optional<int>`.
The data layout of the problematic `std::expected<std::optional<int>, int>` looks like this:
```
+-- optional "has value" flag
| +--+--padding
/---int---\ | | |
00 00 00 00 01 00 00 00
|
|
+- expected "has value" flag
```
The `expected`'s "has value" flag reuses one byte of the padding. It should be "1" in this case but is "0".
Suggested fix: move all assignments to the "has value" flag _after_ the `std::construct_at` calls like this:
```c++
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
{
std::construct_at(std::addressof(__union_.__val_), std::forward<_Args>(__args)...);
__has_val = true;
}
```
I wonder if this analysis is correct or if I'm missing some subtleties with `std::construct_at`.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykV9tu47wRfhr6ZmBBpqzThS8SJ_4bYNsu2u21QIkjibsU6ZJUYvfpC1KWT-vsv0UNQVEozvCbmW8OYtaKTiFuSPpM0pcFG12vzea7EIfj90Wt-XHzpsDqAcEKNzIntLIgHFjEwYLrmQPXIxBKe2bhnckRCaXQStaBboEByWLrOEmeSPKEhz02DjnJYujQWdDvaD6McA4VfPSogq6gBISFRivrzOglIng9sGEv0SuKX0g837N4uhpCn_01rdJkVBxb-NvL6_O__jgvCtXIkSOQZNswa9E4krzeqLvZc4Z73nTzWu-9N5i80_Gztcn2vHaR2QoVTqdbkFp1JHmFdkVoQWh50pafrAEAMOhGoyAmyWxi_vL_HTo9QUv_7MwZVeQMU7bVZqjQGG38aiANoQUbnSa0BJI_X0MFj5KWn4EWysHAhHqMwOsEAyR5uYBMruCdAkgLE_XMVifqhW3XR84EuT74D81rLR1Jnnwce-f21nuK7gjdddO7SJuO0N1_CN2puvlqSkzbu0C_wYceJYfJ5Ve5kMUnbFnsaay0A2dE16FB7l1fj86nkLARvBGaD-DQOqE6-BCuh0YPg3DA13GR53ETx3lRZrxYNwkWvIiTdFU3MV8zrNdIaRndQrLOaNXJI9jRBliN5ghS_EBwvbAh8hFGPtsMBrgNkxKcvknUc-ZVLFjRs_0elYWKtQ5NBRZdAPxZ6t9l6Z2HhevHOmr0QOhOyvf5z3Jv9HdsHKG7Wuqa0F3eNKu6ZW2Sr5o1K1ZZ064xoy0mK16kq7RuizZra-4ViLo5HAjdnRKU0F1VnZOB7ubHqCc0-UJTuvxC0-LGd1P1YbV-R8BTtaFb75eqOjGs8s7wfPertdbSE4uWwBSf9o1KaFVF1fXmEyd-kY6TEl8MJdtH8OZDpX78MiLCApNSfyD3sZvrKP6MVqgQeGiYRaiPwUbJVDeyDsGMEi0wC_cYfyaA5zEIjuyG6HdnBUUGI3hz8H20zifpOGDoGF5FO0oJBdRHh9bj_tDmx8R6py_l_ic0jzx2w_tvPQJnjoFkRz0633m8jr3RtcSBOdE87kO_VyS9aVLrH_Yqjz5pQ6fyROjzcgmzyscpci5k84_k20kw3PaMc6G6ufHslsulUG65XJJ0G7bOIv427YpjuFyr8_OMad4Gt79P1-nzEmZP_cKEhxX22xTBq4ZPaG4fjwkGR4sWtMJAjHPwJgcELtk-VNo6VJuVl7yltS-oQXtMKL1hxj_HrkPrLWjFwRf8wae3L3nT6DOgcoGKn04xc837sxTxdfQ3GHIzqAA4HPaSuWkmkczaKIqgejKdPXebqRf_exTGJ5KtzgeLWmL1TpJt9W3v2RrEoii6SFZf3p63X79Wf3l7ea12__j7X6un57cp0fCwNz68UjTCwaVSFkJVe8karNxZJ6EZoVlAVrHwf3mBpjQeGtz7TixspbTrjf74PZB-YggtwbctVJ3rUSGfVd8MI4_dTovzOuPcoLW6JbS4r8N-JNheVLTafDDjs__saC9zssxjuxs1zlUuTCPOjHh5fZlpHuWBnxEURwOinfjKFJNHK-w03xrjW7QOr6dRYBDW-s46jdxj7SQ6gXYqkr-gX7Tgm4SXSckWuFllZVbQPEuLRb_h6zRJiyRbUVrGnJdpwTPe5Pk6K2nWlMVCbGhMk1Ucl3Eax2kelXm-Soq0xpyyOmlSso5xYEJGvkv7wWghrB1xkxVpSheS1Sht-ICg1LfhE8Ep9R8UZhNaez12lqxjKayzFzVOOBk-Pa7E0pdPPxkepmd3GkUaqevaT1gwqllIHhejkZv_efwI5llCd8HC_wYAAP__pu7xJA">