Compare commits

..

9 Commits

Author SHA1 Message Date
Andrzej Krzemienski 8bc4a16933 Merge branch 'develop' 2026-02-27 14:04:53 +01:00
Andrzej Krzemienski ecb241a919 tests: remove all -Wall warnings 2026-02-25 22:49:18 +01:00
Andrzej Krzemieński ff710d113c Merge pull request #145 from alandefreitas/fix/maybe-uninitialized-pragma
fix: add -Wmaybe-uninitialized pragma to union storage constructors
2026-02-25 17:42:43 +01:00
Alan de Freitas 88e2378c8a Add -Wmaybe-uninitialized pragma to union storage constructors
GCC 7+ produces false-positive -Wmaybe-uninitialized warnings at -O3
when deeply inlining through union constructors that initialize one
member while another (dummy_) exists. This is the same class of false
positive addressed in boostorg/variant2#55.

The pragmas are placed around the forwarding constructors in both
constexpr_union_storage_t and fallback_union_storage_t.
2026-02-24 12:11:51 -05:00
Andrzej Krzemienski aaabe89a69 Merge branch 'develop' 2026-02-20 16:16:26 +01:00
Andrzej Krzemienski fa52755c88 docs update 2026-02-20 16:14:53 +01:00
Andrzej Krzemienski 76be15bfeb update release notes 2026-02-18 21:10:45 +01:00
Andrzej Krzemienski 5d8e50a9aa add conversion from optional T to optional ref T 2026-02-18 16:52:52 +01:00
Andrzej Krzemienski 37513ddbbf remove traces of Boost.Assert 2026-02-18 13:23:48 +01:00
12 changed files with 243 additions and 21 deletions
+12
View File
@@ -50,6 +50,18 @@ In the general case, the internal representation is something equivalent to:
alignas(T) char _value [sizeof(T)];
};
or:
template <typename T>
class Optional
{
bool _has_value = false;
union {
T _value;
DummyType _non_value;
};
};
Next, because we need to pass around these "optional" `int`s as normal `int`s,
like returning them from functions, when copying, we need to copy `_has_value`,
which indicates whether we have the value or not, and, if we do have value, and
+3
View File
@@ -197,6 +197,9 @@ They are empty, trivially copyable classes with disabled default constructor.
template<class F> constexpr auto flat_map( F f ) & -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
template<class F> constexpr auto flat_map( F f ) && -> ``['see below]``; ``[link reference_optional_flat_map_move __GO_TO__]``
constexpr operator optional<T&>() & noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
constexpr operator optional<T const&>() const& noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]``
T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]``
+22
View File
@@ -47,8 +47,10 @@ the parameter.
* [*Example:]
``
#include <boost/none.hpp>
optional<T> n(none) ;
assert ( !n ) ;
assert ( n == none ) ;
``
__SPACE__
@@ -751,6 +753,26 @@ __SPACE__
__SPACE__
[#reference_optional_conversion_to_ref]
[: `constexpr optional<T>::operator optional<T&>() & noexcept ;`]
* [*Returns:] If `*this` contains a value `optional<T&>(**this)`, otherwise `optional<T&>()`.
[: `constexpr optional<T>::operator optional<T const&>() const& noexcept ;`]
* [*Returns:] If `*this` contains a value `optional<T const&>(**this)`, otherwise `optional<T&>()`.
* [*Example:]
``
const optional<int> oi = 1;
optional<const int&> ri = oi;
``
__SPACE__
[#reference_optional_get_value_or_value]
[: `T const& optional<T>::get_value_or( T const& default) const ;`]
-1
View File
@@ -72,7 +72,6 @@ The implementation uses the following other Boost modules:
# assert
# config
# core
# static_assert
# throw_exception
# type_traits
+1 -2
View File
@@ -56,9 +56,8 @@
void test(vector<optional<T>> rng, T val) {
std::ranges::find(rng, make_optional(val));
}
```] [The same code for `std::optional` compiles but is ['undefined behavior] when `T` is itself an `optional`. ] ]
```] [For `std::optional`, code without `make_optional()` compiles but is ['undefined behavior] when `T` is itself an `optional`. ] ]
]
[endsect][/ std_comp]
+22 -1
View File
@@ -26,7 +26,7 @@
* In C++17 all constructors (including copy and move) become core constant expressions
for co-operating types.
This addresses [@https://github.com/boostorg/optional/issues/143 issue #143].
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
`swap`. Hardly anyone knows about this mechanism and it was never documented.
@@ -37,10 +37,31 @@
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
does not create a temporary `T`.
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
* *Warning.* In the future releases we intend to introduce the range interface
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
This may affect the overload resolution in programs that make decisions based
on predicates such as `std::ranges::range`. For instance, the following code
will start behaving differently:
```
template <typename T>
void serialize(T const& v)
{
if constexpr (std::ranges::range<T>)
serialize_as_range(v);
else if constexpr (custom::is_optional_like<T>)
serialize_as_optional(v);
else
serialize_as_value(v);
}
```
[heading Boost Release 1.87]
* *Breaking change.* Dropped support for C++03. C++11 is now the required minimum; at least some C++11 features.
@@ -74,9 +74,20 @@ union constexpr_union_storage_t
constexpr constexpr_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr constexpr_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
//~constexpr_union_storage_t() = default; // No need to destroy a trivially-destructible type
};
@@ -88,9 +99,20 @@ union fallback_union_storage_t
constexpr fallback_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr fallback_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
~fallback_union_storage_t(){} // My owner will destroy the `T` if needed.
// Cannot default in a union with nontrivial `T`.
};
@@ -379,6 +401,20 @@ namespace boost {
: storage(in_place_init, optional_detail::forward_<Args>(args)...)
{}
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
{
return this->has_value() ? optional<T&>(**this) : optional<T&>();
}
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
{
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
}
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
BOOST_CXX14_CONSTEXPR void reset() noexcept
{
storage.reset();
+1 -1
View File
@@ -28,7 +28,6 @@ project
cxx11_explicit_conversion_operators
# cxx11_noexcept
cxx11_rvalue_references
cxx11_static_assert
cxx11_variadic_templates
]
;
@@ -81,6 +80,7 @@ compile-fail optional_test_fail3b.cpp ;
compile-fail optional_test_ref_fail1.cpp ;
compile-fail optional_test_ref_fail3.cpp ;
compile-fail optional_test_ref_fail4.cpp ;
compile-fail optional_test_ref_fail_convert_from_temporary_optional_T.cpp ;
compile-fail optional_test_inplace_fail.cpp ;
compile-fail optional_test_inplace_fail2.cpp ;
compile-fail optional_test_fail_implicit_bool_convert.cpp ;
+2
View File
@@ -45,6 +45,8 @@ void test_optional_of_superconverting_T() // compile-time test
superconv<optional<int> > s;
superconv<optional<int> > & rs = s;
optional<superconv<optional<int> > > os = rs;
(void)s;
(void)os;
#endif
}
+2 -2
View File
@@ -111,10 +111,10 @@ template <typename CharT>
struct basic_formatter
{
template< typename FunT >
basic_formatter(FunT&& fun) {}
basic_formatter(FunT&&) {}
template< typename FunT >
basic_formatter& operator= (FunT&& fun)
basic_formatter& operator= (FunT&&)
{
return *this;
}
@@ -0,0 +1,21 @@
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
//
// 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:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_converting_initialization()
{
boost::optional<const int&> o (boost::optional<int>(1));
(void)o;
}
+121 -14
View File
@@ -24,7 +24,13 @@ using boost::none;
struct Value
{
int val;
explicit Value(int v) : val(v) {}
BOOST_CONSTEXPR explicit Value(int v) : val(v) {}
};
struct Guard
{
int val;
BOOST_CONSTEXPR explicit Guard(int v) : val(v) {}
};
int val(int const& i)
@@ -37,6 +43,11 @@ int val(Value const& v)
return v.val;
}
int val(Guard const& v)
{
return v.val;
}
template <typename Tref>
optional<Tref&> make_opt_ref(Tref& v)
{
@@ -47,21 +58,21 @@ template <typename Tval, typename Tref>
void test_construct_from_optional_ref()
{
Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0 (opt_ref0);
optional<Tval> opt_val1 (opt_ref1);
optional<Tval> opt_val2 (make_opt_ref(v2));
BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
}
@@ -70,29 +81,121 @@ template <typename Tval, typename Tref>
void test_assign_from_optional_ref()
{
Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0;
optional<Tval> opt_val1;
optional<Tval> opt_val2;
opt_val0 = opt_ref0;
opt_val1 = opt_ref1;
opt_val2 = make_opt_ref(v2);
BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
}
template <typename T>
void test_convert_optional_T_to_optional_T_ref()
{
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
using boost::optional;
using boost::in_place_init;
{ // optional<T>& -> optional<T&>
optional<T> ovN, ov1(in_place_init, 1), ov2(in_place_init, 2);
optional<T&> orN = ovN;
optional<T&> or1 = ov1;
optional<T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // const optional<T>& -> optional<const T&>
constexpr optional<T> ovN;
constexpr optional<T> ov1(in_place_init, 1);
constexpr optional<T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // optional<const T>& -> optional<const T&>
optional<const T> ovN;
optional<const T> ov1(in_place_init, 1);
optional<const T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // optional<T>& -> optional<const T&>
optional<T> ovN;
optional<T> ov1(in_place_init, 1);
optional<T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
}
int main()
{
@@ -100,17 +203,21 @@ int main()
test_construct_from_optional_ref<int, int const>();
test_construct_from_optional_ref<int const, int const>();
test_construct_from_optional_ref<int const, int>();
test_construct_from_optional_ref<Value, Value>();
test_construct_from_optional_ref<Value, Value const>();
test_construct_from_optional_ref<Value const, Value const>();
test_construct_from_optional_ref<Value const, Value>();
test_assign_from_optional_ref<int, int>();
test_assign_from_optional_ref<int, int const>();
test_assign_from_optional_ref<Value, Value>();
test_assign_from_optional_ref<Value, Value const>();
test_convert_optional_T_to_optional_T_ref<int>();
test_convert_optional_T_to_optional_T_ref<Value>();
test_convert_optional_T_to_optional_T_ref<Guard>();
return boost::report_errors();
}