From bab2f102a1eb075e7fd9a55cc545b25a8efb35ae Mon Sep 17 00:00:00 2001 From: Logikoma Date: Wed, 5 Aug 2026 23:34:47 -0400 Subject: [PATCH] Test ignored-error storage across translation units --- CMakeLists.txt | 16 ++++++++++++++++ include/akerror.tmpl.h | 2 +- src/error.c | 1 + tests/err_ignore_multitu.c | 18 ++++++++++++++++++ tests/err_ignore_multitu.h | 8 ++++++++ tests/err_ignore_multitu_helper.c | 6 ++++++ 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/err_ignore_multitu.c create mode 100644 tests/err_ignore_multitu.h create mode 100644 tests/err_ignore_multitu_helper.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0770138..b3b275a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,22 @@ foreach(_test IN LISTS AKERR_TESTS) endif() endforeach() +# The ignored-error slot is declared in the public header but must have one +# library definition. Compare its address from two translation units, and +# compile the consumer-facing test with all ordinary warnings enabled: a +# header-local TLS definition would both duplicate storage and warn when unused. +add_executable(test_err_ignore_multitu + tests/err_ignore_multitu.c + tests/err_ignore_multitu_helper.c) +target_include_directories(test_err_ignore_multitu + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests) +target_link_libraries(test_err_ignore_multitu PRIVATE akerror) +target_compile_options(test_err_ignore_multitu PRIVATE -Wall -Wextra -Werror) +if(AKERR_THREAD_SAFE) + target_link_libraries(test_err_ignore_multitu PRIVATE Threads::Threads) +endif() +add_test(NAME err_ignore_multitu COMMAND test_err_ignore_multitu) + # HANDLE_GROUP deliberately enters the next case label. Keep that public macro # compiling with the warning enabled, so a future macro edit cannot restore the # warning for consumers which adopt -Wextra. diff --git a/include/akerror.tmpl.h b/include/akerror.tmpl.h index 851bb77..636ab2f 100644 --- a/include/akerror.tmpl.h +++ b/include/akerror.tmpl.h @@ -216,7 +216,7 @@ extern akerr_ErrorLogFunction akerr_log_method; * after the pool slot is reused. The snapshot is read-only and is replaced by * the next ignored error. Thread local only when AKERR_THREAD_SAFE is 1. */ -static AKERR_THREAD_LOCAL akerr_ErrorContext akerr_last_ignored; +extern AKERR_THREAD_LOCAL akerr_ErrorContext akerr_last_ignored; /* * Drop one reference, returning NULL once the last one is gone so the caller can diff --git a/src/error.c b/src/error.c index 53a5a17..9b2971d 100644 --- a/src/error.c +++ b/src/error.c @@ -28,6 +28,7 @@ * template header because the macro copies into it at the call site. */ static AKERR_THREAD_LOCAL akerr_ErrorContext __akerr_last_ditch; +AKERR_THREAD_LOCAL akerr_ErrorContext akerr_last_ignored; akerr_ErrorUnhandledErrorHandler akerr_handler_unhandled_error; akerr_ErrorLogFunction akerr_log_method = NULL; diff --git a/tests/err_ignore_multitu.c b/tests/err_ignore_multitu.c new file mode 100644 index 0000000..6d89d8e --- /dev/null +++ b/tests/err_ignore_multitu.c @@ -0,0 +1,18 @@ +#include "akerror.h" +#include "err_ignore_multitu.h" +#include + +int main(void) +{ + akerr_ErrorContext *main_address = &akerr_last_ignored; + akerr_ErrorContext *helper_address = akerr_multitu_snapshot_address(); + + if ( main_address != helper_address ) { + fprintf(stderr, + "CHECK FAILED: ignored-error storage differs between translation units\n"); + return 1; + } + + fprintf(stderr, "err_ignore_multitu ok\n"); + return 0; +} diff --git a/tests/err_ignore_multitu.h b/tests/err_ignore_multitu.h new file mode 100644 index 0000000..17f2f9e --- /dev/null +++ b/tests/err_ignore_multitu.h @@ -0,0 +1,8 @@ +#ifndef AKERR_TEST_IGNORE_MULTITU_H +#define AKERR_TEST_IGNORE_MULTITU_H + +#include "akerror.h" + +akerr_ErrorContext *akerr_multitu_snapshot_address(void); + +#endif diff --git a/tests/err_ignore_multitu_helper.c b/tests/err_ignore_multitu_helper.c new file mode 100644 index 0000000..2994089 --- /dev/null +++ b/tests/err_ignore_multitu_helper.c @@ -0,0 +1,6 @@ +#include "err_ignore_multitu.h" + +akerr_ErrorContext *akerr_multitu_snapshot_address(void) +{ + return &akerr_last_ignored; +}