https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105050
Patrick Palka <ppalka at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |ppalka at gcc dot gnu.org --- Comment #2 from Patrick Palka <ppalka at gcc dot gnu.org> --- Created attachment 52687 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52687&action=edit elaborate non-constexpr if stmt branches Seems we issued this error because we determined that neither branch of the first 'if' is a valid constexpr body (since each branch will end up calling a non-constexpr function), and so the 'if' is a non-constant "expression" regardless of control flow, which makes 'swap' non-constexpr overall. The attached diff makes us elaborate why neither branch of an 'if' is non-constant in this case, similar to how we diagnose disjunctions during satisfaction. For this testcase we'd now get: 105050.C:43:24: error: non-constant condition for static assertion 43 | static_assert(test_swap()); | ~~~~~~~~~^~ 105050.C:43:24: in ‘constexpr’ expansion of ‘test_swap()’ 105050.C:38:10: error: ‘constexpr void expected<_Tp>::swap(expected<_Tp>&) [with _Tp = int]’ called in a constant expression 38 | e1.swap(e2); | ~~~~~~~^~~~ 105050.C:13:5: note: ‘constexpr void expected<_Tp>::swap(expected<_Tp>&) [with _Tp = int]’ is not usable as a ‘constexpr’ function because: 13 | swap(expected& __x) | ^~~~ 105050.C:15:7: note: neither branch of ‘if’ is a valid ‘constexpr’ body because: 15 | if (this->has_value()) | ^~ 105050.C:17:9: note: neither branch of ‘if’ is a valid ‘constexpr’ body because: 17 | if (__x.has_value()) | ^~ 105050.C:18:28: error: call to non-‘constexpr’ function ‘void expected<_Tp>::_M_swap_val(expected<_Tp>&) [with _Tp = int]’ 18 | this->_M_swap_val(__x); | ~~~~~~~~~~~~~~~~~^~~~~ 105050.C:4:10: note: ‘void expected<_Tp>::_M_swap_val(expected<_Tp>&) [with _Tp = int]’ declared here 4 | void _M_swap_val(expected&) { } | ^~~~~~~~~~~ 105050.C:20:33: error: call to non-‘constexpr’ function ‘void expected<_Tp>::_M_swap_val_unex(expected<_Tp>&) [with _Tp = int]’ 20 | this->_M_swap_val_unex(__x); | ~~~~~~~~~~~~~~~~~~~~~~^~~~~ 105050.C:8:10: note: ‘void expected<_Tp>::_M_swap_val_unex(expected<_Tp>&) [with _Tp = int]’ declared here 8 | void _M_swap_val_unex(expected&) { } | ^~~~~~~~~~~~~~~~ 105050.C:24:9: note: neither branch of ‘if’ is a valid ‘constexpr’ body because: 24 | if (__x.has_value()) | ^~ 105050.C:25:31: error: call to non-‘constexpr’ function ‘void expected<_Tp>::_M_swap_val_unex(expected<_Tp>&) [with _Tp = int]’ 25 | __x._M_swap_val_unex(*this); | ~~~~~~~~~~~~~~~~~~~~^~~~~~~ 105050.C:8:10: note: ‘void expected<_Tp>::_M_swap_val_unex(expected<_Tp>&) [with _Tp = int]’ declared here 8 | void _M_swap_val_unex(expected&) { } | ^~~~~~~~~~~~~~~~ 105050.C:27:29: error: call to non-‘constexpr’ function ‘void expected<_Tp>::_M_swap_unex(expected<_Tp>&) [with _Tp = int]’ 27 | this->_M_swap_unex(__x); | ~~~~~~~~~~~~~~~~~~^~~~~ 105050.C:6:10: note: ‘void expected<_Tp>::_M_swap_unex(expected<_Tp>&) [with _Tp = int]’ declared here 6 | void _M_swap_unex(expected&) { } | ^~~~~~~~~~~~ We definitely should clarify the initial error, but I'm not sure if we want the recursive elaboration, might be too noisy..