diff --git a/include/etl/absolute.h b/include/etl/absolute.h index cad11b7c..52cfe8bd 100644 --- a/include/etl/absolute.h +++ b/include/etl/absolute.h @@ -34,16 +34,43 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" #include "integral_limits.h" +#include "error_handler.h" namespace etl { + namespace private_absolute + { + //************************************************************************* + // Non-constexpr function that is never called for valid inputs. + // If reached during constant evaluation, the compiler emits an error + // because it's not constexpr. + // At runtime, triggers the ETL assert handler. + //************************************************************************* + template + inline T signed_min_error() + { + ETL_ASSERT_FAIL(ETL_ERROR_GENERIC("absolute value of minimum signed integer is undefined")); + return T(0); + } + } + //*************************************************************************** // For signed types. //*************************************************************************** template ETL_NODISCARD - ETL_CONSTEXPR - typename etl::enable_if::value, T>::type + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_integral::value, T>::type + absolute(T value) + { + return (value == etl::integral_limits::min) ? etl::private_absolute::signed_min_error() + : (value < T(0)) ? -value : value; + } + + template + ETL_NODISCARD + ETL_CONSTEXPR + typename etl::enable_if::value && !etl::is_integral::value, T>::type absolute(T value) ETL_NOEXCEPT { return (value < T(0)) ? -value : value; diff --git a/test/test_math_functions.cpp b/test/test_math_functions.cpp index 0b7c9205..f5ef7842 100644 --- a/test/test_math_functions.cpp +++ b/test/test_math_functions.cpp @@ -574,12 +574,11 @@ namespace constexpr uint16_t absolute1 = etl::absolute(int16_t(0)); constexpr uint16_t absolute2 = etl::absolute(int16_t(32767)); constexpr uint16_t absolute3 = etl::absolute(int16_t(-32767)); - constexpr uint16_t absolute4 = etl::absolute(int16_t(-32768)); + //constexpr uint16_t absolute4 = etl::absolute(int16_t(-32768)); // Compile error CHECK_EQUAL(uint16_t(0), absolute1); CHECK_EQUAL(uint16_t(32767), absolute2); CHECK_EQUAL(uint16_t(32767), absolute3); - CHECK_EQUAL(uint16_t(32768), absolute4); constexpr uint16_t absolute5 = etl::absolute(uint16_t(0)); constexpr uint16_t absolute6 = etl::absolute(uint16_t(65535));