mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Fix undefined behaviour of etl::absolute() for etl::numeric_limits<T>::min (#1333)
absolute_unsigned() already handled that case correctly. Now adding this check to absolute() also. It can be caught at compile time now, if in a constexpr context. Also separating integral and non-integral versions via enable_if. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
54a1c82c98
commit
0a56d40bdd
@ -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 <typename T>
|
||||
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 <typename T>
|
||||
ETL_NODISCARD
|
||||
ETL_CONSTEXPR
|
||||
typename etl::enable_if<etl::is_signed<T>::value, T>::type
|
||||
ETL_CONSTEXPR
|
||||
typename etl::enable_if<etl::is_signed<T>::value && etl::is_integral<T>::value, T>::type
|
||||
absolute(T value)
|
||||
{
|
||||
return (value == etl::integral_limits<T>::min) ? etl::private_absolute::signed_min_error<T>()
|
||||
: (value < T(0)) ? -value : value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ETL_NODISCARD
|
||||
ETL_CONSTEXPR
|
||||
typename etl::enable_if<etl::is_signed<T>::value && !etl::is_integral<T>::value, T>::type
|
||||
absolute(T value) ETL_NOEXCEPT
|
||||
{
|
||||
return (value < T(0)) ? -value : value;
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user