-
-
Notifications
You must be signed in to change notification settings - Fork 464
Debug assert #1175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Debug assert #1175
Changes from all commits
4f2c6ac
6fa4fad
1ba8480
cab3bda
eba6eda
6a1f790
e0e6bde
e02a685
97b3ed4
80f4814
07dfe30
d6adf29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -364,6 +364,62 @@ namespace etl | |||||||||||||||||||||
#endif | ||||||||||||||||||||||
#endif | ||||||||||||||||||||||
|
||||||||||||||||||||||
#if ETL_IS_DEBUG_BUILD | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there should be other macros that make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I filled out the rest of the asserts from the |
||||||||||||||||||||||
#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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||
|
||||||||||||||||||||||
#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. | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
||
//************************************************************************* | ||
|
@@ -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); | ||
} | ||
|
||
//************************************************************************* | ||
|
@@ -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); | ||
} | ||
|
||
//************************************************************************* | ||
|
@@ -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); | ||
} | ||
|
||
//************************************************************************* | ||
|
@@ -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); | ||
} | ||
|
||
//************************************************************************* | ||
|
@@ -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); | ||
} | ||
|
||
//************************************************************************* | ||
|
There was a problem hiding this comment.
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 conditionalif (…) return
, which violates the C++11 constexpr rule that a function body may only contain exactly onereturn
. Redefine it to a singlereturn
expression (e.g. using the comma operator for the assertion) ininclude/etl/error_handler.h
.🤖 Prompt for AI Agents