Loading...
testing/test-cases/thread-local-atexit-macOS.dtest/main.cpp /dev/null dyld-733.8
--- /dev/null
+++ dyld/dyld-733.8/testing/test-cases/thread-local-atexit-macOS.dtest/main.cpp
@@ -0,0 +1,115 @@
+// BUILD_ONLY: MacOSX
+
+// BUILD:  $CXX main.cpp -std=c++11 -o $BUILD_DIR/thread-local-atexit-macOS.exe
+
+// RUN:  ./thread-local-atexit-macOS.exe
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+// We create an A and a B.
+// While destroying B we create a C
+// Given that tlv_finalize has "destroy in reverse order of construction", we
+// must then immediately destroy C before we destroy A to maintain that invariant
+
+enum State {
+    None,
+    ConstructedA,
+    ConstructedB,
+    ConstructedC,
+    DestroyingB,
+    DestroyedA,
+    DestroyedB,
+    DestroyedC,
+};
+
+struct A {
+    A();
+    ~A();
+};
+
+struct B {
+    B();
+    ~B();
+};
+
+struct C {
+    C();
+    ~C();
+};
+
+State state;
+
+A::A() {
+    if ( state != None ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'None' state\n");
+    }
+    state = ConstructedA;
+}
+
+B::B() {
+    if ( state != ConstructedA ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'ConstructedA' state\n");
+        _Exit(0);
+    }
+    state = ConstructedB;
+}
+
+C::C() {
+    // We construct C during B's destructor
+    if ( state != DestroyingB ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'DestroyingB' state\n");
+        _Exit(0);
+    }
+    state = ConstructedC;
+}
+
+// We destroy B first
+B::~B() {
+    if ( state != ConstructedB ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'ConstructedB' state\n");
+        _Exit(0);
+    }
+    state = DestroyingB;
+    static thread_local C c;
+    if ( state != ConstructedC ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'ConstructedC' state\n");
+        _Exit(0);
+    }
+    state = DestroyedB;
+}
+
+// Then we destroy C
+C::~C() {
+    if ( state != DestroyedB ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'DestroyedB' state\n");
+        _Exit(0);
+    }
+    state = DestroyedC;
+}
+
+// And finally destroy A
+A::~A() {
+    if ( state != DestroyedC ) {
+        printf("[FAIL] thread-local-atexit-macOS: should be in the 'DestroyedC' state\n");
+        _Exit(0);
+    }
+    state = DestroyedA;
+    printf("[PASS] thread-local-atexit-macOS\n");
+}
+
+static void work()
+{
+    thread_local A a = {};
+    thread_local B b = {};
+}
+
+int main() {
+    printf("[BEGIN] thread-local-atexit-macOS\n");
+
+    work();
+
+    return 0;
+}
+