crt: test: Add new t_cpp_dtor_atexit_order test which verifies order of atexit callbacks and C++ thread local destructors

Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/testcases/Makefile.am b/mingw-w64-crt/testcases/Makefile.am
index 8459e28..41ce467 100644
--- a/mingw-w64-crt/testcases/Makefile.am
+++ b/mingw-w64-crt/testcases/Makefile.am
@@ -96,6 +96,7 @@
   t_assert \
   t_btowc \
   t_char16_t \
+  t_cpp_dtor_atexit_order \
   t_ctype \
   t_excpt_gcc_cpp \
   t_excpt_int_divzero \
@@ -211,6 +212,7 @@
 # Most of the tests are C programs, but there are some C++ tests as well.
 # For C++ targets, we have to explicitly specify source files so that
 # Automake does not assume .c extension.
+t_cpp_dtor_atexit_order_SOURCES = t_cpp_dtor_atexit_order.cpp
 t_intrin_cpp_SOURCES = t_intrin_cpp.cpp
 t_iostream_SOURCES = t_iostream.cpp
 t_isfine_SOURCES = t_isfine.cpp
@@ -222,6 +224,7 @@
 
 # On arm64ec, link all C++ tests statically; the toolchain (and the C++ DLL in
 # PATH) may be regular native aarch64, but we build and run arm64ec binaries.
+t_cpp_dtor_atexit_order_LDFLAGS = $(AM_LDFLAGS)
 t_intrin_cpp_LDFLAGS = $(AM_LDFLAGS)
 t_iostream_LDFLAGS = $(AM_LDFLAGS)
 t_isfine_LDFLAGS = $(AM_LDFLAGS)
@@ -232,6 +235,7 @@
 t_wrongret_LDFLAGS = $(AM_LDFLAGS)
 
 if ARM64EC
+t_cpp_dtor_atexit_order_LDFLAGS += -static
 t_intrin_cpp_LDFLAGS += -static
 t_iostream_LDFLAGS += -static
 t_isfine_LDFLAGS += -static
diff --git a/mingw-w64-crt/testcases/t_cpp_dtor_atexit_order.cpp b/mingw-w64-crt/testcases/t_cpp_dtor_atexit_order.cpp
new file mode 100644
index 0000000..dce7641
--- /dev/null
+++ b/mingw-w64-crt/testcases/t_cpp_dtor_atexit_order.cpp
@@ -0,0 +1,53 @@
+#include <cstdio>
+#include <cstdlib>
+
+/* mingw-w64 headers */
+#ifdef __MINGW64_VERSION_MAJOR
+#include "libtest.h"
+#endif
+
+template <void (*callback)()> struct dtor_callback { ~dtor_callback() { callback(); } };
+
+bool main_success = false;
+
+void cpp_tls_dtor_func() {
+    std::puts("C++ tls dtor func called");
+    if (!main_success) {
+        std::_Exit(1);
+    }
+    std::puts("TEST PASSED");
+    std::_Exit(0);
+}
+template struct dtor_callback<&cpp_tls_dtor_func>;
+thread_local dtor_callback<&cpp_tls_dtor_func> register_tls_dtor_callback;
+
+void atexit_func() {
+    std::puts("atexit func called");
+    std::puts("TEST FAILED");
+    main_success = false;
+    std::_Exit(1);
+}
+
+int main() {
+#ifdef __MINGW64_VERSION_MAJOR
+    mingw_test_init();
+#endif
+
+    /* For some unknown reasons, this test is passing under mingw-w64 clang and under linux gcc but is failing under mingw-w64 gcc */
+#if defined(__MINGW64_VERSION_MAJOR) && !defined(__clang__)
+    return 77;
+#endif
+
+    std::puts("registering atexit func");
+    std::atexit(atexit_func);
+
+    std::puts("referencing C++ TLS obj");
+    (void)register_tls_dtor_callback;
+
+    std::puts("registering atexit func");
+    std::atexit(atexit_func);
+
+    std::puts("returning from main");
+    main_success = true;
+    return 1;
+}