diff --git a/CMakeLists.txt b/CMakeLists.txt index d391805..b3b275a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ cmake_minimum_required(VERSION 3.10) # calls akerr_exit() instead of exit(1) directly, which changes that exit code # from 1 to AKERR_EXIT_STATUS_UNREPRESENTABLE (125) -- a deliberate behavior # change, not an ABI break: no soname move, no entry point changed shape. -project(akerror VERSION 2.0.2 LANGUAGES C) +project(akerror VERSION 2.0.3 LANGUAGES C) include(GNUInstallDirs) include(CMakePackageConfigHelpers) @@ -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; +}