https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109448
Bug ID: 109448 Summary: _M_exception_object’ may be used uninitialized [-Werror=maybe-uninitialized] Product: gcc Version: 12.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: jincikang at gmail dot com Target Milestone: --- ```cpp // test.cpp #include <variant> #include <vector> #include <cassert> #include <cstdint> #include <exception> #include <atomic> template <typename T> class Try { public: Try() = default; ~Try() = default; Try(Try<T>&& other) = default; Try& operator=(Try<T>&& other) = default; Try& operator=(std::exception_ptr error) { if (std::holds_alternative<std::exception_ptr>(_value) && std::get<std::exception_ptr>(_value) == error) { return *this; } _value.template emplace<std::exception_ptr>(error); return *this; } template <class... U> Try(U&&... value) requires std::is_constructible_v<T, U...> : _value(std::in_place_type<T>, std::forward<U>(value)...) {} Try(std::exception_ptr error) : _value(error) {} private: Try(const Try&) = delete; Try& operator=(const Try&) = delete; public: constexpr bool available() const noexcept { return !std::holds_alternative<std::monostate>(_value); } constexpr bool hasError() const noexcept { return std::holds_alternative<std::exception_ptr>(_value); } const T& value() const& { checkHasTry(); return std::get<T>(_value); } T& value() & { checkHasTry(); return std::get<T>(_value); } T&& value() && { checkHasTry(); return std::move(std::get<T>(_value)); } const T&& value() const&& { checkHasTry(); return std::move(std::get<T>(_value)); } template <class... Args> T& emplace(Args&&... args) { return _value.template emplace<T>(std::forward<Args>(args)...); } void setException(std::exception_ptr error) { if (std::holds_alternative<std::exception_ptr>(_value) && std::get<std::exception_ptr>(_value) == error) { return; } _value.template emplace<std::exception_ptr>(error); } std::exception_ptr getException() const { logicAssert(std::holds_alternative<std::exception_ptr>(_value), "Try object do not has on error"); return std::get<std::exception_ptr>(_value); } private: inline void checkHasTry() const { if (std::holds_alternative<T>(_value)) { return; } else if (std::holds_alternative<std::exception_ptr>(_value)) { std::rethrow_exception(std::get<std::exception_ptr>(_value)); } else if (std::holds_alternative<std::monostate>(_value)) { throw std::logic_error("Try object is empty"); } else { assert(false); } } private: std::variant<std::monostate, T, std::exception_ptr> _value; }; namespace detail { enum class State : uint8_t { START = 0, ONLY_RESULT = 1 << 0, ONLY_CONTINUATION = 1 << 1, DONE = 1 << 5, }; constexpr State operator|(State lhs, State rhs) { return State((uint8_t)lhs | (uint8_t)rhs); } constexpr State operator&(State lhs, State rhs) { return State((uint8_t)lhs & (uint8_t)rhs); } } // namespace detail template <class T> struct TestPromise { public: TestPromise() : _state(detail::State::START) {} ~TestPromise() {} public: bool hasResult() const noexcept { constexpr auto allow = detail::State::DONE | detail::State::ONLY_RESULT; auto state = _state.load(std::memory_order_acquire); return (state & allow) != detail::State(); } void setResult(Try<T>&& value) { assert(!hasResult()); _try_value = std::move(value); } std::atomic<detail::State> _state; Try<T> _try_value; }; struct Empty {}; int main() { int n = 10; std::vector<TestPromise<Empty>> promise(n); for (int i = 0; i < n; ++i) { promise[i].setResult(Empty()); } } ``` # no problem $ g++-11 -std=c++20 -Wall -Werror -O3 test.cpp # no problem $ g++ -std=c++20 -Wall -Werror -O0 test.cpp # Error:‘*(std::__exception_ptr::exception_ptr*)((char*)&<unnamed> + offsetof(Try<Empty>,Try<Empty>::_value.std::variant<std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Variant_base<std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Move_assign_base<false, std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Copy_assign_base<false, std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Move_ctor_base<false, std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Copy_ctor_base<false, std::monostate, Empty, std::__exception_ptr::exception_ptr>::<unnamed>.std::__detail::__variant::_Variant_storage<false, std::monostate, Empty, std::__exception_ptr::exception_ptr>::_M_u)).std::__exception_ptr::exception_ptr::_M_exception_object’ may be used uninitialized [-Werror=maybe-uninitialized] $ g++ -std=c++20 -Wall -Werror -O3 test.cpp