#1171 optional of a const arary can't be emplaced with gcc-15

This commit is contained in:
John Wellbelove 2025-09-06 11:23:20 +01:00
parent ea61ff7770
commit d27adeb510
2 changed files with 111 additions and 40 deletions

View File

@ -42,6 +42,12 @@ SOFTWARE.
namespace etl
{
//*****************************************************************************
// Forward declaration of etl::optional
//*****************************************************************************
template <typename T>
class optional;
//*****************************************************************************
/// A null option type.
///\ingroup utilities
@ -102,7 +108,7 @@ namespace etl
//*****************************************************************************
namespace private_optional
{
template <typename T, bool IsDefaultConstructible = etl::is_fundamental<T>::value>
template <typename T, bool UseFundamentalPath = etl::is_fundamental<T>::value && !etl::is_const<T>::value>
class optional_impl;
//*****************************************************************************
@ -114,6 +120,7 @@ namespace etl
protected:
typedef T value_type;
typedef optional_impl<T, false> this_type;
//***************************************************************************
/// Constructor.
@ -299,7 +306,7 @@ namespace etl
ETL_CONSTEXPR20_STL
T* operator ->()
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -312,7 +319,7 @@ namespace etl
ETL_CONSTEXPR20_STL
const T* operator ->() const
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -325,7 +332,7 @@ namespace etl
ETL_CONSTEXPR20_STL
T& operator *() ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -338,7 +345,7 @@ namespace etl
ETL_CONSTEXPR20_STL
const T& operator *() const ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -352,7 +359,7 @@ namespace etl
ETL_CONSTEXPR20_STL
T&& operator *()&&
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -365,7 +372,7 @@ namespace etl
ETL_CONSTEXPR20_STL
const T&& operator *() const&&
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -496,16 +503,36 @@ namespace etl
storage.destroy();
}
//*************************************************************************
///
//*************************************************************************
ETL_CONSTEXPR20_STL
T& emplace(const optional_impl<T>& other)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid));
#endif
storage.construct(other.value());
return storage.u.value;
}
#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION)
//*************************************************************************
/// Emplaces a value.
///\param args The arguments to construct with.
/// Emplaces a value from arbitrary constructor arguments.
/// Disabled (via SFINAE) if the first argument is an optional_impl (or a
/// derived type such as etl::optional<T>) so that the dedicated
/// emplace(const optional_impl&) overload is selected instead.
//*************************************************************************
template <typename... TArgs>
template <typename U,
typename... URest,
typename etl::enable_if<!etl::is_base_of<optional_impl,
typename etl::remove_cv<typename etl::remove_reference<U>::type>::type>::value, int>::type = 0>
ETL_CONSTEXPR20_STL
T& emplace(TArgs&& ... args)
T& emplace(U&& first, URest&&... rest)
{
storage.construct(etl::forward<TArgs>(args)...);
storage.construct(etl::forward<U>(first), etl::forward<URest>(rest)...);
return storage.u.value;
}
@ -533,7 +560,9 @@ namespace etl
/// 1 parameter.
//*************************************************************************
template <typename T1>
T& emplace(const T1& value1)
typename etl::enable_if<!etl::is_base_of<this_type, typename etl::remove_cv<typename etl::remove_reference<T1>::type>::type>::value &&
!etl::is_same<etl::optional<T>, typename etl::remove_cv<typename etl::remove_reference<T1>::type>::type>::value, T&>::type
emplace(const T1& value1)
{
if (has_value())
{
@ -614,6 +643,8 @@ namespace etl
//*************************************
struct storage_type
{
typedef typename etl::remove_const<T>::type* pointer_type;
//*******************************
ETL_CONSTEXPR20_STL
storage_type()
@ -626,12 +657,9 @@ namespace etl
ETL_CONSTEXPR20_STL
void construct(const T& value_)
{
if (valid)
{
etl::destroy_at(&u.value);
}
destroy();
etl::construct_at(&u.value, value_);
etl::construct_at(const_cast<pointer_type>(&u.value), value_);
valid = true;
}
@ -640,12 +668,9 @@ namespace etl
ETL_CONSTEXPR20_STL
void construct(T&& value_)
{
if (valid)
{
etl::destroy_at(&u.value);
}
destroy();
etl::construct_at(&u.value, etl::move(value_));
etl::construct_at(const_cast<pointer_type>(&u.value), etl::move(value_));
valid = true;
}
@ -654,12 +679,9 @@ namespace etl
ETL_CONSTEXPR20_STL
void construct(TArgs&&... args)
{
if (valid)
{
etl::destroy_at(&u.value);
}
destroy();
etl::construct_at(&u.value, etl::forward<TArgs>(args)...);
etl::construct_at(const_cast<pointer_type>(&u.value), etl::forward<TArgs>(args)...);
valid = true;
}
#endif
@ -670,7 +692,7 @@ namespace etl
{
if (valid)
{
etl::destroy_at(&u.value);
etl::destroy_at(const_cast<pointer_type>(&u.value));
valid = false;
}
}
@ -708,6 +730,7 @@ namespace etl
protected:
typedef T value_type;
typedef optional_impl<T, true> this_type;
//***************************************************************************
/// Constructor.
@ -884,7 +907,7 @@ namespace etl
ETL_CONSTEXPR14
T* operator ->()
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -897,7 +920,7 @@ namespace etl
ETL_CONSTEXPR14
const T* operator ->() const
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -910,7 +933,7 @@ namespace etl
ETL_CONSTEXPR14
T& operator *() ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -923,7 +946,7 @@ namespace etl
ETL_CONSTEXPR14
const T& operator *() const ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -937,7 +960,7 @@ namespace etl
ETL_CONSTEXPR14
T&& operator *()&&
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -950,7 +973,7 @@ namespace etl
ETL_CONSTEXPR14
const T&& operator *() const&&
{
#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL)
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid));
#endif
@ -1081,6 +1104,21 @@ namespace etl
storage.destroy();
}
//*************************************************************************
///
//*************************************************************************
ETL_CONSTEXPR20_STL
T& emplace(const optional_impl<T>& other)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid));
#endif
storage.construct(other.value());
return storage.u.value;
}
#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION)
//*************************************************************************
/// Emplaces a value.
@ -1118,7 +1156,9 @@ namespace etl
/// 1 parameter.
//*************************************************************************
template <typename T1>
T& emplace(const T1& value1)
typename etl::enable_if<!etl::is_base_of<this_type, typename etl::remove_cv<typename etl::remove_reference<T1>::type>::type>::value &&
!etl::is_same<etl::optional<T>, typename etl::remove_cv<typename etl::remove_reference<T1>::type>::type>::value, T&>::type
emplace(const T1& value1)
{
if (has_value())
{
@ -1247,11 +1287,11 @@ namespace etl
};
}
#define ETL_OPTIONAL_ENABLE_CPP14 typename etl::enable_if< etl::is_pod<U>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CPP20_STL typename etl::enable_if<!etl::is_pod<U>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CPP14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CPP20_STL typename etl::enable_if<!etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod<T>::value, bool>::type
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL ETL_CONSTEXPR20_STL typename etl::enable_if<!etl::is_pod<T>::value, bool>::type
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<T>::type>::value, bool>::type
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL ETL_CONSTEXPR20_STL typename etl::enable_if<!etl::is_pod<typename etl::remove_cv<T>::type>::value, bool>::type
//*****************************************************************************
/// An optional type.

View File

@ -976,5 +976,36 @@ namespace
}
};
}
//*************************************************************************
using ItemType = etl::array<uint8_t, 2>;
etl::optional<const ItemType> create_optional_issue_1171()
{
ItemType t;
t[0] = 1;
t[1] = 20;
return etl::optional<const ItemType>(t);
}
TEST(test_optional_issue_1171)
{
etl::optional<const ItemType> opt1 = create_optional_issue_1171();
CHECK_TRUE(opt1.has_value());
CHECK_EQUAL(1, (*opt1)[0]);
CHECK_EQUAL(20, (*opt1)[1]);
etl::optional<const ItemType> opt2(create_optional_issue_1171());
CHECK_TRUE(opt2.has_value());
CHECK_EQUAL(1, (*opt2)[0]);
CHECK_EQUAL(20, (*opt2)[1]);
etl::optional<const ItemType> opt3;
opt3.emplace(create_optional_issue_1171());
CHECK_TRUE(opt3.has_value());
CHECK_EQUAL(1, (*opt3)[0]);
CHECK_EQUAL(20, (*opt3)[1]);
}
};
}