aboutsummaryrefslogtreecommitdiff
path: root/libphobos/testsuite/libphobos.shared
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
committerIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
commitb4c522fabd0df7be08882d2207df8b2765026110 (patch)
treeb5ffc312b0a441c1ba24323152aec463fdbe5e9f /libphobos/testsuite/libphobos.shared
parent01ce9e31a02c8039d88e90f983735104417bf034 (diff)
downloadgcc-b4c522fabd0df7be08882d2207df8b2765026110.zip
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.gz
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.bz2
Add D front-end, libphobos library, and D2 testsuite.
ChangeLog: * Makefile.def (target_modules): Add libphobos. (flags_to_pass): Add GDC, GDCFLAGS, GDC_FOR_TARGET and GDCFLAGS_FOR_TARGET. (dependencies): Make libphobos depend on libatomic, libbacktrace configure, and zlib configure. (language): Add language d. * Makefile.in: Rebuild. * Makefile.tpl (BUILD_EXPORTS): Add GDC and GDCFLAGS. (HOST_EXPORTS): Add GDC. (POSTSTAGE1_HOST_EXPORTS): Add GDC and GDC_FOR_BUILD. (BASE_TARGET_EXPORTS): Add GDC. (GDC_FOR_BUILD, GDC, GDCFLAGS): New variables. (GDC_FOR_TARGET, GDC_FLAGS_FOR_TARGET): New variables. (EXTRA_HOST_FLAGS): Add GDC. (STAGE1_FLAGS_TO_PASS): Add GDC. (EXTRA_TARGET_FLAGS): Add GDC and GDCFLAGS. * config-ml.in: Treat GDC and GDCFLAGS like other compiler/flag environment variables. * configure: Rebuild. * configure.ac: Add target-libphobos to target_libraries. Set and substitute GDC_FOR_BUILD and GDC_FOR_TARGET. config/ChangeLog: * multi.m4: Set GDC. gcc/ChangeLog: * Makefile.in (tm_d_file_list, tm_d_include_list): New variables. (TM_D_H, D_TARGET_DEF, D_TARGET_H, D_TARGET_OBJS): New variables. (tm_d.h, cs-tm_d.h, default-d.o): New rules. (d/d-target-hooks-def.h, s-d-target-hooks-def-h): New rules. (s-tm-texi): Also check timestamp on d-target.def. (generated_files): Add TM_D_H and d-target-hooks-def.h. (build/genhooks.o): Also depend on D_TARGET_DEF. * config.gcc (tm_d_file, d_target_objs, target_has_targetdm): New variables. * config/aarch64/aarch64-d.c: New file. * config/aarch64/aarch64-linux.h (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/aarch64/aarch64-protos.h (aarch64_d_target_versions): New prototype. * config/aarch64/aarch64.h (TARGET_D_CPU_VERSIONS): Define. * config/aarch64/t-aarch64 (aarch64-d.o): New rule. * config/arm/arm-d.c: New file. * config/arm/arm-protos.h (arm_d_target_versions): New prototype. * config/arm/arm.h (TARGET_D_CPU_VERSIONS): Define. * config/arm/linux-eabi.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/arm/t-arm (arm-d.o): New rule. * config/default-d.c: New file. * config/glibc-d.c: New file. * config/gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/i386/i386-d.c: New file. * config/i386/i386-protos.h (ix86_d_target_versions): New prototype. * config/i386/i386.h (TARGET_D_CPU_VERSIONS): Define. * config/i386/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/i386/t-i386 (i386-d.o): New rule. * config/kfreebsd-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/kopensolaris-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/linux-android.h (ANDROID_TARGET_D_OS_VERSIONS): Define. * config/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/mips/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/mips/mips-d.c: New file. * config/mips/mips-protos.h (mips_d_target_versions): New prototype. * config/mips/mips.h (TARGET_D_CPU_VERSIONS): Define. * config/mips/t-mips (mips-d.o): New rule. * config/powerpcspe/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/powerpcspe-d.c: New file. * config/powerpcspe/powerpcspe-protos.h (rs6000_d_target_versions): New prototype. * config/powerpcspe/powerpcspe.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/powerpcspe/powerpcspe.h (TARGET_D_CPU_VERSIONS): Define. * config/powerpcspe/t-powerpcspe (powerpcspe-d.o): New rule. * config/riscv/riscv-d.c: New file. * config/riscv/riscv-protos.h (riscv_d_target_versions): New prototype. * config/riscv/riscv.h (TARGET_D_CPU_VERSIONS): Define. * config/riscv/t-riscv (riscv-d.o): New rule. * config/rs6000/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/rs6000-d.c: New file. * config/rs6000/rs6000-protos.h (rs6000_d_target_versions): New prototype. * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/rs6000/rs6000.h (TARGET_D_CPU_VERSIONS): Define. * config/rs6000/t-rs6000 (rs6000-d.o): New rule. * config/s390/s390-d.c: New file. * config/s390/s390-protos.h (s390_d_target_versions): New prototype. * config/s390/s390.h (TARGET_D_CPU_VERSIONS): Define. * config/s390/t-s390 (s390-d.o): New rule. * config/sparc/sparc-d.c: New file. * config/sparc/sparc-protos.h (sparc_d_target_versions): New prototype. * config/sparc/sparc.h (TARGET_D_CPU_VERSIONS): Define. * config/sparc/t-sparc (sparc-d.o): New rule. * config/t-glibc (glibc-d.o): New rule. * configure: Regenerated. * configure.ac (tm_d_file): New variable. (tm_d_file_list, tm_d_include_list, d_target_objs): Add substitutes. * doc/contrib.texi (Contributors): Add self for the D frontend. * doc/frontends.texi (G++ and GCC): Mention D as a supported language. * doc/install.texi (Configuration): Mention libphobos as an option for --enable-shared. Mention d as an option for --enable-languages. (Testing): Mention check-d as a target. * doc/invoke.texi (Overall Options): Mention .d, .dd, and .di as file name suffixes. Mention d as a -x option. * doc/sourcebuild.texi (Top Level): Mention libphobos. * doc/standards.texi (Standards): Add section on D language. * doc/tm.texi: Regenerated. * doc/tm.texi.in: Add @node for D language and ABI, and @hook for TARGET_CPU_VERSIONS, TARGET_D_OS_VERSIONS, and TARGET_D_CRITSEC_SIZE. * dwarf2out.c (is_dlang): New function. (gen_compile_unit_die): Use DW_LANG_D for D. (declare_in_namespace): Return module die for D, instead of adding extra declarations into the namespace. (gen_namespace_die): Generate DW_TAG_module for D. (gen_decl_die): Handle CONST_DECLSs for D. (dwarf2out_decl): Likewise. (prune_unused_types_walk_local_classes): Handle DW_tag_interface_type. (prune_unused_types_walk): Handle DW_tag_interface_type same as other kinds of aggregates. * gcc.c (default_compilers): Add entries for .d, .dd and .di. * genhooks.c: Include d/d-target.def. gcc/po/ChangeLog: * EXCLUDES: Add sources from d/dmd. gcc/testsuite/ChangeLog: * gcc.misc-tests/help.exp: Add D to option descriptions check. * gdc.dg/asan/asan.exp: New file. * gdc.dg/asan/gdc272.d: New test. * gdc.dg/compilable.d: New test. * gdc.dg/dg.exp: New file. * gdc.dg/gdc254.d: New test. * gdc.dg/gdc260.d: New test. * gdc.dg/gdc270a.d: New test. * gdc.dg/gdc270b.d: New test. * gdc.dg/gdc282.d: New test. * gdc.dg/gdc283.d: New test. * gdc.dg/imports/gdc170.d: New test. * gdc.dg/imports/gdc231.d: New test. * gdc.dg/imports/gdc239.d: New test. * gdc.dg/imports/gdc241a.d: New test. * gdc.dg/imports/gdc241b.d: New test. * gdc.dg/imports/gdc251a.d: New test. * gdc.dg/imports/gdc251b.d: New test. * gdc.dg/imports/gdc253.d: New test. * gdc.dg/imports/gdc254a.d: New test. * gdc.dg/imports/gdc256.d: New test. * gdc.dg/imports/gdc27.d: New test. * gdc.dg/imports/gdcpkg256/package.d: New test. * gdc.dg/imports/runnable.d: New test. * gdc.dg/link.d: New test. * gdc.dg/lto/lto.exp: New file. * gdc.dg/lto/ltotests_0.d: New test. * gdc.dg/lto/ltotests_1.d: New test. * gdc.dg/runnable.d: New test. * gdc.dg/simd.d: New test. * gdc.test/gdc-test.exp: New file. * lib/gdc-dg.exp: New file. * lib/gdc.exp: New file. libphobos/ChangeLog: * Makefile.am: New file. * Makefile.in: New file. * acinclude.m4: New file. * aclocal.m4: New file. * config.h.in: New file. * configure: New file. * configure.ac: New file. * d_rules.am: New file. * libdruntime/Makefile.am: New file. * libdruntime/Makefile.in: New file. * libdruntime/__entrypoint.di: New file. * libdruntime/__main.di: New file. * libdruntime/gcc/attribute.d: New file. * libdruntime/gcc/backtrace.d: New file. * libdruntime/gcc/builtins.d: New file. * libdruntime/gcc/config.d.in: New file. * libdruntime/gcc/deh.d: New file. * libdruntime/gcc/libbacktrace.d.in: New file. * libdruntime/gcc/unwind/arm.d: New file. * libdruntime/gcc/unwind/arm_common.d: New file. * libdruntime/gcc/unwind/c6x.d: New file. * libdruntime/gcc/unwind/generic.d: New file. * libdruntime/gcc/unwind/package.d: New file. * libdruntime/gcc/unwind/pe.d: New file. * m4/autoconf.m4: New file. * m4/druntime.m4: New file. * m4/druntime/cpu.m4: New file. * m4/druntime/libraries.m4: New file. * m4/druntime/os.m4: New file. * m4/gcc_support.m4: New file. * m4/gdc.m4: New file. * m4/libtool.m4: New file. * src/Makefile.am: New file. * src/Makefile.in: New file. * src/libgphobos.spec.in: New file. * testsuite/Makefile.am: New file. * testsuite/Makefile.in: New file. * testsuite/config/default.exp: New file. * testsuite/lib/libphobos-dg.exp: New file. * testsuite/lib/libphobos.exp: New file. * testsuite/testsuite_flags.in: New file. From-SVN: r265573
Diffstat (limited to 'libphobos/testsuite/libphobos.shared')
-rw-r--r--libphobos/testsuite/libphobos.shared/finalize.d63
-rw-r--r--libphobos/testsuite/libphobos.shared/host.c60
-rw-r--r--libphobos/testsuite/libphobos.shared/lib.d133
-rw-r--r--libphobos/testsuite/libphobos.shared/lib_13414.d4
-rw-r--r--libphobos/testsuite/libphobos.shared/liblinkdep.d6
-rw-r--r--libphobos/testsuite/libphobos.shared/libloaddep.d13
-rw-r--r--libphobos/testsuite/libphobos.shared/link.d64
-rw-r--r--libphobos/testsuite/libphobos.shared/linkD.c14
-rw-r--r--libphobos/testsuite/libphobos.shared/linkDR.c28
-rw-r--r--libphobos/testsuite/libphobos.shared/link_linkdep.d6
-rw-r--r--libphobos/testsuite/libphobos.shared/link_loaddep.d7
-rw-r--r--libphobos/testsuite/libphobos.shared/link_mod_collision.d5
-rw-r--r--libphobos/testsuite/libphobos.shared/load.d147
-rw-r--r--libphobos/testsuite/libphobos.shared/loadDR.c39
-rw-r--r--libphobos/testsuite/libphobos.shared/load_13414.d30
-rw-r--r--libphobos/testsuite/libphobos.shared/load_linkdep.d18
-rw-r--r--libphobos/testsuite/libphobos.shared/load_loaddep.d17
-rw-r--r--libphobos/testsuite/libphobos.shared/load_mod_collision.d14
-rw-r--r--libphobos/testsuite/libphobos.shared/plugin.d73
-rw-r--r--libphobos/testsuite/libphobos.shared/shared.exp108
20 files changed, 849 insertions, 0 deletions
diff --git a/libphobos/testsuite/libphobos.shared/finalize.d b/libphobos/testsuite/libphobos.shared/finalize.d
new file mode 100644
index 0000000..f31b818
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/finalize.d
@@ -0,0 +1,63 @@
+import core.runtime;
+import core.stdc.stdio;
+import core.stdc.string;
+import core.thread;
+import core.sys.posix.dlfcn;
+
+void runTest()
+{
+ Object obj;
+ obj = Object.factory("lib.MyFinalizer");
+ assert(obj.toString() == "lib.MyFinalizer");
+ obj = Object.factory("lib.MyFinalizerBig");
+ assert(obj.toString() == "lib.MyFinalizerBig");
+}
+
+class NoFinalize
+{
+ size_t _finalizeCounter;
+
+ ~this()
+ {
+ ++_finalizeCounter;
+ }
+}
+
+class NoFinalizeBig : NoFinalize
+{
+ ubyte[4096] _big = void;
+}
+
+extern (C) alias SetFinalizeCounter = void function(shared(size_t*));
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ name = name[0 .. pathlen] ~ "lib.so";
+
+ auto h = Runtime.loadLibrary(name);
+ assert(h !is null);
+
+ auto nf1 = new NoFinalize;
+ auto nf2 = new NoFinalizeBig;
+
+ shared size_t finalizeCounter;
+ auto setFinalizeCounter = cast(SetFinalizeCounter)dlsym(h, "setFinalizeCounter");
+ setFinalizeCounter(&finalizeCounter);
+
+ runTest();
+ auto thr = new Thread(&runTest);
+ thr.start();
+ thr.join();
+
+ auto r = Runtime.unloadLibrary(h);
+ if (!r)
+ assert(0);
+ if (finalizeCounter != 4)
+ assert(0);
+ if (nf1._finalizeCounter)
+ assert(0);
+ if (nf2._finalizeCounter)
+ assert(0);
+}
diff --git a/libphobos/testsuite/libphobos.shared/host.c b/libphobos/testsuite/libphobos.shared/host.c
new file mode 100644
index 0000000..81e896a
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/host.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+int main(int argc, char* argv[])
+{
+#if defined(__FreeBSD__)
+ // workaround for Bugzilla 14824
+ void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime
+ assert(druntime);
+#endif
+
+ const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1;
+ char *name = malloc(pathlen + sizeof("plugin1.so"));
+ memcpy(name, argv[0], pathlen);
+ memcpy(name+pathlen, "plugin1.so", sizeof("plugin1.so"));
+
+ void* plugin1 = dlopen(name, RTLD_LAZY);
+ name[pathlen + sizeof("plugin1.so") - 5] = '2';
+ void* plugin2 = dlopen(name, RTLD_LAZY);
+
+ int (*plugin1_init)() = dlsym(plugin1, "plugin_init");
+ int (*plugin1_term)() = dlsym(plugin1, "plugin_term");
+ int (*runTests1)() = dlsym(plugin1, "runTests");
+ int (*plugin2_init)() = dlsym(plugin2, "plugin_init");
+ int (*plugin2_term)() = dlsym(plugin2, "plugin_term");
+ int (*runTests2)() = dlsym(plugin2, "runTests");
+ assert(plugin1_init());
+ assert(runTests1());
+ assert(plugin2_init());
+ assert(runTests2());
+
+ assert(plugin1_term());
+ assert(dlclose(plugin1) == 0);
+ assert(runTests2());
+
+ name[pathlen + sizeof("plugin1.so") - 5] = '1';
+ plugin1 = dlopen(name, RTLD_LAZY);
+ plugin1_init = dlsym(plugin1, "plugin_init");
+ plugin1_term = dlsym(plugin1, "plugin_term");
+ runTests1 = dlsym(plugin1, "runTests");
+ assert(plugin1_init());
+ assert(runTests1());
+ assert(runTests2());
+
+ assert(plugin2_term());
+ assert(dlclose(plugin2) == 0);
+ assert(runTests1());
+
+ assert(plugin1_term());
+ assert(dlclose(plugin1) == 0);
+
+ free(name);
+
+#if defined(__FreeBSD__)
+ dlclose(druntime);
+#endif
+ return EXIT_SUCCESS;
+}
diff --git a/libphobos/testsuite/libphobos.shared/lib.d b/libphobos/testsuite/libphobos.shared/lib.d
new file mode 100644
index 0000000..0e4eb44
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/lib.d
@@ -0,0 +1,133 @@
+module lib;
+
+// test EH
+void throwException()
+{
+ throw new Exception(null);
+}
+
+Exception collectException(void delegate() dg)
+{
+ try
+ dg();
+ catch (Exception e)
+ return e;
+ return null;
+}
+
+// test GC
+__gshared Object root;
+void alloc() { root = new Object(); }
+void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized
+void free() { root = null; }
+
+Object tls_root;
+void tls_alloc() { tls_root = new Object(); }
+void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized
+void tls_free() { tls_root = null; }
+
+void stack(alias func)()
+{
+ // allocate some extra stack space to not keep references to GC memory on the scanned stack
+ ubyte[1024] buf = void;
+ func();
+}
+
+void testGC()
+{
+ import core.memory;
+
+ stack!alloc();
+ stack!tls_alloc();
+ stack!access();
+ stack!tls_access();
+ GC.collect();
+ stack!tls_access();
+ stack!access();
+ stack!tls_free();
+ stack!free();
+}
+
+// test Init
+import core.atomic : atomicOp;
+shared uint shared_static_ctor, shared_static_dtor, static_ctor, static_dtor;
+shared static this() { if (atomicOp!"+="(shared_static_ctor, 1) != 1) assert(0); }
+shared static ~this() { if (atomicOp!"+="(shared_static_dtor, 1) != 1) assert(0); }
+static this() { atomicOp!"+="(static_ctor, 1); }
+static ~this() { atomicOp!"+="(static_dtor, 1); }
+
+extern(C) int runTests()
+{
+ try
+ runTestsImpl();
+ catch (Throwable)
+ return 0;
+ return 1;
+}
+
+void runTestsImpl()
+{
+ import core.thread;
+
+ bool passed;
+ try
+ throwException();
+ catch (Exception e)
+ passed = true;
+ assert(passed);
+ assert(collectException({throwException();}) !is null);
+
+ testGC();
+
+ assert(shared_static_ctor == 1);
+ assert(static_ctor == 1);
+ static void run()
+ {
+ assert(static_ctor == 2);
+ assert(shared_static_ctor == 1);
+ testGC();
+ }
+ auto thr = new Thread(&run);
+ thr.start();
+ thr.join();
+ assert(static_dtor == 1);
+
+ passed = false;
+ foreach (m; ModuleInfo)
+ if (m.name == "lib") passed = true;
+ assert(passed);
+}
+
+// Provide a way to initialize D from C programs that are D agnostic.
+import core.runtime : rt_init, rt_term;
+
+extern(C) int lib_init()
+{
+ return rt_init();
+}
+
+extern(C) int lib_term()
+{
+ return rt_term();
+}
+
+shared size_t* _finalizeCounter;
+
+class MyFinalizer
+{
+ ~this()
+ {
+ import core.atomic;
+ atomicOp!"+="(*_finalizeCounter, 1);
+ }
+}
+
+class MyFinalizerBig : MyFinalizer
+{
+ ubyte[4096] _big = void;
+}
+
+extern(C) void setFinalizeCounter(shared(size_t)* p)
+{
+ _finalizeCounter = p;
+}
diff --git a/libphobos/testsuite/libphobos.shared/lib_13414.d b/libphobos/testsuite/libphobos.shared/lib_13414.d
new file mode 100644
index 0000000..2859438
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/lib_13414.d
@@ -0,0 +1,4 @@
+shared void function() sharedStaticDtorHook;
+shared void function() staticDtorHook;
+shared static ~this() { sharedStaticDtorHook(); }
+static ~this() { staticDtorHook(); }
diff --git a/libphobos/testsuite/libphobos.shared/liblinkdep.d b/libphobos/testsuite/libphobos.shared/liblinkdep.d
new file mode 100644
index 0000000..c2d2cc6
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/liblinkdep.d
@@ -0,0 +1,6 @@
+import lib;
+
+extern(C) int runDepTests()
+{
+ return runTests();
+}
diff --git a/libphobos/testsuite/libphobos.shared/libloaddep.d b/libphobos/testsuite/libphobos.shared/libloaddep.d
new file mode 100644
index 0000000..93a2dab
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/libloaddep.d
@@ -0,0 +1,13 @@
+import core.runtime, core.sys.posix.dlfcn;
+
+extern(C) alias RunTests = int function();
+
+extern(C) int runDepTests(const char* name)
+{
+ auto h = rt_loadLibrary(name);
+ if (h is null) return false;
+ auto runTests = cast(RunTests).dlsym(h, "runTests");
+ assert(runTests !is null);
+ if (!runTests()) return false;
+ return rt_unloadLibrary(h);
+}
diff --git a/libphobos/testsuite/libphobos.shared/link.d b/libphobos/testsuite/libphobos.shared/link.d
new file mode 100644
index 0000000..433da66
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/link.d
@@ -0,0 +1,64 @@
+import lib;
+
+void testEH()
+{
+ bool passed;
+ try
+ lib.throwException();
+ catch (Exception e)
+ passed = true;
+ assert(passed); passed = false;
+
+ assert(lib.collectException({throw new Exception(null);}) !is null);
+ assert(lib.collectException({lib.throwException();}) !is null);
+}
+
+void testGC()
+{
+ import core.memory;
+ lib.alloc();
+ lib.tls_alloc();
+ lib.access();
+ lib.tls_access();
+ GC.collect();
+ lib.tls_access();
+ lib.access();
+ lib.tls_free();
+ lib.free();
+}
+
+import core.atomic : atomicOp;
+shared static this() { assert(lib.shared_static_ctor == 1); }
+shared static ~this() { assert(lib.shared_static_dtor == 0); }
+shared uint static_ctor, static_dtor;
+static this() { assert(lib.static_ctor == atomicOp!"+="(static_ctor, 1)); }
+static ~this() { assert(lib.static_dtor + 1 == atomicOp!"+="(static_dtor, 1)); }
+
+void testInit()
+{
+ import core.thread;
+
+ assert(lib.static_ctor == 1);
+ assert(lib.static_dtor == 0);
+ static void foo()
+ {
+ assert(lib.shared_static_ctor == 1);
+ assert(lib.shared_static_dtor == 0);
+ assert(lib.static_ctor == 2);
+ assert(lib.static_dtor == 0);
+ }
+ auto thr = new Thread(&foo);
+ thr.start();
+ assert(thr.join() is null);
+ assert(lib.shared_static_ctor == 1);
+ assert(lib.shared_static_dtor == 0);
+ assert(lib.static_ctor == 2);
+ assert(lib.static_dtor == 1);
+}
+
+void main()
+{
+ testEH();
+ testGC();
+ testInit();
+}
diff --git a/libphobos/testsuite/libphobos.shared/linkD.c b/libphobos/testsuite/libphobos.shared/linkD.c
new file mode 100644
index 0000000..657c9e8
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/linkD.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <assert.h>
+
+extern int runTests(void);
+extern int lib_init(void);
+extern int lib_term(void);
+
+int main(int argc, char* argv[])
+{
+ if (!lib_init()) return EXIT_SUCCESS;
+ const int res = runTests() ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (!lib_term()) return EXIT_FAILURE;
+ return res;
+}
diff --git a/libphobos/testsuite/libphobos.shared/linkDR.c b/libphobos/testsuite/libphobos.shared/linkDR.c
new file mode 100644
index 0000000..924709c
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/linkDR.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+extern void* rt_loadLibrary(const char*);
+extern int rt_unloadLibrary(void*);
+extern int rt_init(void);
+extern int rt_term(void);
+
+int main(int argc, char* argv[])
+{
+ if (!rt_init()) return EXIT_FAILURE;
+ const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1;
+ char *name = malloc(pathlen + sizeof("lib.so"));
+ memcpy(name, argv[0], pathlen);
+ memcpy(name+pathlen, "lib.so", sizeof("lib.so"));
+
+ void *dlib = rt_loadLibrary(name);
+ free(name);
+ assert(dlib);
+
+ int (*runTests)(void) = dlsym(dlib, "runTests");
+ assert(runTests());
+ assert(rt_unloadLibrary(dlib));
+ if (!rt_term()) return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
diff --git a/libphobos/testsuite/libphobos.shared/link_linkdep.d b/libphobos/testsuite/libphobos.shared/link_linkdep.d
new file mode 100644
index 0000000..ca72e7e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/link_linkdep.d
@@ -0,0 +1,6 @@
+import liblinkdep;
+
+void main()
+{
+ runDepTests();
+}
diff --git a/libphobos/testsuite/libphobos.shared/link_loaddep.d b/libphobos/testsuite/libphobos.shared/link_loaddep.d
new file mode 100644
index 0000000..8e0c58e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/link_loaddep.d
@@ -0,0 +1,7 @@
+import libloaddep;
+
+void main(string[] args)
+{
+ auto libname = args[0][0..$-"link_loaddep".length] ~ "lib.so\0";
+ runDepTests(libname.ptr);
+}
diff --git a/libphobos/testsuite/libphobos.shared/link_mod_collision.d b/libphobos/testsuite/libphobos.shared/link_mod_collision.d
new file mode 100644
index 0000000..9c3d1c7
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/link_mod_collision.d
@@ -0,0 +1,5 @@
+module lib; // module collides with lib.so
+
+void main()
+{
+}
diff --git a/libphobos/testsuite/libphobos.shared/load.d b/libphobos/testsuite/libphobos.shared/load.d
new file mode 100644
index 0000000..8c13f51
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/load.d
@@ -0,0 +1,147 @@
+import core.runtime;
+import core.stdc.stdio;
+import core.stdc.string;
+import core.thread;
+
+version (linux) import core.sys.linux.dlfcn;
+else version (FreeBSD) import core.sys.freebsd.dlfcn;
+else version (NetBSD) import core.sys.netbsd.dlfcn;
+else static assert(0, "unimplemented");
+
+void loadSym(T)(void* handle, ref T val, const char* mangle)
+{
+ val = cast(T).dlsym(handle, mangle);
+}
+
+void* openLib(string s)
+{
+ auto h = Runtime.loadLibrary(s);
+ assert(h !is null);
+
+ loadSym(h, libThrowException, "_D3lib14throwExceptionFZv");
+ loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception");
+
+ loadSym(h, libAlloc, "_D3lib5allocFZv");
+ loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv");
+ loadSym(h, libAccess, "_D3lib6accessFZv");
+ loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv");
+ loadSym(h, libFree, "_D3lib4freeFZv");
+ loadSym(h, libTlsFree, "_D3lib8tls_freeFZv");
+
+ loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk");
+ loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk");
+ loadSym(h, libStaticCtor, "_D3lib11static_ctorOk");
+ loadSym(h, libStaticDtor, "_D3lib11static_dtorOk");
+
+ return h;
+}
+
+void closeLib(void* h)
+{
+ Runtime.unloadLibrary(h);
+}
+
+__gshared
+{
+ void function() libThrowException;
+ Exception function(void delegate()) libCollectException;
+
+ void function() libAlloc;
+ void function() libTlsAlloc;
+ void function() libAccess;
+ void function() libTlsAccess;
+ void function() libFree;
+ void function() libTlsFree;
+
+ shared uint* libSharedStaticCtor;
+ shared uint* libSharedStaticDtor;
+ shared uint* libStaticCtor;
+ shared uint* libStaticDtor;
+}
+
+void testEH()
+{
+ bool passed;
+ try
+ libThrowException();
+ catch (Exception e)
+ passed = true;
+ assert(passed); passed = false;
+
+ assert(libCollectException({throw new Exception(null);}) !is null);
+ assert(libCollectException({libThrowException();}) !is null);
+}
+
+void testGC()
+{
+ import core.memory;
+ libAlloc();
+ libTlsAlloc();
+ libAccess();
+ libTlsAccess();
+ GC.collect();
+ libTlsAccess();
+ libAccess();
+ libTlsFree();
+ libFree();
+}
+
+void testInit()
+{
+
+ assert(*libStaticCtor == 1);
+ assert(*libStaticDtor == 0);
+ static void run()
+ {
+ assert(*libSharedStaticCtor == 1);
+ assert(*libSharedStaticDtor == 0);
+ assert(*libStaticCtor == 2);
+ assert(*libStaticDtor == 0);
+ }
+ auto thr = new Thread(&run);
+ thr.start();
+ thr.join();
+ assert(*libSharedStaticCtor == 1);
+ assert(*libSharedStaticDtor == 0);
+ assert(*libStaticCtor == 2);
+ assert(*libStaticDtor == 1);
+}
+
+const(ModuleInfo)* findModuleInfo(string name)
+{
+ foreach (m; ModuleInfo)
+ if (m.name == name) return m;
+ return null;
+}
+
+void runTests(string libName)
+{
+ assert(findModuleInfo("lib") is null);
+ auto handle = openLib(libName);
+ assert(findModuleInfo("lib") !is null);
+
+ testEH();
+ testGC();
+ testInit();
+
+ closeLib(handle);
+ assert(findModuleInfo("lib") is null);
+}
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ name = name[0 .. pathlen] ~ "lib.so";
+
+ runTests(name);
+
+ // lib is no longer resident
+ name ~= '\0';
+ assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null);
+ name = name[0 .. $-1];
+
+ auto thr = new Thread({runTests(name);});
+ thr.start();
+ thr.join();
+}
diff --git a/libphobos/testsuite/libphobos.shared/loadDR.c b/libphobos/testsuite/libphobos.shared/loadDR.c
new file mode 100644
index 0000000..08508cbc
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/loadDR.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ return EXIT_FAILURE;
+ void *h = dlopen(argv[1], RTLD_LAZY); // load druntime
+ assert(h != NULL);
+
+ int (*rt_init)(void) = dlsym(h, "rt_init");
+ int (*rt_term)(void) = dlsym(h, "rt_term");
+ void* (*rt_loadLibrary)(const char*) = dlsym(h, "rt_loadLibrary");
+ int (*rt_unloadLibrary)(void*) = dlsym(h, "rt_unloadLibrary");
+
+ int res = EXIT_FAILURE;
+ if (!rt_init()) goto Lexit;
+
+ const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1;
+ char *name = malloc(pathlen + sizeof("lib.so"));
+ memcpy(name, argv[0], pathlen);
+ memcpy(name+pathlen, "lib.so", sizeof("lib.so"));
+
+ void *dlib = rt_loadLibrary(name);
+ free(name);
+ assert(dlib);
+
+ int (*runTests)(void) = dlsym(dlib, "runTests");
+ assert(runTests());
+ assert(rt_unloadLibrary(dlib));
+
+ if (rt_term()) res = EXIT_SUCCESS;
+
+Lexit:
+ assert(dlclose(h) == 0);
+ return res;
+}
diff --git a/libphobos/testsuite/libphobos.shared/load_13414.d b/libphobos/testsuite/libphobos.shared/load_13414.d
new file mode 100644
index 0000000..f7cbf45
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/load_13414.d
@@ -0,0 +1,30 @@
+import core.runtime;
+import core.atomic;
+import core.stdc.string;
+import core.sys.posix.dlfcn;
+
+shared uint tlsDtor, dtor;
+void staticDtorHook() { atomicOp!"+="(tlsDtor, 1); }
+void sharedStaticDtorHook() { atomicOp!"+="(dtor, 1); }
+
+void runTest(string name)
+{
+ auto h = Runtime.loadLibrary(name);
+ assert(h !is null);
+
+ *cast(void function()*).dlsym(h, "_D9lib_1341414staticDtorHookOPFZv") = &staticDtorHook;
+ *cast(void function()*).dlsym(h, "_D9lib_1341420sharedStaticDtorHookOPFZv") = &sharedStaticDtorHook;
+
+ Runtime.unloadLibrary(h);
+ assert(tlsDtor == 1);
+ assert(dtor == 1);
+}
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ name = name[0 .. pathlen] ~ "lib_13414.so";
+
+ runTest(name);
+}
diff --git a/libphobos/testsuite/libphobos.shared/load_linkdep.d b/libphobos/testsuite/libphobos.shared/load_linkdep.d
new file mode 100644
index 0000000..5f5dcf2
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/load_linkdep.d
@@ -0,0 +1,18 @@
+import core.runtime;
+import core.stdc.string;
+import core.sys.posix.dlfcn;
+
+extern(C) alias RunDepTests = int function();
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ name = name[0 .. pathlen] ~ "liblinkdep.so";
+
+ auto h = Runtime.loadLibrary(name);
+ assert(h);
+ auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests");
+ assert(runDepTests());
+ assert(Runtime.unloadLibrary(h));
+}
diff --git a/libphobos/testsuite/libphobos.shared/load_loaddep.d b/libphobos/testsuite/libphobos.shared/load_loaddep.d
new file mode 100644
index 0000000..c189683e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/load_loaddep.d
@@ -0,0 +1,17 @@
+import core.runtime;
+import core.stdc.string;
+import core.sys.posix.dlfcn;
+
+extern(C) alias RunDepTests = int function(const char*);
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ auto root = name[0 .. pathlen];
+ auto libloaddep = root ~ "libloaddep.so";
+ auto h = Runtime.loadLibrary(libloaddep);
+ auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests");
+ assert(runDepTests((root ~ "lib.so\0").ptr));
+ assert(Runtime.unloadLibrary(h));
+}
diff --git a/libphobos/testsuite/libphobos.shared/load_mod_collision.d b/libphobos/testsuite/libphobos.shared/load_mod_collision.d
new file mode 100644
index 0000000..64243d4
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/load_mod_collision.d
@@ -0,0 +1,14 @@
+module lib; // module collides with lib.so
+
+import core.runtime;
+import core.stdc.stdio;
+import core.stdc.string;
+import core.sys.posix.dlfcn;
+
+void main(string[] args)
+{
+ auto name = args[0] ~ '\0';
+ const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
+ name = name[0 .. pathlen] ~ "lib.so";
+ auto lib = Runtime.loadLibrary(name);
+}
diff --git a/libphobos/testsuite/libphobos.shared/plugin.d b/libphobos/testsuite/libphobos.shared/plugin.d
new file mode 100644
index 0000000..74d6601
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/plugin.d
@@ -0,0 +1,73 @@
+import core.thread, core.memory, core.atomic;
+
+// test init
+shared uint gctor, gdtor, tctor, tdtor;
+shared static this() { if (atomicOp!"+="(gctor, 1) != 1) assert(0); }
+shared static ~this() { if (atomicOp!"+="(gdtor, 1) != 1) assert(0); }
+static this() { atomicOp!"+="(tctor, 1); }
+static ~this() { atomicOp!"+="(tdtor, 1); }
+
+// test GC
+__gshared Object root;
+void alloc() { root = new Object(); }
+void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized
+void free() { root = null; }
+
+Object tls_root;
+void tls_alloc() { tls_root = new Object(); }
+void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized
+void tls_free() { tls_root = null; }
+
+void stack(alias func)()
+{
+ // allocate some extra stack space to not keep references to GC memory on the scanned stack
+ ubyte[1024] buf = void;
+ func();
+}
+
+void testGC()
+{
+ import core.memory;
+
+ stack!alloc();
+ stack!tls_alloc();
+ stack!access();
+ stack!tls_access();
+ GC.collect();
+ stack!tls_access();
+ stack!access();
+ stack!tls_free();
+ stack!free();
+}
+
+extern(C) int runTests()
+{
+ try
+ {
+ assert(atomicLoad!(MemoryOrder.acq)(gctor) == 1);
+ assert(atomicLoad!(MemoryOrder.acq)(gdtor) == 0);
+ assert(atomicLoad!(MemoryOrder.acq)(tctor) >= 1);
+ assert(atomicLoad!(MemoryOrder.acq)(tdtor) >= 0);
+ // test some runtime functionality
+ testGC();
+ new Thread(&testGC).start.join;
+ }
+ catch (Throwable)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Provide a way to initialize D from C programs that are D agnostic.
+import core.runtime : rt_init, rt_term;
+
+extern(C) int plugin_init()
+{
+ return rt_init();
+}
+
+extern(C) int plugin_term()
+{
+ return rt_term();
+}
diff --git a/libphobos/testsuite/libphobos.shared/shared.exp b/libphobos/testsuite/libphobos.shared/shared.exp
new file mode 100644
index 0000000..5555b3b
--- /dev/null
+++ b/libphobos/testsuite/libphobos.shared/shared.exp
@@ -0,0 +1,108 @@
+# Copyright (C) 2017-2018 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libphobos-dg.exp
+
+# Immediately exit if target doesn't support shared.
+if { ![is-effective-target shared] } {
+ return
+}
+
+# If a testcase doesn't have special options, use these.
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS "-g"
+}
+
+#
+# Build all shared libraries, used as dependencies for other tests.
+#
+
+proc shared_library { source destfile options } {
+ global DEFAULT_DFLAGS
+ global all_libraries
+
+ # Compiling with -fno-gnu-unique as tests call dlopen/dlclose multiple times on the same library.
+ lappend options "additional_flags=$DEFAULT_DFLAGS -fno-gnu-unique -fpic -shared -shared-libphobos"
+
+ set comp_output [libphobos_target_compile "$source" "$destfile" "executable" $options]
+ if ![ string match "" $comp_output ] {
+ fail "libphobos.shared/[file tail $source]"
+ verbose -log $comp_output
+ return 1
+ }
+
+ lappend all_libraries $destfile
+}
+
+# lib.so
+shared_library "$srcdir/$subdir/lib.d" "lib.so" ""
+
+# liblinkdep.so
+shared_library "$srcdir/$subdir/liblinkdep.d" "liblinkdep.so" \
+ [list "additional_flags=-I$srcdir/$subdir lib.so"]
+
+# libloaddep.so
+shared_library "$srcdir/$subdir/libloaddep.d" "libloaddep.so" ""
+
+# lib_13414.so
+shared_library "$srcdir/$subdir/lib_13414.d" "lib_13414.so" ""
+
+# plugin.so
+shared_library "$srcdir/$subdir/plugin.d" "plugin1.so" ""
+shared_library "$srcdir/$subdir/plugin.d" "plugin2.so" ""
+
+# Initialize dg.
+dg-init
+
+# Main loop.
+dg-test "$srcdir/$subdir/link.d" "-I$srcdir/$subdir lib.so -shared-libphobos" \
+ "$DEFAULT_DFLAGS"
+
+dg-test "$srcdir/$subdir/link_linkdep.d" \
+ "-I$srcdir/$subdir liblinkdep.so lib.so -shared-libphobos" \
+ "$DEFAULT_DFLAGS"
+
+dg-test "$srcdir/$subdir/link_loaddep.d" \
+ "-I$srcdir/$subdir libloaddep.so -shared-libphobos" "$DEFAULT_DFLAGS"
+
+# dlopen() tests.
+if [is-effective-target dlopen] {
+ dg-test "$srcdir/$subdir/load.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS"
+ dg-test "$srcdir/$subdir/load_linkdep.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS"
+ dg-test "$srcdir/$subdir/load_loaddep.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS"
+ dg-test "$srcdir/$subdir/load_13414.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS"
+ dg-test "$srcdir/$subdir/finalize.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS"
+}
+
+# C program link tests.
+if { [is-effective-target dlopen] && [is-effective-target pthread] } {
+ dg-test "$srcdir/$subdir/linkD.c" "lib.so -ldl -pthread" "$DEFAULT_CFLAGS"
+ dg-test "$srcdir/$subdir/linkDR.c" "-shared-libphobos -ldl -pthread" "$DEFAULT_CFLAGS"
+ dg-test "$srcdir/$subdir/host.c" "-ldl -pthread" "$DEFAULT_CFLAGS"
+
+ # Test requires a command line argument to be passed to the program.
+ set libphobos_run_args "$objdir/../src/.libs/libgphobos.so"
+ dg-test "$srcdir/$subdir/loadDR.c" "-ldl -pthread -g" "$DEFAULT_CFLAGS"
+ set libphobos_run_args ""
+}
+
+# All done.
+dg-finish
+
+# Remove all libraries built before running tests.
+foreach lib $all_libraries {
+ catch "file delete -force -- $lib"
+}