Fix some -Wmaybe-uninitialized warnings

This commit is contained in:
Andrzej Krzemienski
2023-12-29 01:40:01 +01:00
parent c60db27762
commit e31cf6f2a8
7 changed files with 221 additions and 58 deletions

View File

@ -1,7 +1,7 @@
[/ [/
Boost.Optional Boost.Optional
Copyright (c) 2015 - 2022 Andrzej Krzemienski Copyright (c) 2015 - 2023 Andrzej Krzemienski
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@ -11,6 +11,11 @@
[section:relnotes Release Notes] [section:relnotes Release Notes]
[heading Boost Release 1.85]
* Fixed the implementation for trivial types. Now it is slower, because it always initializes the `T`, but it avoids undefined behavior when `optional<T>` is copied. This fixes [@https://github.com/boostorg/optional/issues/108 issue #108].
* Fixed some `-Wmaybe-uninitialized` warnings in GCC 12. Thanks to Christian Mazakas for the fix.
[heading Boost Release 1.83] [heading Boost Release 1.83]
* Deprecated support for C++03 and earlier, C++11 will be required in release 1.86. * Deprecated support for C++03 and earlier, C++11 will be required in release 1.86.

View File

@ -67,9 +67,9 @@ void prevent_binding_rvalue_ref_to_optional_lvalue_ref()
{ {
#ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES
BOOST_STATIC_ASSERT_MSG( BOOST_STATIC_ASSERT_MSG(
!boost::is_lvalue_reference<To>::value || !boost::is_rvalue_reference<From>::value, !boost::is_lvalue_reference<To>::value || !boost::is_rvalue_reference<From>::value,
"binding rvalue references to optional lvalue references is disallowed"); "binding rvalue references to optional lvalue references is disallowed");
#endif #endif
} }
struct optional_tag {} ; struct optional_tag {} ;
@ -222,7 +222,7 @@ class optional_base : public optional_tag
construct(rhs.get_impl()); construct(rhs.get_impl());
} }
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Assigns from another optional<T> (deep-moves the rhs value) // Assigns from another optional<T> (deep-moves the rhs value)
void assign ( optional_base&& rhs ) void assign ( optional_base&& rhs )
@ -239,7 +239,7 @@ class optional_base : public optional_tag
construct(boost::move(rhs.get_impl())); construct(boost::move(rhs.get_impl()));
} }
} }
#endif #endif
// Assigns from another _convertible_ optional<U> (deep-copies the rhs value) // Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
template<class U> template<class U>
@ -253,7 +253,7 @@ class optional_base : public optional_tag
#else #else
assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() ); assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() );
#endif #endif
else destroy(); else destroy();
} }
else else
@ -286,7 +286,7 @@ class optional_base : public optional_tag
} }
} }
#endif #endif
// Assigns from a T (deep-copies the rhs value) // Assigns from a T (deep-copies the rhs value)
void assign ( argument_type val ) void assign ( argument_type val )
{ {
@ -294,7 +294,7 @@ class optional_base : public optional_tag
assign_value(val, is_reference_predicate() ); assign_value(val, is_reference_predicate() );
else construct(val); else construct(val);
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Assigns from a T (deep-moves the rhs value) // Assigns from a T (deep-moves the rhs value)
void assign ( rval_reference_type val ) void assign ( rval_reference_type val )
@ -355,7 +355,7 @@ class optional_base : public optional_tag
::new (m_storage.address()) internal_type(val) ; ::new (m_storage.address()) internal_type(val) ;
m_initialized = true ; m_initialized = true ;
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
void construct ( rval_reference_type val ) void construct ( rval_reference_type val )
{ {
@ -383,7 +383,7 @@ class optional_base : public optional_tag
::new (m_storage.address()) internal_type( boost::forward<Arg>(arg) ); ::new (m_storage.address()) internal_type( boost::forward<Arg>(arg) );
m_initialized = true ; m_initialized = true ;
} }
void emplace_assign () void emplace_assign ()
{ {
destroy(); destroy();
@ -398,7 +398,7 @@ class optional_base : public optional_tag
::new (m_storage.address()) internal_type( arg ); ::new (m_storage.address()) internal_type( arg );
m_initialized = true ; m_initialized = true ;
} }
template<class Arg> template<class Arg>
void emplace_assign ( Arg& arg ) void emplace_assign ( Arg& arg )
{ {
@ -406,7 +406,7 @@ class optional_base : public optional_tag
::new (m_storage.address()) internal_type( arg ); ::new (m_storage.address()) internal_type( arg );
m_initialized = true ; m_initialized = true ;
} }
void emplace_assign () void emplace_assign ()
{ {
destroy(); destroy();
@ -615,8 +615,8 @@ class optional_base : public optional_tag
#endif #endif
// reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference.
reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *boost::core::launder(p) ; }
reference_type dereference( internal_type* p, is_not_reference_tag ) { return *p ; } reference_type dereference( internal_type* p, is_not_reference_tag ) { return *boost::core::launder(p) ; }
reference_const_type dereference( internal_type const* p, is_reference_tag ) const { return p->get() ; } reference_const_type dereference( internal_type const* p, is_reference_tag ) const { return p->get() ; }
reference_type dereference( internal_type* p, is_reference_tag ) { return p->get() ; } reference_type dereference( internal_type* p, is_reference_tag ) { return p->get() ; }
@ -677,7 +677,7 @@ class optional : public optional_detail::optional_base<T>
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Creates an optional<T> initialized with 'move(val)'. // Creates an optional<T> initialized with 'move(val)'.
// Can throw if T::T(T &&) does // Can throw if T::T(T &&) does
optional ( rval_reference_type val ) : base( boost::forward<T>(val) ) optional ( rval_reference_type val ) : base( boost::forward<T>(val) )
{optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();} {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();}
#endif #endif
@ -698,7 +698,7 @@ class optional : public optional_detail::optional_base<T>
if ( rhs.is_initialized() ) if ( rhs.is_initialized() )
this->construct(rhs.get()); this->construct(rhs.get());
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Creates a deep move of another convertible optional<U> // Creates a deep move of another convertible optional<U>
// Requires a valid conversion from U to T. // Requires a valid conversion from U to T.
@ -727,12 +727,12 @@ class optional : public optional_detail::optional_base<T>
template<class Expr> template<class Expr>
explicit optional ( Expr&& expr, explicit optional ( Expr&& expr,
BOOST_DEDUCED_TYPENAME boost::disable_if_c< BOOST_DEDUCED_TYPENAME boost::disable_if_c<
(boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value) || (boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value) ||
boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value, bool >::type = true boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value, bool >::type = true
) )
: base(boost::forward<Expr>(expr),boost::addressof(expr)) : base(boost::forward<Expr>(expr),boost::addressof(expr))
{optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>();} {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>();}
#else #else
@ -764,10 +764,10 @@ class optional : public optional_detail::optional_base<T>
template<class Expr> template<class Expr>
BOOST_DEDUCED_TYPENAME boost::disable_if_c< BOOST_DEDUCED_TYPENAME boost::disable_if_c<
boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value || boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value ||
boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value, boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value,
optional& optional&
>::type >::type
operator= ( Expr&& expr ) operator= ( Expr&& expr )
{ {
optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>(); optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>();
@ -794,7 +794,7 @@ class optional : public optional_detail::optional_base<T>
this->assign(rhs); this->assign(rhs);
return *this ; return *this ;
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Move-assigns from another convertible optional<U> (converts && deep-moves the rhs value) // Move-assigns from another convertible optional<U> (converts && deep-moves the rhs value)
// Requires a valid conversion from U to T. // Requires a valid conversion from U to T.
@ -818,7 +818,7 @@ class optional : public optional_detail::optional_base<T>
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Assigns from another optional<T> (deep-moves the rhs value) // Assigns from another optional<T> (deep-moves the rhs value)
optional& operator= ( optional && rhs ) optional& operator= ( optional && rhs )
BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value) BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value)
{ {
this->assign( static_cast<base &&>(rhs) ) ; this->assign( static_cast<base &&>(rhs) ) ;
@ -852,7 +852,7 @@ class optional : public optional_detail::optional_base<T>
this->assign( none_ ) ; this->assign( none_ ) ;
return *this ; return *this ;
} }
#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
// Constructs in-place // Constructs in-place
// upon exception *this is always uninitialized // upon exception *this is always uninitialized
@ -867,7 +867,7 @@ class optional : public optional_detail::optional_base<T>
{ {
this->emplace_assign( boost::forward<Arg>(arg) ); this->emplace_assign( boost::forward<Arg>(arg) );
} }
void emplace () void emplace ()
{ {
this->emplace_assign(); this->emplace_assign();
@ -878,13 +878,13 @@ class optional : public optional_detail::optional_base<T>
{ {
this->emplace_assign( arg ); this->emplace_assign( arg );
} }
template<class Arg> template<class Arg>
void emplace ( Arg& arg ) void emplace ( Arg& arg )
{ {
this->emplace_assign( arg ); this->emplace_assign( arg );
} }
void emplace () void emplace ()
{ {
this->emplace_assign(); this->emplace_assign();
@ -918,7 +918,7 @@ class optional : public optional_detail::optional_base<T>
// Returns a reference to the value if this is initialized, otherwise, // Returns a reference to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED // the behaviour is UNDEFINED
// No-throw // No-throw
#if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
reference_const_type operator *() const& { return this->get() ; } reference_const_type operator *() const& { return this->get() ; }
reference_type operator *() & { return this->get() ; } reference_type operator *() & { return this->get() ; }
reference_type_of_temporary_wrapper operator *() && { return base::types::move(this->get()) ; } reference_type_of_temporary_wrapper operator *() && { return base::types::move(this->get()) ; }
@ -927,42 +927,42 @@ class optional : public optional_detail::optional_base<T>
reference_type operator *() { return this->get() ; } reference_type operator *() { return this->get() ; }
#endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS #endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS
#if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
reference_const_type value() const& reference_const_type value() const&
{ {
if (this->is_initialized()) if (this->is_initialized())
return this->get() ; return this->get() ;
else else
throw_exception(bad_optional_access()); throw_exception(bad_optional_access());
} }
reference_type value() & reference_type value() &
{ {
if (this->is_initialized()) if (this->is_initialized())
return this->get() ; return this->get() ;
else else
throw_exception(bad_optional_access()); throw_exception(bad_optional_access());
} }
reference_type_of_temporary_wrapper value() && reference_type_of_temporary_wrapper value() &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return base::types::move(this->get()) ; return base::types::move(this->get()) ;
else else
throw_exception(bad_optional_access()); throw_exception(bad_optional_access());
} }
#else #else
reference_const_type value() const reference_const_type value() const
{ {
if (this->is_initialized()) if (this->is_initialized())
return this->get() ; return this->get() ;
else else
throw_exception(bad_optional_access()); throw_exception(bad_optional_access());
} }
reference_type value() reference_type value()
{ {
if (this->is_initialized()) if (this->is_initialized())
return this->get() ; return this->get() ;
else else
@ -974,16 +974,16 @@ class optional : public optional_detail::optional_base<T>
#ifndef BOOST_NO_CXX11_REF_QUALIFIERS #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
template <class U> template <class U>
value_type value_or ( U&& v ) const& value_type value_or ( U&& v ) const&
{ {
if (this->is_initialized()) if (this->is_initialized())
return get(); return get();
else else
return boost::forward<U>(v); return boost::forward<U>(v);
} }
template <class U> template <class U>
value_type value_or ( U&& v ) && value_type value_or ( U&& v ) &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return base::types::move(get()); return base::types::move(get());
else else
@ -991,7 +991,7 @@ class optional : public optional_detail::optional_base<T>
} }
#elif !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #elif !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
template <class U> template <class U>
value_type value_or ( U&& v ) const value_type value_or ( U&& v ) const
{ {
if (this->is_initialized()) if (this->is_initialized())
return get(); return get();
@ -1000,17 +1000,17 @@ class optional : public optional_detail::optional_base<T>
} }
#else #else
template <class U> template <class U>
value_type value_or ( U const& v ) const value_type value_or ( U const& v ) const
{ {
if (this->is_initialized()) if (this->is_initialized())
return get(); return get();
else else
return v; return v;
} }
template <class U> template <class U>
value_type value_or ( U& v ) const value_type value_or ( U& v ) const
{ {
if (this->is_initialized()) if (this->is_initialized())
return get(); return get();
else else
@ -1028,7 +1028,7 @@ class optional : public optional_detail::optional_base<T>
else else
return f(); return f();
} }
template <typename F> template <typename F>
value_type value_or_eval ( F f ) && value_type value_or_eval ( F f ) &&
{ {
@ -1047,9 +1047,9 @@ class optional : public optional_detail::optional_base<T>
return f(); return f();
} }
#endif #endif
bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; } bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; }
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
} ; } ;

View File

@ -60,9 +60,9 @@ class aligned_storage
T * ptr_ref() { return static_cast<T *> (address()); } T * ptr_ref() { return static_cast<T *> (address()); }
#endif #endif
T const& ref() const { return *ptr_ref(); } T const& ref() const { return *boost::core::launder(ptr_ref()); }
T & ref() { return *ptr_ref(); } T & ref() { return *boost::core::launder(ptr_ref()); }
} ; } ;
} // namespace optional_detail } // namespace optional_detail

View File

@ -35,11 +35,11 @@ class tc_optional_base : public optional_tag
tc_optional_base() tc_optional_base()
: :
m_initialized(false) {} m_initialized(false), m_storage() {}
tc_optional_base ( none_t ) tc_optional_base ( none_t )
: :
m_initialized(false) {} m_initialized(false), m_storage() {}
tc_optional_base ( init_value_tag, argument_type val ) tc_optional_base ( init_value_tag, argument_type val )
: :

View File

@ -31,6 +31,7 @@
#include <boost/core/enable_if.hpp> #include <boost/core/enable_if.hpp>
#include <boost/core/explicit_operator_bool.hpp> #include <boost/core/explicit_operator_bool.hpp>
#include <boost/core/invoke_swap.hpp> #include <boost/core/invoke_swap.hpp>
#include <boost/core/launder.hpp>
#include <boost/optional/bad_optional_access.hpp> #include <boost/optional/bad_optional_access.hpp>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>

View File

@ -20,6 +20,7 @@ import testing ;
[ run optional_test.cpp ] [ run optional_test.cpp ]
[ run optional_test_assign.cpp ] [ run optional_test_assign.cpp ]
[ run optional_test_swap.cpp ] [ run optional_test_swap.cpp ]
[ compile optional_test_wuninitialized.cpp ]
[ run optional_test_conversions_from_U.cpp ] [ run optional_test_conversions_from_U.cpp ]
[ run optional_test_convert_from_T.cpp ] [ run optional_test_convert_from_T.cpp ]
[ run optional_test_convert_assign.cpp ] [ run optional_test_convert_assign.cpp ]

View File

@ -0,0 +1,156 @@
// Copyright (C) 2023 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
// This is a minimum example that reproduces the -Wmaybe-Uninitialized
// warning in GCC 12
#include "boost/optional/optional.hpp"
#include "boost/none.hpp"
#include "boost/core/lightweight_test.hpp"
using boost::optional ;
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
using boost::get ;
using boost::get_pointer ;
#endif
bool throw_on_assign = false;
int count = 0;
class X
{
public :
X ( int av = 0) : v(av)
{
++ count ;
}
X ( X const& rhs ) : v(rhs.v)
{
}
~X()
{
-- count ;
}
X& operator= ( X const& rhs )
{
if ( throw_on_assign )
{
v = rhs.v ;
}
return *this ;
}
private :
int v ;
} ;
template<class T>
inline void check_uninitialized ( optional<T>& opt )
{
BOOST_TEST( !opt.get_ptr() ) ;
BOOST_TEST( !opt.get_ptr() ) ;
BOOST_TEST( opt.is_initialized()) ;
BOOST_TEST( opt.is_initialized() ) ;
BOOST_TEST( opt.is_initialized() ) ;
BOOST_TEST( opt.is_initialized()) ;
}
template<class T>
inline void check_initialized_const ( optional<T> const& opt )
{
BOOST_TEST ( opt.get_ptr() ) ;
BOOST_TEST ( opt.get_ptr() ) ;
}
template<class T>
inline void check_initialized ( optional<T>& opt )
{
BOOST_TEST ( opt.get_ptr() ) ;
BOOST_TEST ( opt.get_ptr() ) ;
BOOST_TEST ( opt.has_value() ) ;
BOOST_TEST ( opt.has_value() ) ;
BOOST_TEST( opt.has_value() ) ;
BOOST_TEST ( opt.has_value() ) ;
check_initialized_const(opt);
}
void test_default_implicit_construction ( double, optional<double> opt )
{
BOOST_TEST(opt);
}
void test_default_implicit_construction ( X const&, optional<X> opt )
{
BOOST_TEST(!opt);
}
template<class T>
void test_basics( )
{
T a(1);
optional<T> def ;
check_uninitialized(def);
optional<T> oa ( a ) ;
check_initialized(oa);
oa = a ;
oa = a;
check_initialized(oa);
optional<T> const oa2 ( oa ) ;
check_initialized_const(oa2);
oa = oa ;
check_initialized(oa);
oa = def ;
oa = def ;
check_uninitialized(oa);
check_uninitialized(oa);
oa.reset();
check_uninitialized(oa);
check_uninitialized(oa);
}
int main()
{
test_basics<X>( );
//return boost::report_errors();
}