Skip to content
Merged
46 changes: 44 additions & 2 deletions include/etl/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ namespace etl
ETL_CONSTEXPR14
reference operator[](size_t i)
{
ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));

return _buffer[i];
}

Expand All @@ -156,7 +158,14 @@ namespace etl
ETL_NODISCARD
ETL_CONSTEXPR const_reference operator[](size_t i) const
{
//throwing from c++11 constexpr requires a special macro
#if ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_DEBUG_USING_EXCEPTIONS
ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(i < SIZE, ETL_ERROR(array_out_of_range), _buffer[i]);
#else
ETL_DEBUG_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));

return _buffer[i];
#endif
}
Comment on lines +161 to 169
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

C++11 constexpr + debug exceptions + debug logging breaks single-return rule

When ETL_USING_CPP11 && !ETL_USING_CPP14 && ETL_DEBUG_USING_EXCEPTIONS && ETL_DEBUG_LOG_ERRORS, ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR expands to an if + return, which is ill-formed in a C++11 constexpr function body (must be a single return statement). Prefer a single return expression (use comma operator) and move the fix into the macro (see error_handler.h comment with diff).


Enforce single-return in C++11 constexpr
ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR expands to a conditional if (…) return, which violates the C++11 constexpr rule that a function body may only contain exactly one return. Redefine it to a single return expression (e.g. using the comma operator for the assertion) in include/etl/error_handler.h.

🤖 Prompt for AI Agents
In include/etl/array.h around lines 161 to 169, the macro
ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR expands to an if-return form
which violates C++11 constexpr's single-return rule; update the macro definition
in include/etl/error_handler.h so that under ETL_USING_CPP11 && !ETL_USING_CPP14
&& ETL_DEBUG_USING_EXCEPTIONS it expands to a single return statement (for
example, perform the assertion expression as a side-effect using the comma
operator or a conditional operator and then return the value in the same return
expression), ensuring the assertion still occurs and the function body contains
exactly one return.


//*************************************************************************
Expand All @@ -166,6 +175,8 @@ namespace etl
ETL_CONSTEXPR14
reference front()
{
ETL_STATIC_ASSERT(SIZE > 0, "Array is empty.");

return _buffer[0];
}

Expand All @@ -175,6 +186,8 @@ namespace etl
ETL_NODISCARD
ETL_CONSTEXPR const_reference front() const
{
ETL_STATIC_ASSERT(SIZE > 0, "Array is empty.");

return _buffer[0];
}

Expand All @@ -185,6 +198,8 @@ namespace etl
ETL_CONSTEXPR14
reference back()
{
ETL_STATIC_ASSERT(SIZE > 0, "Array is empty.");

return _buffer[SIZE - 1];
}

Expand All @@ -194,6 +209,8 @@ namespace etl
ETL_NODISCARD
ETL_CONSTEXPR const_reference back() const
{
ETL_STATIC_ASSERT(SIZE > 0, "Array is empty.");

return _buffer[SIZE - 1];
}

Expand Down Expand Up @@ -429,6 +446,8 @@ namespace etl
//*************************************************************************
inline iterator insert_at(size_t position, parameter_t value)
{
ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range));

return insert(begin() + position, value);
}

Expand All @@ -439,6 +458,8 @@ namespace etl
//*************************************************************************
iterator insert(const_iterator position, parameter_t value)
{
ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(position);

etl::move_backward(p, end() - 1, end());
Expand All @@ -456,6 +477,8 @@ namespace etl
template <typename TIterator>
inline iterator insert_at(size_t position, TIterator first, const TIterator last)
{
ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range));

return insert(begin() + position, first, last);
}

Expand All @@ -468,6 +491,8 @@ namespace etl
template <typename TIterator>
iterator insert(const_iterator position, TIterator first, const TIterator last)
{
ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(position);
iterator result(p);

Expand All @@ -494,6 +519,8 @@ namespace etl
//*************************************************************************
inline iterator erase_at(size_t position)
{
ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range));

return erase(begin() + position);
}

Expand All @@ -504,6 +531,8 @@ namespace etl
//*************************************************************************
iterator erase(const_iterator position)
{
ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(position);
etl::move(p + 1, end(), p);

Expand All @@ -518,6 +547,8 @@ namespace etl
//*************************************************************************
iterator erase_range(size_t first, size_t last)
{
ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range));

return erase(begin() + first, begin() + last);
}

Expand All @@ -529,6 +560,8 @@ namespace etl
//*************************************************************************
iterator erase(const_iterator first, const_iterator last)
{
ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(first);
etl::move(last, cend(), p);
return p;
Expand All @@ -541,6 +574,8 @@ namespace etl
//*************************************************************************
inline iterator erase_at(size_t position, parameter_t value)
{
ETL_DEBUG_ASSERT(position < SIZE, ETL_ERROR(array_out_of_range));

return erase(begin() + position, value);
}

Expand All @@ -551,6 +586,8 @@ namespace etl
//*************************************************************************
iterator erase(const_iterator position, parameter_t value)
{
ETL_DEBUG_ASSERT(cbegin() <= position && position < cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(position);

etl::move(p + 1, end(), p);
Expand All @@ -567,16 +604,21 @@ namespace etl
//*************************************************************************
iterator erase_range(size_t first, size_t last, parameter_t value)
{
ETL_DEBUG_ASSERT(first <= last && last <= SIZE, ETL_ERROR(array_out_of_range));

return erase(begin() + first, begin() + last, value);
}

//*************************************************************************
/// Erases a range of values from the array.
///\param position The iterator to the position to erase at.
///\param value The value to use to overwrite the last elements in the array.
///\param first The first item to erase.
///\param last The one past the last item to erase.
///\param value The value to use to overwrite the last elements in the array.
//*************************************************************************
iterator erase(const_iterator first, const_iterator last, parameter_t value)
{
ETL_DEBUG_ASSERT(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(array_out_of_range));

iterator p = to_iterator(first);

p = etl::move(last, cend(), p);
Expand Down
56 changes: 56 additions & 0 deletions include/etl/error_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,62 @@ namespace etl
#endif
#endif

#if ETL_IS_DEBUG_BUILD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be other macros that make ETL_DEBUG_ASSERT consistent with the options provided by the ETL_ASSERT_XXX set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I filled out the rest of the asserts from the ETL_ASSERT_XXX set. I'm not sure if its useful or not but I also included macros for ETL_DEBUG_USE_ASSERT_FUNCTION and ETL_DEBUG_LOG_ERRORS.

#if defined(ETL_DEBUG_USE_ASSERT_FUNCTION)
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value

#define ETL_DEBUG_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value
#elif ETL_DEBUG_USING_EXCEPTIONS
#if defined(ETL_DEBUG_LOG_ERRORS)
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception.
Comment on lines +377 to +381
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix C++11 constexpr variant to remain a single return statement (with logging)

The current macro emits an extra statement in C++11 constexpr contexts when ETL_DEBUG_LOG_ERRORS is set. Keep logging but ensure one return expression.

Apply:

-      #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e)  // throwing from c++11 constexpr requires ? operator
+      #define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : (etl::error_handler::error((e)), throw (e), (v))  // single return expr for C++11 constexpr
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#if defined(ETL_DEBUG_LOG_ERRORS)
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));} return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception.
#if defined(ETL_DEBUG_LOG_ERRORS)
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : (etl::error_handler::error((e)), throw (e), (v)) // single return expr for C++11 constexpr
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return;}} // If the condition fails, calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); throw((e)); return(v);}} // If the condition fails, calls the error handler then throws an exception.
🤖 Prompt for AI Agents
In include/etl/error_handler.h around lines 377-381, the
ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR macro currently emits an extra
statement and breaks C++11 constexpr contexts; replace its body with a single
return expression that uses the conditional (?:) operator so that when (b) is
true it returns v, otherwise it first invokes etl::error_handler::error(e) and
then throws e — all inside the single returned expression (ensure proper
parenthesization for the conditional and the error call so the macro remains a
single constexpr-compatible return).


#define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e)); throw((e));} // Calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); throw((e)); return;} // Calls the error handler then throws an exception.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); throw((e)); return(v);} // Calls the error handler then throws an exception.
#else
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE_CPP11_CONSTEXPR(b, e, v) return (b) ? (v) : throw(e) // throwing from c++11 constexpr requires ? operator
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {throw((e));}} // If the condition fails, throws an exception.

#define ETL_DEBUG_ASSERT_FAIL(e) {throw((e));} // Throws an exception.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception.
#endif
#elif defined(ETL_DEBUG_LOG_ERRORS)
#define ETL_DEBUG_ASSERT(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e));}} // If the condition fails, calls the error handler
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return;}} // If the condition fails, calls the error handler and return
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {etl::error_handler::error((e)); return (v);}} // If the condition fails, calls the error handler and return a value

#define ETL_DEBUG_ASSERT_FAIL(e) {etl::error_handler::error((e));} // Calls the error handler
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {etl::error_handler::error((e)); return;} // Calls the error handler and return
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::error_handler::error((e)); return (v);} // Calls the error handler and return a value
#else
#define ETL_DEBUG_ASSERT(b, e) assert((b)) // If the condition fails, asserts.
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY {assert(false); return;}} // If the condition fails, asserts and return.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY {assert(false); return(v);}} // If the condition fails, asserts and return a value.

#define ETL_DEBUG_ASSERT_FAIL(e) assert(false) // Asserts.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {assert(false); return;} // Asserts.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts.
#endif
#else
#define ETL_DEBUG_ASSERT(b, e) // Does nothing.
#define ETL_DEBUG_ASSERT_OR_RETURN(b, e) {if (!(b)) ETL_UNLIKELY return;} // Returns.
#define ETL_DEBUG_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) ETL_UNLIKELY return(v);} // Returns a value.

#define ETL_DEBUG_ASSERT_FAIL(e) // Does nothing.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns.
#define ETL_DEBUG_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {return(v);} // Returns a value.
#endif

#if defined(ETL_VERBOSE_ERRORS)
#define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number.
#define ETL_ERROR_WITH_VALUE(e, v) (e(__FILE__, __LINE__, (v))) // Make an exception with the file name, line number and value.
Expand Down
24 changes: 6 additions & 18 deletions include/etl/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,7 @@ namespace etl
//*******************************************
value_type* operator ->()
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::addressof(etl::get<value_type>(storage));
}
Expand All @@ -687,9 +685,7 @@ namespace etl
//*******************************************
const value_type* operator ->() const
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::addressof(etl::get<value_type>(storage));
}
Expand All @@ -699,9 +695,7 @@ namespace etl
//*******************************************
value_type& operator *() ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::get<value_type>(storage);
}
Expand All @@ -711,9 +705,7 @@ namespace etl
//*******************************************
const value_type& operator *() const ETL_LVALUE_REF_QUALIFIER
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::get<value_type>(storage);
}
Expand All @@ -724,9 +716,7 @@ namespace etl
//*******************************************
value_type&& operator *()&&
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::move(etl::get<value_type>(storage));
}
Expand All @@ -736,9 +726,7 @@ namespace etl
//*******************************************
const value_type&& operator *() const&&
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(has_value(), ETL_ERROR(expected_invalid));
#endif
ETL_DEBUG_ASSERT(has_value(), ETL_ERROR(expected_invalid));

return etl::move(etl::get<value_type>(storage));
}
Expand Down
10 changes: 10 additions & 0 deletions include/etl/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ SOFTWARE.
#define ETL_NOT_USING_EXCEPTIONS 1
#endif

//*************************************
// Indicate if C++ exceptions are enabled for debug asserts.
#if ETL_IS_DEBUG_BUILD && defined(ETL_DEBUG_THROW_EXCEPTIONS)
#define ETL_DEBUG_USING_EXCEPTIONS 1
#define ETL_DEBUG_NOT_USING_EXCEPTIONS 0
#else
#define ETL_DEBUG_USING_EXCEPTIONS 0
#define ETL_DEBUG_NOT_USING_EXCEPTIONS 1
#endif

//*************************************
// Indicate if nullptr is used.
#if ETL_NO_NULLPTR_SUPPORT
Expand Down
2 changes: 2 additions & 0 deletions test/etl_profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ SOFTWARE.
#ifndef ETL_PROFILE_H_INCLUDED
#define ETL_PROFILE_H_INCLUDED

#define ETL_DEBUG
#define ETL_THROW_EXCEPTIONS
#define ETL_DEBUG_THROW_EXCEPTIONS
#define ETL_VERBOSE_ERRORS
#define ETL_CHECK_PUSH_POP
#define ETL_ISTRING_REPAIR_ENABLE
Expand Down
25 changes: 25 additions & 0 deletions test/test_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}

//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range);
}
Comment on lines +138 to 140
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Gate the out-of-bounds [] checks behind the same flags used by ETL_DEBUG_ASSERT.

Unconditionally requiring a throw will fail in release or non-exception builds. Guard the checks so they only run when ETL_IS_DEBUG_BUILD && ETL_USING_EXCEPTIONS (or ETL_DEBUG_USING_EXCEPTIONS if adopted).

-      //ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
-      CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range);
+      // Only active when debug + exceptions route is enabled for ETL_DEBUG_ASSERT
+#if ETL_IS_DEBUG_BUILD && ETL_USING_EXCEPTIONS
+      CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range);
+#endif
🤖 Prompt for AI Agents
In test/test_array.cpp around lines 138 to 140, the test unconditionally expects
an exception from an out-of-bounds operator[] which will fail in release or
non-exception builds; wrap the CHECK_THROW block with a preprocessor guard so it
only runs when both debug and exceptions are enabled (e.g. #if
defined(ETL_IS_DEBUG_BUILD) && (defined(ETL_USING_EXCEPTIONS) ||
defined(ETL_DEBUG_USING_EXCEPTIONS))) and close the #endif after the
CHECK_THROW; ensure the guarded code preserves the existing CHECK_THROW
invocation and adds no additional side effects.

Copy link
Contributor Author

@mike919192 mike919192 Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this applies because there are many tests that that rely on exceptions and debug build already. Basically most tests already rely on these build options.


//*************************************************************************
Expand All @@ -145,6 +148,9 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}

//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
CHECK_THROW({ int d = data[data.size()]; (void)d; }, etl::array_out_of_range);
}

//*************************************************************************
Expand Down Expand Up @@ -443,6 +449,10 @@ namespace
CHECK_EQUAL(data[9], *result);
isEqual = std::equal(data.begin(), data.end(), std::begin(check3));
CHECK(isEqual);

// Insert out of range
//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
CHECK_THROW({ result = data.insert_at(data.size(), 99); }, etl::array_out_of_range);
}

//*************************************************************************
Expand Down Expand Up @@ -493,6 +503,10 @@ namespace
CHECK_EQUAL(data[4], *result);
isEqual = std::equal(data.begin(), data.end(), std::begin(check5));
CHECK(isEqual);

// Insert out of range
//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
CHECK_THROW({ result = data.insert_at(data.size(), &source2[0], &source2[13]); }, etl::array_out_of_range);
}

//*************************************************************************
Expand Down Expand Up @@ -547,6 +561,10 @@ namespace
CHECK_EQUAL(data[9], *result);
isEqual = std::equal(data.begin(), data.end(), std::begin(check3b));
CHECK(isEqual);

// Erase out of range
//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
CHECK_THROW({ result = data.erase_at(data.size()); }, etl::array_out_of_range);
}

//*************************************************************************
Expand Down Expand Up @@ -601,6 +619,13 @@ namespace
CHECK_EQUAL(data[5], *result);
isEqual = std::equal(data.begin(), data.end(), std::begin(check3b));
CHECK(isEqual);

//ETL_DEBUG and ETL_THROW_EXCEPTIONS are defined
// first is greater than last
CHECK_THROW({ result = data.erase_range(6, 5, 99); }, etl::array_out_of_range);

// Erase out of range
CHECK_THROW({ result = data.erase_range(5, data.size() + 1, 99); }, etl::array_out_of_range);
}

//*************************************************************************
Expand Down
Loading