https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112480
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Last reconfirmed| |2023-11-10
Status|UNCONFIRMED |NEW
Ever confirmed|0 |1
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I feel like the compiler should be able to do that anyway.
_M_destroy() is:
_M_engaged = false;
_M_payload._M_value.~_Stored_type();
For a trivially destructible type the second statement is a no-op, so we have:
if (_M_engaged)
_M_engaged = false;
The compiler should turn that into _M_engaged = false.
The suggested change is wrong though, because it runs the trivial destructor
unconditionally, even if there is no object within its lifetime. Clang will
diagnose that during constant evaluation (although gcc doesn't, which I think
is a known bug).
For example:
#include <optional>
constexpr bool f()
{
std::optional<int> opt(1);
opt = std::nullopt;
opt = std::nullopt;
return true;
}
static_assert(f());
opt.cc:10:15: error: static assertion expression is not an integral constant
expression
static_assert(f());
^~~
/home/jwakely/gcc/latest/lib/gcc/x86_64-pc-linux-gnu/14.0.0/../../../../include/c++/14.0.0/optional:282:2:
note: destruction of member '_M_value' of union with active member '_M_empty'
is not allowed in a constant expression
_M_payload._M_value.~_Stored_type();
^
/home/jwakely/gcc/latest/lib/gcc/x86_64-pc-linux-gnu/14.0.0/../../../../include/c++/14.0.0/optional:313:4:
note: in call to '&opt._Optional_base::_M_payload->_M_destroy()'
_M_destroy();
^
/home/jwakely/gcc/latest/lib/gcc/x86_64-pc-linux-gnu/14.0.0/../../../../include/c++/14.0.0/optional:465:45:
note: in call to '&opt._Optional_base::_M_payload->_M_reset()'
{ static_cast<_Dp*>(this)->_M_payload._M_reset(); }
^
/home/jwakely/gcc/latest/lib/gcc/x86_64-pc-linux-gnu/14.0.0/../../../../include/c++/14.0.0/optional:831:8:
note: in call to '&opt->_M_reset()'
this->_M_reset();
^
opt.cc:6:7: note: in call to '&opt->operator=({})'
opt = std::nullopt;
^
opt.cc:10:15: note: in call to 'f()'
static_assert(f());
^
1 error generated.
We could do:
constexpr void
_M_reset() noexcept
{
if constexpr (is_trivially_destructible_v<_Tp>)
{
if (!std::__is_constant_evaluated())
{
this->_M_engaged = false;
return;
}
}
if (this->_M_engaged)
_M_destroy();
}
Yuck