From 75606fc079c4785c8726bfe1c1364ff159a322a2 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 10 Sep 2025 11:37:30 +0200 Subject: [PATCH] Regression fix: Support zero arguments emplace() in etl::optional (#1183) * Added coderabbitai configuration * Added builtin mem function tests * Modified etl::typed_storage * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Added ETL_NOEXCEPT and ETL_NOEXCEPT_IF_NO_THROW * Added etl::typed_storage_ext and swap for same * Added etl::typed_storage_ext and swap for same # Conflicts: # include/etl/alignment.h * Added release notes * Fixes to GCC -O2 errors * Changed char* parameters to value_type* parameters * Fixed compilation issues for const containers unit tests * Added automatic selection of __builtin_memxxx functions for GCC and clang * Added enhanced coderabbit configuration * Updated version and release notes * Disabled constexpr const container tests for C++11 * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Updated version and release notes * feat: removed unreachable break statements (#1169) * Updated version and release notes * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Support zero arguments emplace() in etl::optional For non-fundamental types, a recent change in etl::optional was introduced that doesn't support zero arguments emplace() anymore. This change fixes it and adds the respective test. --------- Co-authored-by: John Wellbelove Co-authored-by: Drew Rife --- include/etl/alignment.h | 72 ++++++++++++++++++++++++++++++++--------- include/etl/optional.h | 11 +++++++ test/test_optional.cpp | 16 +++++++-- 3 files changed, 81 insertions(+), 18 deletions(-) diff --git a/include/etl/alignment.h b/include/etl/alignment.h index 5ab63802..c289b4a4 100644 --- a/include/etl/alignment.h +++ b/include/etl/alignment.h @@ -450,9 +450,17 @@ namespace etl template reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (&storage.value) value_type(etl::forward(args)...); + if (has_value()) + { + storage.value = T(args...); + } + else + { + valid = true; + ::new (&storage.value) value_type(etl::forward(args)...); + } + + return storage.value; } #else //*************************************************************************** @@ -462,9 +470,17 @@ namespace etl template reference create(const T1& t1) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (&storage.value) value_type(t1); + if (has_value()) + { + storage.value = T(t1); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1); + } + + return storage.value; } //*************************************************************************** @@ -474,9 +490,17 @@ namespace etl template reference create(const T1& t1, const T2& t2) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (&storage.value) value_type(t1, t2); + if (has_value()) + { + storage.value = T(t1, t2); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2); + } + + return storage.value; } //*************************************************************************** @@ -486,9 +510,17 @@ namespace etl template reference create(const T1& t1, const T2& t2, const T3& t3) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (&storage.value) value_type(t1, t2, t3); + if (has_value()) + { + storage.value = T(t1, t2, t3); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2, t3); + } + + return storage.value; } //*************************************************************************** @@ -498,9 +530,17 @@ namespace etl template reference create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (&storage.value) value_type(t1, t2, t3, t4); + if (has_value()) + { + storage.value = T(t1, t2, t3, t4); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2, t3, t4); + } + + return storage.value; } #endif @@ -559,7 +599,7 @@ namespace etl struct dummy_t {}; - //******************************* + //******************************* union union_type { union_type() ETL_NOEXCEPT diff --git a/include/etl/optional.h b/include/etl/optional.h index 48289116..e8e40439 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -536,6 +536,17 @@ namespace etl return storage.u.value; } + + //************************************************************************* + /// Emplaces with zero arguments, i.e. default construct emplace. + //************************************************************************* + ETL_CONSTEXPR20_STL + T& emplace() + { + storage.construct(); + + return storage.u.value; + } #else //************************************************************************* /// Emplaces a value. diff --git a/test/test_optional.cpp b/test/test_optional.cpp index e9623b87..c5a34d08 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -218,15 +218,27 @@ namespace } //************************************************************************* - TEST(test_emplace_zero_parameters) + TEST(test_emplace_zero_parameters_fundamental) { etl::optional result = 1; - result.emplace(); + CHECK_EQUAL(0, static_cast(result.emplace())); CHECK_TRUE(result.has_value()); CHECK_EQUAL(0, int(result.value())); } + //************************************************************************* + TEST(test_emplace_zero_parameters_non_fundamental) + { + etl::optional result = std::string("abc"); + + std::string& ref = result.emplace(); + CHECK_EQUAL(std::string(), ref); + CHECK_EQUAL(&ref, &result.value()); + CHECK_TRUE(result.has_value()); + CHECK_EQUAL("", std::string(result.value())); + } + //************************************************************************* TEST(test_emplace_return) {