From patchwork Tue Nov 30 15:11:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 48296 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 48210385BF99 for ; Tue, 30 Nov 2021 15:12:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48210385BF99 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1638285156; bh=Z+guBZr4ukyS+EWjv49CFUilqla/8N1UiMIJfD1vkxI=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=jvJfOFO4vqyRsWWkjRIiTTcMIFxb5Vfelhmf9In1Ftoo3noEvGMia59ZsZ8/1EIdz gFyaPxlj6wG7HtJcFthGczoxKBrAtqlOprtEb4RmwPHLOAxbGOwrw8uY8po6K6mSkz mgRi1LOIjyyiV2GLkh3vjloAS3Xoc/lCCJKIvdqY= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [IPv6:2001:67c:2050::465:202]) by sourceware.org (Postfix) with ESMTPS id 2D709385C017 for ; Tue, 30 Nov 2021 15:11:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2D709385C017 Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 4J3QfX2XL8zQjh5; Tue, 30 Nov 2021 16:11:32 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de To: gcc-patches@gcc.gnu.org Subject: [committed 17/19] libphobos: Import druntime testsuite v2.098.0-beta.1 (e6caaab9) Date: Tue, 30 Nov 2021 16:11:12 +0100 Message-Id: <20211130151112.631900-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_LOTSOFHASH, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Iain Buclaw via Gcc-patches From: Iain Buclaw Reply-To: Iain Buclaw Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This is the updated D runtime library testsuite. Bootstrapped, regression tested, and committed to mainline. Regards, Iain. --- libphobos/ChangeLog: * testsuite/libphobos.aa/test_aa.d: Update test. * testsuite/libphobos.exceptions/unknown_gc.d: Likewise. * testsuite/libphobos.hash/test_hash.d: Likewise. * testsuite/libphobos.shared/host.c: Likewise. * testsuite/libphobos.shared/load.d: Likewise. * testsuite/libphobos.shared/load_13414.d: Likewise. * testsuite/libphobos.thread/fiber_guard_page.d: Likewise. * testsuite/libphobos.thread/tlsgc_sections.d: Likewise. * testsuite/libphobos.shared/link_mod_collision.d: Removed. * testsuite/libphobos.shared/load_mod_collision.d: Removed. * testsuite/libphobos.allocations/alloc_from_assert.d: New test. * testsuite/libphobos.betterc/test18828.d: New test. * testsuite/libphobos.betterc/test19416.d: New test. * testsuite/libphobos.betterc/test19421.d: New test. * testsuite/libphobos.betterc/test19561.d: New test. * testsuite/libphobos.betterc/test19924.d: New test. * testsuite/libphobos.betterc/test20088.d: New test. * testsuite/libphobos.betterc/test20613.d: New test. * testsuite/libphobos.config/test19433.d: New test. * testsuite/libphobos.config/test20459.d: New test. * testsuite/libphobos.exceptions/assert_fail.d: New test. * testsuite/libphobos.exceptions/catch_in_finally.d: New test. * testsuite/libphobos.exceptions/future_message.d: New test. * testsuite/libphobos.exceptions/long_backtrace_trunc.d: New test. * testsuite/libphobos.exceptions/refcounted.d: New test. * testsuite/libphobos.exceptions/rt_trap_exceptions.d: New test. * testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d: New test. * testsuite/libphobos.gc/attributes.d: New test. * testsuite/libphobos.gc/forkgc.d: New test. * testsuite/libphobos.gc/forkgc2.d: New test. * testsuite/libphobos.gc/nocollect.d: New test. * testsuite/libphobos.gc/precisegc.d: New test. * testsuite/libphobos.gc/recoverfree.d: New test. * testsuite/libphobos.gc/sigmaskgc.d: New test. * testsuite/libphobos.gc/startbackgc.d: New test. * testsuite/libphobos.imports/bug18193.d: New test. * testsuite/libphobos.init_fini/custom_gc.d: New test. * testsuite/libphobos.init_fini/test18996.d: New test. * testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d: New test. * testsuite/libphobos.thread/external_threads.d: New test. * testsuite/libphobos.thread/join_detach.d: New test. * testsuite/libphobos.thread/test_import.d: New test. * testsuite/libphobos.thread/tlsstack.d: New test. * testsuite/libphobos.typeinfo/enum_.d: New test. * testsuite/libphobos.typeinfo/isbaseof.d: New test. * testsuite/libphobos.unittest/customhandler.d: New test. --- libphobos/testsuite/libphobos.aa/test_aa.d | 79 ++- .../libphobos.allocations/alloc_from_assert.d | 25 + .../testsuite/libphobos.betterc/test18828.d | 10 + .../testsuite/libphobos.betterc/test19416.d | 14 + .../testsuite/libphobos.betterc/test19421.d | 13 + .../testsuite/libphobos.betterc/test19561.d | 16 + .../testsuite/libphobos.betterc/test19924.d | 15 + .../testsuite/libphobos.betterc/test20088.d | 14 + .../testsuite/libphobos.betterc/test20613.d | 18 + .../testsuite/libphobos.config/test19433.d | 7 + .../testsuite/libphobos.config/test20459.d | 5 + .../libphobos.exceptions/assert_fail.d | 564 ++++++++++++++++++ .../libphobos.exceptions/catch_in_finally.d | 191 ++++++ .../libphobos.exceptions/future_message.d | 71 +++ .../long_backtrace_trunc.d | 37 ++ .../libphobos.exceptions/refcounted.d | 96 +++ .../libphobos.exceptions/rt_trap_exceptions.d | 15 + .../rt_trap_exceptions_drt.d | 11 + .../libphobos.exceptions/unknown_gc.d | 4 + libphobos/testsuite/libphobos.gc/attributes.d | 30 + libphobos/testsuite/libphobos.gc/forkgc.d | 36 ++ libphobos/testsuite/libphobos.gc/forkgc2.d | 22 + libphobos/testsuite/libphobos.gc/nocollect.d | 15 + libphobos/testsuite/libphobos.gc/precisegc.d | 126 ++++ .../testsuite/libphobos.gc/recoverfree.d | 13 + libphobos/testsuite/libphobos.gc/sigmaskgc.d | 42 ++ .../testsuite/libphobos.gc/startbackgc.d | 22 + .../testsuite/libphobos.hash/test_hash.d | 140 ++++- .../testsuite/libphobos.imports/bug18193.d | 4 + .../testsuite/libphobos.init_fini/custom_gc.d | 203 +++++++ .../testsuite/libphobos.init_fini/test18996.d | 13 + .../large_aggregate_destroy_21097.d | 78 +++ libphobos/testsuite/libphobos.shared/host.c | 8 + .../libphobos.shared/link_mod_collision.d | 5 - libphobos/testsuite/libphobos.shared/load.d | 1 - .../testsuite/libphobos.shared/load_13414.d | 13 +- .../libphobos.shared/load_mod_collision.d | 14 - .../libphobos.thread/external_threads.d | 50 ++ .../libphobos.thread/fiber_guard_page.d | 4 + .../testsuite/libphobos.thread/join_detach.d | 20 + .../testsuite/libphobos.thread/test_import.d | 7 + .../libphobos.thread/tlsgc_sections.d | 61 +- .../testsuite/libphobos.thread/tlsstack.d | 38 ++ .../testsuite/libphobos.typeinfo/enum_.d | 21 + .../testsuite/libphobos.typeinfo/isbaseof.d | 46 ++ .../libphobos.unittest/customhandler.d | 21 + 46 files changed, 2191 insertions(+), 67 deletions(-) create mode 100644 libphobos/testsuite/libphobos.allocations/alloc_from_assert.d create mode 100644 libphobos/testsuite/libphobos.betterc/test18828.d create mode 100644 libphobos/testsuite/libphobos.betterc/test19416.d create mode 100644 libphobos/testsuite/libphobos.betterc/test19421.d create mode 100644 libphobos/testsuite/libphobos.betterc/test19561.d create mode 100644 libphobos/testsuite/libphobos.betterc/test19924.d create mode 100644 libphobos/testsuite/libphobos.betterc/test20088.d create mode 100644 libphobos/testsuite/libphobos.betterc/test20613.d create mode 100644 libphobos/testsuite/libphobos.config/test19433.d create mode 100644 libphobos/testsuite/libphobos.config/test20459.d create mode 100644 libphobos/testsuite/libphobos.exceptions/assert_fail.d create mode 100644 libphobos/testsuite/libphobos.exceptions/catch_in_finally.d create mode 100644 libphobos/testsuite/libphobos.exceptions/future_message.d create mode 100644 libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d create mode 100644 libphobos/testsuite/libphobos.exceptions/refcounted.d create mode 100644 libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d create mode 100644 libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d create mode 100644 libphobos/testsuite/libphobos.gc/attributes.d create mode 100644 libphobos/testsuite/libphobos.gc/forkgc.d create mode 100644 libphobos/testsuite/libphobos.gc/forkgc2.d create mode 100644 libphobos/testsuite/libphobos.gc/nocollect.d create mode 100644 libphobos/testsuite/libphobos.gc/precisegc.d create mode 100644 libphobos/testsuite/libphobos.gc/recoverfree.d create mode 100644 libphobos/testsuite/libphobos.gc/sigmaskgc.d create mode 100644 libphobos/testsuite/libphobos.gc/startbackgc.d create mode 100644 libphobos/testsuite/libphobos.imports/bug18193.d create mode 100644 libphobos/testsuite/libphobos.init_fini/custom_gc.d create mode 100644 libphobos/testsuite/libphobos.init_fini/test18996.d create mode 100644 libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d delete mode 100644 libphobos/testsuite/libphobos.shared/link_mod_collision.d delete mode 100644 libphobos/testsuite/libphobos.shared/load_mod_collision.d create mode 100644 libphobos/testsuite/libphobos.thread/external_threads.d create mode 100644 libphobos/testsuite/libphobos.thread/join_detach.d create mode 100644 libphobos/testsuite/libphobos.thread/test_import.d create mode 100644 libphobos/testsuite/libphobos.thread/tlsstack.d create mode 100644 libphobos/testsuite/libphobos.typeinfo/enum_.d create mode 100644 libphobos/testsuite/libphobos.typeinfo/isbaseof.d create mode 100644 libphobos/testsuite/libphobos.unittest/customhandler.d diff --git a/libphobos/testsuite/libphobos.aa/test_aa.d b/libphobos/testsuite/libphobos.aa/test_aa.d index d6222b13175..11ad2f90ff1 100644 --- a/libphobos/testsuite/libphobos.aa/test_aa.d +++ b/libphobos/testsuite/libphobos.aa/test_aa.d @@ -30,6 +30,8 @@ void main() issue15367(); issue16974(); issue18071(); + issue20440(); + issue21442(); testIterationWithConst(); testStructArrayKey(); miscTests1(); @@ -286,21 +288,20 @@ void testUpdate2() assert(updated); } -void testByKey1() +void testByKey1() @safe { - static assert(!__traits(compiles, - () @safe { - struct BadValue - { - int x; - this(this) @safe { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe - alias x this; - } + static struct BadValue + { + int x; + this(this) @system { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe + alias x this; + } - BadValue[int] aa; - () @safe { auto x = aa.byKey.front; } (); - } - )); + BadValue[int] aa; + + // FIXME: Should be @system because of the postblit + if (false) + auto x = aa.byKey.front; } void testByKey2() nothrow pure @@ -690,6 +691,58 @@ void issue18071() () @safe { assert(f.byKey.empty); }(); } +/// Test that `require` works even with types whose opAssign +/// doesn't return a reference to the receiver. +/// https://issues.dlang.org/show_bug.cgi?id=20440 +void issue20440() @safe +{ + static struct S + { + int value; + auto opAssign(S s) { + this.value = s.value; + return this; + } + } + S[S] aa; + assert(aa.require(S(1), S(2)) == S(2)); + assert(aa[S(1)] == S(2)); +} + +/// +void issue21442() +{ + import core.memory; + + size_t[size_t] glob; + + class Foo + { + size_t count; + + this (size_t entries) @safe + { + this.count = entries; + foreach (idx; 0 .. entries) + glob[idx] = idx; + } + + ~this () @safe + { + foreach (idx; 0 .. this.count) + glob.remove(idx); + } + } + + void bar () @safe + { + Foo f = new Foo(16); + } + + bar(); + GC.collect(); // Needs to happen from a GC collection +} + /// Verify iteration with const. void testIterationWithConst() { diff --git a/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d b/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d new file mode 100644 index 00000000000..a377cd9139d --- /dev/null +++ b/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d @@ -0,0 +1,25 @@ +import core.exception; +import core.memory; + +class FailFinalization +{ + int magic; + + ~this () @nogc nothrow + { + try + assert(this.magic == 42); + catch (AssertError) {} + } +} + +void foo () +{ + auto dangling = new FailFinalization(); +} + +void main() +{ + foo(); + GC.collect(); +} diff --git a/libphobos/testsuite/libphobos.betterc/test18828.d b/libphobos/testsuite/libphobos.betterc/test18828.d new file mode 100644 index 00000000000..db0530dd13c --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test18828.d @@ -0,0 +1,10 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=18828 + +struct S18828 { } + +extern(C) void main() +{ + S18828 s; + destroy(s); +} diff --git a/libphobos/testsuite/libphobos.betterc/test19416.d b/libphobos/testsuite/libphobos.betterc/test19416.d new file mode 100644 index 00000000000..aff93d3aa5f --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test19416.d @@ -0,0 +1,14 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19416 + +import core.stdc.stdlib : malloc, free; +import core.exception : onOutOfMemoryError; + +extern(C) void main() +{ + auto m = malloc(1); + if (!m) + onOutOfMemoryError(); + else + free(m); +} diff --git a/libphobos/testsuite/libphobos.betterc/test19421.d b/libphobos/testsuite/libphobos.betterc/test19421.d new file mode 100644 index 00000000000..2427c5e9a0c --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test19421.d @@ -0,0 +1,13 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19421 + +import core.memory; + +extern(C) void main() @nogc nothrow pure +{ + auto p = pureMalloc(1); + p = pureRealloc(p, 2); + if (p) pureFree(p); + p = pureCalloc(1, 1); + if (p) pureFree(p); +} diff --git a/libphobos/testsuite/libphobos.betterc/test19561.d b/libphobos/testsuite/libphobos.betterc/test19561.d new file mode 100644 index 00000000000..96ecec51ae4 --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test19561.d @@ -0,0 +1,16 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19561 + +import core.memory; + +extern(C) void main() @nogc nothrow pure +{ + int[3] a, b; + a[] = 0; + a[] = b[]; + //FIXME: Next line requires compiler change. + //a[] = 1; // error: undefined reference to '_memset32' + a[] += 1; + a[] += b[]; + int[3] c = a[] + b[]; +} diff --git a/libphobos/testsuite/libphobos.betterc/test19924.d b/libphobos/testsuite/libphobos.betterc/test19924.d new file mode 100644 index 00000000000..e9a93cad0ac --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test19924.d @@ -0,0 +1,15 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=19924 + +import core.bitop; + +extern(C) void main() +{ + uint a = 0x01_23_45_67; + a = bswap(a); + assert(a == 0x67_45_23_01); + + ulong b = 0x01_23_45_67_89_ab_cd_ef; + b = bswap(b); + assert(b == 0xef_cd_ab_89_67_45_23_01); +} diff --git a/libphobos/testsuite/libphobos.betterc/test20088.d b/libphobos/testsuite/libphobos.betterc/test20088.d new file mode 100644 index 00000000000..a809041c877 --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test20088.d @@ -0,0 +1,14 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=20088 + +struct S { + int i; +} + +extern(C) int main() @nogc nothrow pure +{ + S[2] s = [S(1),S(2)]; + void[] v = cast(void[])s; + S[] p = cast(S[])v; // cast of void[] to S[] triggers __ArrayCast template function + return 0; +} diff --git a/libphobos/testsuite/libphobos.betterc/test20613.d b/libphobos/testsuite/libphobos.betterc/test20613.d new file mode 100644 index 00000000000..b03e2d17b62 --- /dev/null +++ b/libphobos/testsuite/libphobos.betterc/test20613.d @@ -0,0 +1,18 @@ +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=20613 + +extern(C) int main() @nogc nothrow pure +{ + auto s = "F"; + final switch(s) + { + case "A": break; + case "B": break; + case "C": break; + case "D": break; + case "E": break; + case "F": break; + case "G": break; + } + return 0; +} diff --git a/libphobos/testsuite/libphobos.config/test19433.d b/libphobos/testsuite/libphobos.config/test19433.d new file mode 100644 index 00000000000..1c58145103e --- /dev/null +++ b/libphobos/testsuite/libphobos.config/test19433.d @@ -0,0 +1,7 @@ +extern(C) __gshared bool rt_cmdline_enabled = false; + +void main(string[] args) +{ + assert(args.length == 2); + assert(args[1] == "--DRT-dont-eat-me"); +} diff --git a/libphobos/testsuite/libphobos.config/test20459.d b/libphobos/testsuite/libphobos.config/test20459.d new file mode 100644 index 00000000000..248720d8f30 --- /dev/null +++ b/libphobos/testsuite/libphobos.config/test20459.d @@ -0,0 +1,5 @@ +void main (string[] args) +{ + assert(args.length == 5); + assert(args[1 .. $] == [ "foo", "bar", "--", "--DRT-gcopts=profile:1" ]); +} diff --git a/libphobos/testsuite/libphobos.exceptions/assert_fail.d b/libphobos/testsuite/libphobos.exceptions/assert_fail.d new file mode 100644 index 00000000000..79b3cb8139e --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/assert_fail.d @@ -0,0 +1,564 @@ +import core.stdc.stdio : fprintf, stderr; +import core.internal.dassert : _d_assert_fail; + +void test(string comp = "==", A, B)(A a, B b, string msg, size_t line = __LINE__) +{ + test(_d_assert_fail!(A)(comp, a, b), msg, line); +} + +void test(const string actual, const string expected, size_t line = __LINE__) +{ + import core.exception : AssertError; + + if (actual != expected) + { + const msg = "Mismatch!\nExpected: <" ~ expected ~ ">\nActual: <" ~ actual ~ '>'; + throw new AssertError(msg, __FILE__, line); + } +} + +void testIntegers() +{ + test(1, 2, "1 != 2"); + test(-10, 8, "-10 != 8"); + test(byte.min, byte.max, "-128 != 127"); + test(ubyte.min, ubyte.max, "0 != 255"); + test(short.min, short.max, "-32768 != 32767"); + test(ushort.min, ushort.max, "0 != 65535"); + test(int.min, int.max, "-2147483648 != 2147483647"); + test(uint.min, uint.max, "0 != 4294967295"); + test(long.min, long.max, "-9223372036854775808 != 9223372036854775807"); + test(ulong.min, ulong.max, "0 != 18446744073709551615"); + test(shared(ulong).min, shared(ulong).max, "0 != 18446744073709551615"); + + int testFun() { return 1; } + test(testFun(), 2, "1 != 2"); +} + +void testIntegerComparisons() +{ + test!"!="(2, 2, "2 == 2"); + test!"<"(2, 1, "2 >= 1"); + test!"<="(2, 1, "2 > 1"); + test!">"(1, 2, "1 <= 2"); + test!">="(1, 2, "1 < 2"); +} + +void testFloatingPoint() +{ + if (__ctfe) + { + test(float.max, -float.max, " != "); + test(double.max, -double.max, " != "); + test(real(1), real(-1), " != "); + } + else + { + test(1.5, 2.5, "1.5 != 2.5"); + test(float.max, -float.max, "3.40282e+38 != -3.40282e+38"); + test(double.max, -double.max, "1.79769e+308 != -1.79769e+308"); + test(real(1), real(-1), "1 != -1"); + } +} + +void testPointers() +{ + static struct S + { + string toString() const { return "S(...)"; } + } + + static if ((void*).sizeof == 4) + enum ptr = "0x12345670"; + else + enum ptr = "0x123456789abcdef0"; + + int* p = cast(int*) mixin(ptr); + test(cast(S*) p, p, ptr ~ " != " ~ ptr); +} + +void testStrings() +{ + test("foo", "bar", `"foo" != "bar"`); + test("", "bar", `"" != "bar"`); + + char[] dlang = "dlang".dup; + const(char)[] rust = "rust"; + test(dlang, rust, `"dlang" != "rust"`); + + // https://issues.dlang.org/show_bug.cgi?id=20322 + test("left"w, "right"w, `"left" != "right"`); + test("left"d, "right"d, `"left" != "right"`); + + test('A', 'B', "'A' != 'B'"); + test(wchar('❤'), wchar('∑'), "'❤' != '∑'"); + test(dchar('❤'), dchar('∑'), "'❤' != '∑'"); + + // Detect invalid code points + test(char(255), 'B', "cast(char) 255 != 'B'"); + test(wchar(0xD888), wchar('∑'), "cast(wchar) 55432 != '∑'"); + test(dchar(0xDDDD), dchar('∑'), "cast(dchar) 56797 != '∑'"); +} + +void testToString() +{ + class Foo + { + this(string payload) { + this.payload = payload; + } + + string payload; + override string toString() { + return "Foo(" ~ payload ~ ")"; + } + } + test(new Foo("a"), new Foo("b"), "Foo(a) != Foo(b)"); + + scope f = cast(shared) new Foo("a"); + if (!__ctfe) // Ref somehow get's lost in CTFE + test!"!="(f, f, "Foo(a) == Foo(a)"); + + // Verifiy that the const toString is selected if present + static struct Overloaded + { + string toString() + { + return "Mutable"; + } + + string toString() const + { + return "Const"; + } + } + + test!"!="(Overloaded(), Overloaded(), "Const == Const"); + + Foo fnull = null; + test!"!is"(fnull, fnull, "`null` is `null`"); +} + + +void testArray() +{ + test([1], [0], "[1] != [0]"); + test([1, 2, 3], [0], "[1, 2, 3] != [0]"); + + // test with long arrays + int[] arr; + foreach (i; 0 .. 100) + arr ~= i; + test(arr, [0], "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ...] != [0]"); + + // Ignore fake arrays + static struct S + { + int[2] arr; + int[] get() return { return arr[]; } + alias get this; + } + + const a = S([1, 2]); + test(a, S([3, 4]), "S([1, 2]) != S([3, 4])"); +} + +void testStruct() +{ + struct S { int s; } + struct T { T[] t; } + test(S(0), S(1), "S(0) != S(1)"); + test(T([T(null)]), T(null), "T([T([])]) != T([])"); + + // https://issues.dlang.org/show_bug.cgi?id=20323 + static struct NoCopy + { + @disable this(this); + } + + NoCopy n; + test(_d_assert_fail!(typeof(n))("!=", n, n), "NoCopy() == NoCopy()"); + + shared NoCopy sn; + test(_d_assert_fail!(typeof(sn))("!=", sn, sn), "NoCopy() == NoCopy()"); +} + +void testAA() +{ + test([1:"one"], [2: "two"], `[1: "one"] != [2: "two"]`); + test!"in"(1, [2: 3], "1 !in [2: 3]"); + test!"in"("foo", ["bar": true], `"foo" !in ["bar": true]`); +} + +void testAttributes() @safe pure @nogc nothrow +{ + int a; + string s = _d_assert_fail!(int, char)("==", a, 'c', 1, 'd'); + assert(s == `(0, 'c') != (1, 'd')`); + + string s2 = _d_assert_fail!int("", a); + assert(s2 == `0 != true`); +} + +// https://issues.dlang.org/show_bug.cgi?id=20066 +void testVoidArray() +{ + test!"!is"([], null, (__ctfe ? "" : "[]") ~ " is `null`"); + test!"!is"(null, null, "`null` is `null`"); + test([1], null, "[1] != `null`"); + test("s", null, "\"s\" != `null`"); + test(['c'], null, "\"c\" != `null`"); + test!"!="(null, null, "`null` == `null`"); + + const void[] chunk = [byte(1), byte(2), byte(3)]; + test(chunk, null, (__ctfe ? "" : "[1, 2, 3]") ~ " != `null`"); +} + +void testTemporary() +{ + static struct Bad + { + ~this() @system {} + } + + test!"!="(Bad(), Bad(), "Bad() == Bad()"); +} + +void testEnum() +{ + static struct UUID { + union + { + ubyte[] data = [1]; + } + } + + ubyte[] data; + enum ctfe = UUID(); + test(_d_assert_fail!(ubyte[])("==", ctfe.data, data), "[1] != []"); +} + +void testUnary() +{ + test(_d_assert_fail!int("", 9), "9 != true"); + test(_d_assert_fail!(int[])("!", [1, 2, 3]), "[1, 2, 3] == true"); +} + +void testTuple() +{ + test(_d_assert_fail("=="), "() != ()"); + test(_d_assert_fail("!="), "() == ()"); + test(_d_assert_fail(">="), "() < ()"); +} + +void testStructEquals() +{ + struct T { + bool b; + int i; + float f1 = 2.5; + float f2 = 0; + string s1 = "bar"; + string s2; + } + + T t1; + test!"!="(t1, t1, `T(false, 0, 2.5, 0, "bar", "") == T(false, 0, 2.5, 0, "bar", "")`); + T t2 = {s1: "bari"}; + test(t1, t2, `T(false, 0, 2.5, 0, "bar", "") != T(false, 0, 2.5, 0, "bari", "")`); +} + +void testStructEquals2() +{ + struct T { + bool b; + int i; + float f1 = 2.5; + float f2 = 0; + } + + T t1; + test!"!="(t1, t1, `T(false, 0, 2.5, 0) == T(false, 0, 2.5, 0)`); + T t2 = {i: 2}; + test(t1, t2, `T(false, 0, 2.5, 0) != T(false, 2, 2.5, 0)`); +} + +void testStructEquals3() +{ + struct T { + bool b; + int i; + string s1 = "bar"; + string s2; + } + + T t1; + test!"!="(t1, t1, `T(false, 0, "bar", "") == T(false, 0, "bar", "")`); + T t2 = {s1: "bari"}; + test(t1, t2, `T(false, 0, "bar", "") != T(false, 0, "bari", "")`); +} + +void testStructEquals4() +{ + struct T { + float f1 = 2.5; + float f2 = 0; + string s1 = "bar"; + string s2; + } + + T t1; + test!"!="(t1, t1, `T(2.5, 0, "bar", "") == T(2.5, 0, "bar", "")`); + T t2 = {s1: "bari"}; + test(t1, t2, `T(2.5, 0, "bar", "") != T(2.5, 0, "bari", "")`); +} + +void testStructEquals5() +{ + struct T { + bool b; + int i; + float f2 = 0; + string s2; + } + + T t1; + test!"!="(t1, t1, `T(false, 0, 0, "") == T(false, 0, 0, "")`); + T t2 = {b: true}; + test(t1, t2, `T(false, 0, 0, "") != T(true, 0, 0, "")`); +} + +void testStructEquals6() +{ + class C { override string toString() { return "C()"; }} + struct T { + bool b; + int i; + float f2 = 0; + string s2; + int[] arr; + C c; + } + + T t1; + test!"!="(t1, t1, "T(false, 0, 0, \"\", [], `null`) == T(false, 0, 0, \"\", [], `null`)"); + T t2 = {arr: [1]}; + test(t1, t2, "T(false, 0, 0, \"\", [], `null`) != T(false, 0, 0, \"\", [1], `null`)"); + T t3 = {c: new C()}; + test(t1, t3, "T(false, 0, 0, \"\", [], `null`) != T(false, 0, 0, \"\", [], C())"); +} + +void testContextPointer() +{ + int i; + struct T + { + int j; + int get() + { + return i * j; + } + } + T t = T(1); + t.tupleof[$-1] = cast(void*) 0xABCD; // Deterministic context pointer + test(t, t, `T(1, : 0xabcd) != T(1, : 0xabcd)`); +} + +void testExternClasses() +{ + { + extern(C++) static class Cpp + { + int a; + this(int a) { this.a = a; } + } + scope a = new Cpp(1); + scope b = new Cpp(2); + test(a, b, "Cpp(1) != Cpp(2)"); + test(a, Cpp.init, "Cpp(1) != null"); + } + { + extern(C++) static class CppToString + { + int a; + this(int a) { this.a = a; } + extern(D) string toString() const { return a == 0 ? "hello" : "world"; } + } + scope a = new CppToString(0); + scope b = new CppToString(1); + test(a, b, "hello != world"); + } + if (!__ctfe) + { + extern(C++) static class Opaque; + Opaque null_ = null; + Opaque notNull = cast(Opaque) &null_; + test(null_, notNull, "null != "); + } + { + extern(C++) static interface Stuff {} + scope Stuff stuff = new class Stuff {}; + test(stuff, Stuff.init, "Stuff() != null"); + } +} + +void testShared() +{ + static struct Small + { + int i; + } + + auto s1 = shared Small(1); + const s2 = shared Small(2); + test(s1, s2, "Small(1) != Small(2)"); + + static struct Big + { + long[10] l; + } + + auto b1 = shared Big([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + const b2 = shared Big(); + test(b1, b2, "Big([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) != Big([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])"); + + // Sanity check: Big shouldn't be supported by atomicLoad + import core.atomic : atomicLoad; + static assert( __traits(compiles, atomicLoad(s1))); + static assert(!__traits(compiles, atomicLoad(b1))); +} + +void testException() +{ + static struct MayThrow + { + int i; + string toString() + { + if (i == 1) + throw new Exception("Error"); + return "Some message"; + } + } + + test(MayThrow(0), MayThrow(1), `Some message != `); +} + +void testOverlappingFields() +{ + static struct S + { + union + { + double num; + immutable(char)[] name; + } + } + + test(S(1.0), S(2.0), "S(, ) != S(, )"); + + static struct S2 + { + int valid; + union + { + double num; + immutable(char)[] name; + } + } + + test(S2(4, 1.0), S2(5, 2.0), "S2(4, , ) != S2(5, , )"); + + static struct S3 + { + union + { + double num; + immutable(char)[] name; + } + int valid; + } + S3 a = { + num: 1.0, + valid: 8 + }; + + S3 b = { + num: 1.0, + valid: 8 + }; + test(a, b, "S3(, , 8) != S3(, , 8)"); +} + +void testDestruction() +{ + static class Test + { + __gshared string unary, binary; + __gshared bool run; + + ~this() + { + run = true; + unary = _d_assert_fail!int("", 1); + binary = _d_assert_fail!int("==", 1, 2); + } + } + + static void createGarbage() + { + new Test(); + new long[100]; + } + + import core.memory : GC; + createGarbage(); + GC.collect(); + + assert(Test.run); + assert(Test.unary == "Assertion failed (rich formatting is disabled in finalizers)"); + assert(Test.binary == "Assertion failed (rich formatting is disabled in finalizers)"); +} + +int main() +{ + testIntegers(); + testIntegerComparisons(); + testFloatingPoint(); + testPointers(); + testStrings(); + testToString(); + testArray(); + testStruct(); + testAA(); + testAttributes(); + testVoidArray(); + testTemporary(); + testEnum(); + testUnary(); + testTuple(); + if (!__ctfe) + testStructEquals(); + if (!__ctfe) + testStructEquals2(); + testStructEquals3(); + if (!__ctfe) + testStructEquals4(); + if (!__ctfe) + testStructEquals5(); + if (!__ctfe) + testStructEquals6(); + testContextPointer(); + testExternClasses(); + testShared(); + testException(); + testOverlappingFields(); + if (!__ctfe) + testDestruction(); + + if (!__ctfe) + fprintf(stderr, "success.\n"); + return 0; +} + +enum forceCTFE = main(); diff --git a/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d b/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d new file mode 100644 index 00000000000..88bd73957dd --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d @@ -0,0 +1,191 @@ +import core.stdc.stdio : fprintf, stderr; + +class MyException : Exception +{ + this() { super(typeof(this).stringof); } +} + +void throw_catch() +{ + try + { + throw new MyException; + } + catch (MyException) + { + } + catch (Exception) + { + assert(false); + } +} + +// Test that exceptions that are entirely thrown and caught in finally blocks don't affect exception handling. +void test1() +{ + try + { + try + { + throw new Exception("p"); + } + finally + { + throw_catch(); + } + } + catch (Exception e) + { + assert(e.msg == "p"); + } +} + +// Test that exceptions that are entirely thrown and caught in finally blocks don't interfere with chaining. +void test2() +{ + try + { + try + { + try + { + throw new Exception("p"); + } + finally + { + throw new Exception("q"); + } + } + finally + { + throw_catch(); + } + } + catch(Exception e) + { + assert(e.msg == "p"); + assert(e.next.msg == "q"); + assert(!e.next.next); + } +} + +void test3() +{ + try + { + try + { + try + { + throw new Exception("p"); + } + finally + { + throw_catch(); + } + } + finally + { + throw new Exception("q"); + } + } + catch(Exception e) + { + assert(e.msg == "p"); + assert(e.next.msg == "q"); + assert(!e.next.next); + } +} + +// Test order of exception handler operations. +void test4() +{ + string result; + void throw_catch() + { + pragma(inline, false); + try + { + result ~= "b"; + throw new MyException; + } + catch (MyException) + { + result ~= "c"; + } + catch (Exception) + { + assert(false); + } + } + try + { + try + { + result ~= "a"; + throw new Exception(""); + } + finally + { + throw_catch(); + } + } + catch(Exception e) + { + result ~= "d"; + } + assert(result == "abcd"); +} + +void test5() +{ + string result; + void fail() + { + result ~= "b"; + throw new Exception("a"); + } + + void throw_catch() + { + pragma(inline, false); + try + { + fail(); + } + catch(Exception e) + { + assert(e.msg == "a"); + assert(!e.next); + result ~= "c"; + } + } + try + { + try + { + result ~= "a"; + throw new Exception("x"); + } + finally + { + throw_catch(); + } + } + catch (Exception e) + { + assert(e.msg == "x"); + assert(!e.next); + result ~= "d"; + } + assert(result == "abcd"); +} + +void main() { + test1(); + test2(); + test3(); + test4(); + test5(); + fprintf(stderr, "success.\n"); +} diff --git a/libphobos/testsuite/libphobos.exceptions/future_message.d b/libphobos/testsuite/libphobos.exceptions/future_message.d new file mode 100644 index 00000000000..61b10348287 --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/future_message.d @@ -0,0 +1,71 @@ +// { dg-options "-Wno-deprecated" } +import core.stdc.stdio; + +// Make sure basic stuff works with future Throwable.message +class NoMessage : Throwable +{ + @nogc @safe pure nothrow this(string msg, Throwable next = null) + { + super(msg, next); + } +} + +class WithMessage : Throwable +{ + @nogc @safe pure nothrow this(string msg, Throwable next = null) + { + super(msg, next); + } + + override const(char)[] message() const + { + return "I have a custom message."; + } +} + +class WithMessageNoOverride : Throwable +{ + @nogc @safe pure nothrow this(string msg, Throwable next = null) + { + super(msg, next); + } + + const(char)[] message() const + { + return "I have a custom message and no override."; + } +} + +class WithMessageNoOverrideAndDifferentSignature : Throwable +{ + @nogc @safe pure nothrow this(string msg, Throwable next = null) + { + super(msg, next); + } + + immutable(char)[] message() + { + return "I have a custom message and I'm nothing like Throwable.message."; + } +} + +void test(Throwable t) +{ + try + { + throw t; + } + catch (Throwable e) + { + fprintf(stderr, "%.*s ", cast(int)e.message.length, e.message.ptr); + } +} + +void main() +{ + test(new NoMessage("exception")); + test(new WithMessage("exception")); + test(new WithMessageNoOverride("exception")); + test(new WithMessageNoOverrideAndDifferentSignature("exception")); + fprintf(stderr, "\n"); +} diff --git a/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d b/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d new file mode 100644 index 00000000000..3ff45e55c87 --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d @@ -0,0 +1,37 @@ +struct AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(T) { +struct BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB { +struct CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC { +struct DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD { +struct EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE { +struct FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF { +struct GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG { +struct HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH { + T tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt(int x) { + throw new Exception("test"); + } +} +} +} +} +} +} +} +} + +void main() { + try { + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!int. + BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB. + CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC. + DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD. + EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. + GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. + HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH x; + x.tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt(1); + } catch (Exception e) { + import core.stdc.stdio; + auto str = e.toString(); + printf("%.*s\n", cast(int)str.length, str.ptr); + } +} diff --git a/libphobos/testsuite/libphobos.exceptions/refcounted.d b/libphobos/testsuite/libphobos.exceptions/refcounted.d new file mode 100644 index 00000000000..2b7e79bbf39 --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/refcounted.d @@ -0,0 +1,96 @@ +// { dg-options "-fpreview=dip1008" } +class E : Exception +{ + static int instances; + this(string msg = "") + { + super(msg); + instances++; + } + + ~this() + { + instances--; + } +} + +void main() +{ + alias chain = Exception.chainTogether; + + assert(chain(null, null) is null); + + try + { + throw new E(); + } + catch (E e) + { + assert(E.instances == 1); + assert(e.refcount == 2); + } + + assert(E.instances == 0); + + try + { + throw new E(); + } + catch (E e) + { + assert(chain(null, e) is e); + assert(e.refcount == 2); // "Owned by e" + 1 + } + + assert(E.instances == 0); + + try + { + throw new E(); + } + catch (E e) + { + assert(chain(e, null) is e); + assert(e.refcount == 2); // "Owned by e" + 1 + } + + assert(E.instances == 0); + + try + { + throw new E("first"); + } + catch (E first) + { + try + { + throw new E("second"); + } + catch (E second) + { + try + { + throw new E("third"); + } + catch (E third) + { + assert(chain(first, second) is first); + assert(first.next is second); + assert(second.next is null); + + assert(chain(first, third) is first); + assert(first.next is second); + assert(second.next is third); + assert(third.next is null); + + assert(first.refcount == 2); + assert(second.refcount == 3); + assert(third.refcount == 3); + } + } + + assert(E.instances == 3); + } + + assert(E.instances == 0); +} diff --git a/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d new file mode 100644 index 00000000000..bd0c227e0f6 --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d @@ -0,0 +1,15 @@ +// { dg-shouldfail "uncaught exception" } +// { dg-output "gcc.deh.*: uncaught exception" } +// Code adapted from +// http://arsdnet.net/this-week-in-d/2016-aug-07.html +extern extern(C) __gshared bool rt_trapExceptions; +extern extern(C) int _d_run_main(int, char**, void*) @system; + +extern(C) int main(int argc, char** argv) { + rt_trapExceptions = false; + return _d_run_main(argc, argv, &_main); +} + +int _main() { + throw new Exception("this will abort"); +} diff --git a/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d new file mode 100644 index 00000000000..fc4448cf0bf --- /dev/null +++ b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d @@ -0,0 +1,11 @@ +// { dg-shouldfail "uncaught exception" } +void test() +{ + int innerLocal = 20; + throw new Exception("foo"); +} +void main(string[] args) +{ + string myLocal = "bar"; + test(); +} diff --git a/libphobos/testsuite/libphobos.exceptions/unknown_gc.d b/libphobos/testsuite/libphobos.exceptions/unknown_gc.d index eb95aeed036..183c0f2969e 100644 --- a/libphobos/testsuite/libphobos.exceptions/unknown_gc.d +++ b/libphobos/testsuite/libphobos.exceptions/unknown_gc.d @@ -2,8 +2,12 @@ // { dg-options "-shared-libphobos" } // { dg-shouldfail "unknowngc" } // { dg-output "No GC was initialized, please recheck the name of the selected GC \\('unknowngc'\\)." } +import core.memory; + extern(C) __gshared string[] rt_options = [ "gcopt=gc:unknowngc" ]; void main() { + // GC initialized upon first call -> Unknown GC error is thrown + GC.enable(); } diff --git a/libphobos/testsuite/libphobos.gc/attributes.d b/libphobos/testsuite/libphobos.gc/attributes.d new file mode 100644 index 00000000000..a7acd6ce550 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/attributes.d @@ -0,0 +1,30 @@ +import core.memory; + +// TODO: The following should work, but L10 (second assert) fails. +version(none) void dotest(T) (T* ptr) +{ + GC.clrAttr(ptr, uint.max); + assert(GC.getAttr(ptr) == 0); + + GC.setAttr(ptr, GC.BlkAttr.NO_MOVE); + assert(GC.getAttr(ptr) == GC.BlkAttr.NO_MOVE); + + GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE); + assert(GC.getAttr(ptr) == 0); + GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE); + assert(GC.getAttr(ptr) == 0); +} +else void dotest(T) (T* ptr) +{ + // https://issues.dlang.org/show_bug.cgi?id=21484 + GC.clrAttr(ptr, uint.max); + GC.setAttr(ptr, GC.BlkAttr.NO_MOVE); + GC.getAttr(ptr); +} + +void main () +{ + auto ptr = new int; + dotest!(const(int))(ptr); + dotest!(int)(ptr); +} diff --git a/libphobos/testsuite/libphobos.gc/forkgc.d b/libphobos/testsuite/libphobos.gc/forkgc.d new file mode 100644 index 00000000000..9c18dc296f0 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/forkgc.d @@ -0,0 +1,36 @@ +import core.memory; +import core.stdc.stdio; +import core.sys.posix.sys.wait; +import core.sys.posix.unistd; + +void main() +{ + printf("[parent] Creating garbage...\n"); + foreach (n; 0 .. 1_000) + new uint[10_000]; + printf("[parent] Collecting garbage...\n"); + GC.collect(); + printf("[parent] Forking...\n"); + auto i = fork(); + if (i < 0) + assert(false, "Fork failed"); + if (i == 0) + { + printf("[child] In fork.\n"); + printf("[child] Creating garbage...\n"); + foreach (n; 0 .. 1_000) + new uint[10_000]; + printf("[child] Collecting garbage...\n"); + GC.collect(); + printf("[child] Exiting fork.\n"); + } + else + { + printf("[parent] Waiting for fork (PID %d).\n", i); + int status; + i = waitpid(i, &status, 0); + printf("[parent] Fork %d exited (%d).\n", i, status); + if (status != 0) + assert(false, "child had errors"); + } +} diff --git a/libphobos/testsuite/libphobos.gc/forkgc2.d b/libphobos/testsuite/libphobos.gc/forkgc2.d new file mode 100644 index 00000000000..de7796ced72 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/forkgc2.d @@ -0,0 +1,22 @@ +import core.stdc.stdlib : exit; +import core.sys.posix.sys.wait : waitpid; +import core.sys.posix.unistd : fork; +import core.thread : Thread; + +void main() +{ + foreach (t; 0 .. 10) + new Thread({ + foreach (n; 0 .. 100) + { + foreach (x; 0 .. 100) + new ubyte[x]; + auto f = fork(); + assert(f >= 0); + if (f == 0) + exit(0); + else + waitpid(f, null, 0); + } + }).start(); +} diff --git a/libphobos/testsuite/libphobos.gc/nocollect.d b/libphobos/testsuite/libphobos.gc/nocollect.d new file mode 100644 index 00000000000..5df1483a284 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/nocollect.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=20567 + +import core.memory; + +void main() +{ + auto stats = GC.profileStats(); + assert(stats.numCollections == 0); + + char[] sbuf = new char[256]; // small pool + char[] lbuf = new char[2049]; // large pool + + stats = GC.profileStats(); + assert(stats.numCollections == 0); +} \ No newline at end of file diff --git a/libphobos/testsuite/libphobos.gc/precisegc.d b/libphobos/testsuite/libphobos.gc/precisegc.d new file mode 100644 index 00000000000..9bcaf3f4faa --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/precisegc.d @@ -0,0 +1,126 @@ +// precise GC related: +// https://issues.dlang.org/show_bug.cgi?id=3463 +// https://issues.dlang.org/show_bug.cgi?id=4358 +// https://issues.dlang.org/show_bug.cgi?id=9094 +// https://issues.dlang.org/show_bug.cgi?id=13801 +// https://issues.dlang.org/show_bug.cgi?id=18900 +module testgc; + +import core.memory; +import core.stdc.stdio; + +class C +{ + __gshared int dtors; + ~this() { dtors++; } + + C next; + size_t val; +} + +struct S +{ + __gshared int dtors; + ~this() { dtors++; } + + size_t val; + S* next; +} + +struct L +{ + __gshared int dtors; + ~this() { dtors++; } + + size_t[1000] data; + S* node; +} + +struct Roots +{ + C c; + S *s; + L *l; +}; + +Roots* roots; +size_t iroots; + +void init() +{ + roots = new Roots; + roots.c = new C; + roots.c.next = new C; + + roots.s = new S; + roots.s.next = new S; + + roots.l = new L; + roots.l.node = new S; +} + +void verifyPointers() +{ + assert(C.dtors == 0); + assert(S.dtors == 0); + assert(L.dtors == 0); +} + +// compiling with -gx should help eliminating false pointers on the stack +Roots makeFalsePointers() +{ + roots.c.val = cast(size_t) cast(void*) roots.c.next; + roots.c.next = null; + roots.s.val = cast(size_t) cast(void*) roots.s.next; + roots.s.next = null; + roots.l.data[7] = cast(size_t) cast(void*) roots.l.node; + roots.l.node = null; + + return Roots(null, null, null); // try to spill register contents +} + +Roots moveRoot() +{ + iroots = cast(size_t)roots; + roots = null; + + return Roots(null, null, null); // try to spill register contents +} + +// compiling with -gx should help eliminating false pointers on the stack +void verifyFalsePointers() +{ + assert(C.dtors <= 1); + if (C.dtors < 1) printf ("False pointers? C.dtors = %d, 1 expected\n", C.dtors); + assert(S.dtors <= 2); + if (S.dtors < 2) printf ("False pointers? S.dtors = %d, 2 expected\n", S.dtors); + assert(L.dtors == 0); +} + +extern(C) __gshared string[] rt_options = [ "gcopt=gc:precise", "scanDataSeg=precise" ]; + +void main() +{ + GC.collect(); // cleanup from unittests + + init(); + GC.collect(); // should collect nothing + verifyPointers(); + + makeFalsePointers(); + GC.collect(); // should collect roots.c.next, roots.s.next and roots.l.node + verifyFalsePointers(); + + moveRoot(); + GC.collect(); // should collect all + + version(Windows) // precise DATA scanning only implemented on Windows + { + assert(C.dtors <= 2); + if (C.dtors < 2) printf ("False DATA pointers? C.dtors = %d, 2 expected\n", C.dtors); + assert(S.dtors <= 3); + if (S.dtors < 3) printf ("False DATA pointers? S.dtors = %d, 2 expected\n", S.dtors); + assert(L.dtors <= 1); + if (L.dtors < 1) printf ("False DATA pointers? L.dtors = %d, 1 expected\n", L.dtors); + } +} diff --git a/libphobos/testsuite/libphobos.gc/recoverfree.d b/libphobos/testsuite/libphobos.gc/recoverfree.d new file mode 100644 index 00000000000..59c3b4ab597 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/recoverfree.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=20438 +import core.stdc.stdio; +import core.memory; + +void main() +{ + auto used0 = GC.stats.usedSize; + void* z = GC.malloc(100); + GC.free(z); + GC.collect(); + auto used1 = GC.stats.usedSize; + used1 <= used0 || assert(false); +} diff --git a/libphobos/testsuite/libphobos.gc/sigmaskgc.d b/libphobos/testsuite/libphobos.gc/sigmaskgc.d new file mode 100644 index 00000000000..eb46316d18f --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/sigmaskgc.d @@ -0,0 +1,42 @@ + +// https://issues.dlang.org/show_bug.cgi?id=20256 + +extern(C) __gshared string[] rt_options = [ "gcopt=parallel:1" ]; + +void main() +{ + version (Posix) + { + import core.sys.posix.signal; + import core.sys.posix.unistd; + import core.thread; + import core.memory; + + sigset_t m; + sigemptyset(&m); + sigaddset(&m, SIGHUP); + + auto x = new int[](10000); + foreach (i; 0 .. 10000) + { + x ~= i; + } + GC.collect(); // GC create thread + + sigprocmask(SIG_BLOCK, &m, null); // block SIGHUP from delivery to main thread + + auto parent_pid = getpid(); + auto child_pid = fork(); + assert(child_pid >= 0); + if (child_pid == 0) + { + kill(parent_pid, SIGHUP); // send signal to parent + _exit(0); + } + // parent + Thread.sleep(100.msecs); + // if we are here, then GC threads didn't receive SIGHUP, + // otherwise whole process killed + _exit(0); + } +} diff --git a/libphobos/testsuite/libphobos.gc/startbackgc.d b/libphobos/testsuite/libphobos.gc/startbackgc.d new file mode 100644 index 00000000000..bf51fbdbefe --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/startbackgc.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=20270 +import core.sys.posix.sys.wait : waitpid; +import core.sys.posix.unistd : fork, _exit; +import core.thread : Thread; + +void main() +{ + foreach (t; 0 .. 10) + new Thread({ + foreach (n; 0 .. 100) + { + foreach (x; 0 .. 100) + new ubyte[x]; + auto f = fork(); + assert(f >= 0); + if (f == 0) + _exit(0); + else + waitpid(f, null, 0); + } + }).start(); +} diff --git a/libphobos/testsuite/libphobos.hash/test_hash.d b/libphobos/testsuite/libphobos.hash/test_hash.d index b40626659b7..d0a8e5fb809 100644 --- a/libphobos/testsuite/libphobos.hash/test_hash.d +++ b/libphobos/testsuite/libphobos.hash/test_hash.d @@ -1,3 +1,5 @@ +// { dg-prune-output "Warning: struct HasNonConstToHash has method toHash" } +// { dg-prune-output "HasNonConstToHash.toHash defined here:" } void main() { issue19562(); @@ -8,8 +10,14 @@ void main() issue19005(); issue19204(); issue19262(); + issue19282(); + issue19332(); // Support might be removed in the future! issue19568(); issue19582(); + issue20034(); + issue21642(); + issue22024(); + issue22076(); testTypeInfoArrayGetHash1(); testTypeInfoArrayGetHash2(); pr2243(); @@ -130,6 +138,30 @@ void issue19262() nothrow h = hashOf(aa, h); } +extern(C++) class Issue19282CppClass {} + +/// test that hashOf doesn't crash for non-null C++ objects. +void issue19282() +{ + Issue19282CppClass c = new Issue19282CppClass(); + size_t h = hashOf(c); + h = hashOf(c, h); +} + +/// Ensure hashOf works for const struct that has non-const toHash & has all +/// fields bitwise-hashable. (Support might be removed in the future!) +void issue19332() +{ + static struct HasNonConstToHash + { + int a; + size_t toHash() { return a; } + } + const HasNonConstToHash val; + size_t h = hashOf(val); + h = hashOf!(const HasNonConstToHash)(val); // Ensure doesn't match more than one overload. +} + /// hashOf should not unnecessarily call a struct's fields' postblits & dtors in CTFE void issue19568() { @@ -189,11 +221,99 @@ void issue19582() } } enum b2 = () { - S[10] a; - return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(a); + return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(new S[10]); }(); } +/// Check core.internal.hash.hashOf works with enums of non-scalar values +void issue20034() +{ + enum E + { + a = "foo" + } + // should compile + assert(hashOf(E.a, 1)); +} + +/// [REG 2.084] hashOf will fail to compile for some structs/unions that recursively contain shared enums +void issue21642() @safe nothrow pure +{ + enum C : char { _ = 1, } + union U { C c; void[0] _; } + shared union V { U u; } + cast(void) hashOf(V.init); + // Also test the underlying reason the above was failing. + import core.internal.convert : toUbyte; + shared C c; + assert(toUbyte(c) == [ubyte(1)]); +} + +/// Accept enum type whose ultimate base type is a SIMD vector. +void issue22024() @nogc nothrow pure @safe +{ + static if (is(__vector(float[2]))) + { + enum E2 : __vector(float[2]) { a = __vector(float[2]).init, } + enum F2 : E2 { a = E2.init, } + assert(hashOf(E2.init) == hashOf(F2.init)); + assert(hashOf(E2.init, 1) == hashOf(F2.init, 1)); + } + static if (is(__vector(float[4]))) + { + enum E4 : __vector(float[4]) { a = __vector(float[4]).init, } + enum F4 : E4 { a = E4.init, } + assert(hashOf(E4.init) == hashOf(F4.init)); + assert(hashOf(E4.init, 1) == hashOf(F4.init, 1)); + } +} + +/// hashOf(S) can segfault if S.toHash is forwarded via `alias this` to a +/// receiver which may be null. +void issue22076() +{ + static struct S0 { Object a; alias a this; } + + static struct S1 + { + S0 a; + inout(S0)* b() inout nothrow { return &a; } + alias b this; + } + + static struct S2 + { + S0 a; + S1 b; + } + + extern(C++) static class C0 + { + int foo() { return 0; } // Need at least one function in vtable. + S0 a; alias a this; + } + + extern(C++) static class C1 + { + S1 a; + inout(S1)* b() inout nothrow { return &a; } + alias b this; + } + + cast(void) hashOf(S0.init); + cast(void) hashOf(S0.init, 0); + cast(void) hashOf(S1.init); + cast(void) hashOf(S1.init, 0); + cast(void) hashOf(S2.init); + cast(void) hashOf(S2.init, 0); + auto c0 = new C0(); + cast(void) hashOf(c0); + cast(void) hashOf(c0, 0); + auto c1 = new C1(); + cast(void) hashOf(c1); + cast(void) hashOf(c1, 0); +} + /// Tests ensure TypeInfo_Array.getHash uses element hash functions instead /// of hashing array data. void testTypeInfoArrayGetHash1() @@ -300,11 +420,9 @@ void pr2243() enum Bar vsexpr = Bar(); enum int[int] aaexpr = [99:2, 12:6, 45:4]; enum Gun eexpr = Gun.A; - enum cdouble cexpr = 7+4i; enum Foo[] staexpr = [Foo(), Foo(), Foo()]; enum Bar[] vsaexpr = [Bar(), Bar(), Bar()]; enum realexpr = 7.88; - enum raexpr = [8.99L+86i, 3.12L+99i, 5.66L+12i]; enum nullexpr = null; enum plstr = Plain(); enum plarrstr = [Plain(), Plain(), Plain()]; @@ -328,7 +446,6 @@ void pr2243() enum h10 = vsexpr.hashOf(); enum h11 = aaexpr.hashOf(); enum h12 = eexpr.hashOf(); - enum h13 = cexpr.hashOf(); enum h14 = hashOf(new Boo); enum h15 = staexpr.hashOf(); enum h16 = hashOf([new Boo, new Boo, new Boo]); @@ -349,7 +466,6 @@ void pr2243() auto h27 = ptrexpr.hashOf(); enum h28 = realexpr.hashOf(); - enum h29 = raexpr.hashOf(); enum h30 = nullexpr.hashOf(); enum h31 = plstr.hashOf(); enum h32 = plarrstr.hashOf(); @@ -367,7 +483,6 @@ void pr2243() auto v10 = vsexpr; auto v11 = aaexpr; auto v12 = eexpr; - auto v13 = cexpr; auto v14 = new Boo; auto v15 = staexpr; auto v16 = [new Boo, new Boo, new Boo]; @@ -389,7 +504,6 @@ void pr2243() auto v26 = dgexpr; auto v27 = ptrexpr; auto v28 = realexpr; - auto v29 = raexpr; //runtime hashes auto rth1 = hashOf(v1); @@ -404,7 +518,6 @@ void pr2243() auto rth10 = hashOf(v10); auto rth11 = hashOf(v11); auto rth12 = hashOf(v12); - auto rth13 = hashOf(v13); auto rth14 = hashOf(v14); auto rth15 = hashOf(v15); auto rth16 = hashOf(v16); @@ -422,7 +535,6 @@ void pr2243() auto rth26 = hashOf(v26); auto rth27 = hashOf(v27); auto rth28 = hashOf(v28); - auto rth29 = hashOf(v29); auto rth31 = hashOf(v31); auto rth32 = hashOf(v32); @@ -440,7 +552,6 @@ void pr2243() assert(h10 == rth10); assert(h11 == rth11); assert(h12 == rth12); - assert(h13 == rth13); assert(h14 == rth14); assert(h15 == rth15); assert(h16 == rth16); @@ -455,8 +566,7 @@ void pr2243() assert(h25 == rth25); assert(h26 == rth26); assert(h27 == rth27); - assert(h28 == rth28); - assert(h29 == rth29);*/ + assert(h28 == rth28);*/ assert(h30 == rth30); assert(h31 == rth31); assert(h32 == rth32); @@ -482,7 +592,6 @@ void pr2243() auto tih10 = tiHashOf(v10); auto tih11 = tiHashOf(v11); auto tih12 = tiHashOf(v12); - auto tih13 = tiHashOf(v13); auto tih14 = tiHashOf(v14); auto tih15 = tiHashOf(v15); auto tih16 = tiHashOf(v16); @@ -498,7 +607,6 @@ void pr2243() auto tih26 = tiHashOf(v26); auto tih27 = tiHashOf(v27); auto tih28 = tiHashOf(v28); - auto tih29 = tiHashOf(v29); auto tih30 = tiHashOf(v30); auto tih31 = tiHashOf(v31); auto tih32 = tiHashOf(v32); @@ -516,7 +624,6 @@ void pr2243() //assert(tih10 == rth10); // need compiler-generated __xtoHash changes assert(tih11 == rth11); assert(tih12 == rth12); - assert(tih13 == rth13); assert(tih14 == rth14); assert(tih15 == rth15); assert(tih16 == rth16); @@ -532,7 +639,6 @@ void pr2243() assert(tih26 == rth26); assert(tih27 == rth27); assert(tih28 == rth28); - assert(tih29 == rth29); assert(tih30 == rth30); assert(tih31 == rth31); assert(tih32 == rth32); diff --git a/libphobos/testsuite/libphobos.imports/bug18193.d b/libphobos/testsuite/libphobos.imports/bug18193.d new file mode 100644 index 00000000000..fc8f5ca6882 --- /dev/null +++ b/libphobos/testsuite/libphobos.imports/bug18193.d @@ -0,0 +1,4 @@ +// { dg-options "-fversion=Shared" } +// { dg-do compile } +import core.runtime; +import core.thread; diff --git a/libphobos/testsuite/libphobos.init_fini/custom_gc.d b/libphobos/testsuite/libphobos.init_fini/custom_gc.d new file mode 100644 index 00000000000..a5e2bf40356 --- /dev/null +++ b/libphobos/testsuite/libphobos.init_fini/custom_gc.d @@ -0,0 +1,203 @@ +import core.gc.registry; +import core.gc.gcinterface; +import core.stdc.stdlib; + +static import core.memory; + +extern (C) __gshared string[] rt_options = ["gcopt=gc:malloc"]; + +extern (C) pragma(crt_constructor) void register_mygc() +{ + registerGCFactory("malloc", &MallocGC.initialize); +} + +extern (C) void register_default_gcs() +{ + // remove default GCs +} + +/** Simple GC that requires any pointers passed to it's API + to point to start of the allocation. + */ +class MallocGC : GC +{ +nothrow @nogc: + static GC initialize() + { + import core.stdc.string : memcpy; + + __gshared ubyte[__traits(classInstanceSize, MallocGC)] buf; + + auto init = typeid(MallocGC).initializer(); + assert(init.length == buf.length); + auto instance = cast(MallocGC) memcpy(buf.ptr, init.ptr, init.length); + instance.__ctor(); + return instance; + } + + this() + { + } + + void Dtor() + { + } + + void enable() + { + } + + void disable() + { + } + + void collect() nothrow + { + } + + void collectNoStack() nothrow + { + } + + void minimize() nothrow + { + } + + uint getAttr(void* p) nothrow + { + return 0; + } + + uint setAttr(void* p, uint mask) nothrow + { + return mask; + } + + uint clrAttr(void* p, uint mask) nothrow + { + return mask; + } + + void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow + { + return sentinelAdd(.malloc(size + sentinelSize), size); + } + + BlkInfo qalloc(size_t size, uint bits, const scope TypeInfo ti) nothrow + { + return BlkInfo(malloc(size, bits, ti), size); + } + + void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow + { + return sentinelAdd(.calloc(1, size + sentinelSize), size); + } + + void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow + { + return sentinelAdd(.realloc(p - sentinelSize, size + sentinelSize), size); + } + + size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow + { + return 0; + } + + size_t reserve(size_t size) nothrow + { + return 0; + } + + void free(void* p) nothrow + { + free(p - sentinelSize); + } + + void* addrOf(void* p) nothrow + { + return p; + } + + size_t sizeOf(void* p) nothrow + { + return query(p).size; + } + + BlkInfo query(void* p) nothrow + { + return p ? BlkInfo(p, sentinelGet(p)) : BlkInfo.init; + } + + core.memory.GC.Stats stats() nothrow + { + return core.memory.GC.Stats.init; + } + + core.memory.GC.ProfileStats profileStats() nothrow + { + return typeof(return).init; + } + + void addRoot(void* p) nothrow @nogc + { + } + + void removeRoot(void* p) nothrow @nogc + { + } + + @property RootIterator rootIter() @nogc + { + return null; + } + + void addRange(void* p, size_t sz, const TypeInfo ti) nothrow @nogc + { + } + + void removeRange(void* p) nothrow @nogc + { + } + + @property RangeIterator rangeIter() @nogc + { + return null; + } + + void runFinalizers(const scope void[] segment) nothrow + { + } + + bool inFinalizer() nothrow + { + return false; + } + + ulong allocatedInCurrentThread() nothrow + { + return stats().allocatedInCurrentThread; + } + +private: + // doesn't care for alignment + static void* sentinelAdd(void* p, size_t value) + { + *cast(size_t*) p = value; + return p + sentinelSize; + } + + static size_t sentinelGet(void* p) + { + return *cast(size_t*)(p - sentinelSize); + } + + enum sentinelSize = size_t.sizeof; +} + +void main() +{ + // test array append cache + char[] s; + foreach (char c; char.min .. char.max + 1) + s ~= c; +} diff --git a/libphobos/testsuite/libphobos.init_fini/test18996.d b/libphobos/testsuite/libphobos.init_fini/test18996.d new file mode 100644 index 00000000000..01d514cd563 --- /dev/null +++ b/libphobos/testsuite/libphobos.init_fini/test18996.d @@ -0,0 +1,13 @@ +// Issue https://issues.dlang.org/show_bug.cgi?id=18996 +// Array!string calls removeRange without first adding the range, but never +// initializes the GC. The behavior of the default GC is to ignore removing +// ranges when the range wasn't added. The ProtoGC originally would crash when +// this happened. + +import core.memory; + +void main() +{ + GC.removeRange(null); + GC.removeRoot(null); +} diff --git a/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d b/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d new file mode 100644 index 00000000000..bc0695ed57d --- /dev/null +++ b/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d @@ -0,0 +1,78 @@ +// https://issues.dlang.org/show_bug.cgi?id=21097 + +// The crucial part of the test cases is testing `destroy`. At the same time, we test +// `core.internal.lifetime.emplaceInitializer` (which is currently called by `destroy`). + +enum SIZE = 10_000_000; // 10 MB should exhaust the stack on most if not all test systems. + +import core.internal.lifetime; + +void test_largestruct() +{ + static struct LargeStruct + { + int[SIZE/2] a1; + int b = 42; + int[SIZE/2] a2; + } + static LargeStruct s = void; + emplaceInitializer(s); + assert(s.b == 42); + s.b = 101; + destroy(s); + assert(s.b == 42); +} + +void test_largestruct_w_opassign() +{ + static struct LargeStructOpAssign + { + int[SIZE/2] a1; + int b = 420; // non-zero init + int[SIZE/2] a2; + + void opAssign(typeof(this)) {} // hasElaborateAssign == true + } + static LargeStructOpAssign s = void; + emplaceInitializer(s); + assert(s.b == 420); + s.b = 101; + destroy(s); + assert(s.b == 420); +} + +void test_largearray() { + static struct NonZero + { + int i = 123; + } + static NonZero[SIZE] s = void; + emplaceInitializer(s); + assert(s[SIZE/2] == NonZero.init); + s[10] = NonZero(101); + destroy(s); + assert(s[10] == NonZero.init); +} + +void test_largearray_w_opassign() { + static struct NonZeroWithOpAssign + { + int i = 123; + void opAssign(typeof(this)) {} // hasElaborateAssign == true + } + static NonZeroWithOpAssign[SIZE] s = void; + emplaceInitializer(s); + assert(s[SIZE/2] == NonZeroWithOpAssign.init); + s[10] = NonZeroWithOpAssign(101); + destroy(s); + assert(s[10] == NonZeroWithOpAssign.init); +} + +int main() +{ + test_largestruct(); + test_largestruct_w_opassign(); + test_largearray(); + test_largearray_w_opassign(); + return 0; +} diff --git a/libphobos/testsuite/libphobos.shared/host.c b/libphobos/testsuite/libphobos.shared/host.c index 81e896aa3d8..395ad0c3f55 100644 --- a/libphobos/testsuite/libphobos.shared/host.c +++ b/libphobos/testsuite/libphobos.shared/host.c @@ -10,6 +10,11 @@ int main(int argc, char* argv[]) void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime assert(druntime); #endif +#if defined(__DragonFly__) + // 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")); @@ -55,6 +60,9 @@ int main(int argc, char* argv[]) #if defined(__FreeBSD__) dlclose(druntime); +#endif +#if defined(__DragonFly__) + dlclose(druntime); #endif return EXIT_SUCCESS; } diff --git a/libphobos/testsuite/libphobos.shared/link_mod_collision.d b/libphobos/testsuite/libphobos.shared/link_mod_collision.d deleted file mode 100644 index 9c3d1c7b235..00000000000 --- a/libphobos/testsuite/libphobos.shared/link_mod_collision.d +++ /dev/null @@ -1,5 +0,0 @@ -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 index 5a2dd01b778..0d3ffa65d6e 100644 --- a/libphobos/testsuite/libphobos.shared/load.d +++ b/libphobos/testsuite/libphobos.shared/load.d @@ -2,7 +2,6 @@ import core.runtime; import core.stdc.stdio; import core.stdc.string; import core.thread; - import core.sys.posix.dlfcn; version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_NOLOAD; diff --git a/libphobos/testsuite/libphobos.shared/load_13414.d b/libphobos/testsuite/libphobos.shared/load_13414.d index f7cbf45190a..047d5079937 100644 --- a/libphobos/testsuite/libphobos.shared/load_13414.d +++ b/libphobos/testsuite/libphobos.shared/load_13414.d @@ -16,8 +16,17 @@ void runTest(string name) *cast(void function()*).dlsym(h, "_D9lib_1341420sharedStaticDtorHookOPFZv") = &sharedStaticDtorHook; Runtime.unloadLibrary(h); - assert(tlsDtor == 1); - assert(dtor == 1); + version (CRuntime_Musl) + { + // On Musl, unloadLibrary is a no-op because dlclose is a no-op + assert(tlsDtor == 0); + assert(dtor == 0); + } + else + { + assert(tlsDtor == 1); + assert(dtor == 1); + } } void main(string[] args) diff --git a/libphobos/testsuite/libphobos.shared/load_mod_collision.d b/libphobos/testsuite/libphobos.shared/load_mod_collision.d deleted file mode 100644 index 64243d4b7bb..00000000000 --- a/libphobos/testsuite/libphobos.shared/load_mod_collision.d +++ /dev/null @@ -1,14 +0,0 @@ -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.thread/external_threads.d b/libphobos/testsuite/libphobos.thread/external_threads.d new file mode 100644 index 00000000000..9c98a3fa13d --- /dev/null +++ b/libphobos/testsuite/libphobos.thread/external_threads.d @@ -0,0 +1,50 @@ +import core.sys.posix.pthread; +import core.memory; +import core.thread; + +extern (C) void rt_moduleTlsCtor(); +extern (C) void rt_moduleTlsDtor(); + +extern(C) +void* entry_point1(void*) +{ + // try collecting - GC must ignore this call because this thread + // is not registered in runtime + GC.collect(); + return null; +} + +extern(C) +void* entry_point2(void*) +{ + // This thread gets registered in druntime, does some work and gets + // unregistered to be cleaned up manually + thread_attachThis(); + rt_moduleTlsCtor(); + + auto x = new int[10]; + + rt_moduleTlsDtor(); + thread_detachThis(); + return null; +} + +void main() +{ + // allocate some garbage + auto x = new int[1000]; + + { + pthread_t thread; + auto status = pthread_create(&thread, null, &entry_point1, null); + assert(status == 0); + pthread_join(thread, null); + } + + { + pthread_t thread; + auto status = pthread_create(&thread, null, &entry_point2, null); + assert(status == 0); + pthread_join(thread, null); + } +} diff --git a/libphobos/testsuite/libphobos.thread/fiber_guard_page.d b/libphobos/testsuite/libphobos.thread/fiber_guard_page.d index ca54a19857f..dbdd0f9d08d 100644 --- a/libphobos/testsuite/libphobos.thread/fiber_guard_page.d +++ b/libphobos/testsuite/libphobos.thread/fiber_guard_page.d @@ -4,6 +4,9 @@ import core.thread; import core.sys.posix.signal; import core.sys.posix.sys.mman; +version (LDC) import ldc.attributes; +else struct optStrategy { string a; } + // this should be true for most architectures // (taken from core.thread) version (GNU_StackGrowsDown) @@ -12,6 +15,7 @@ version (GNU_StackGrowsDown) enum stackSize = MINSIGSTKSZ; // Simple method that causes a stack overflow +@optStrategy("none") void stackMethod() { // Over the stack size, so it overflows the stack diff --git a/libphobos/testsuite/libphobos.thread/join_detach.d b/libphobos/testsuite/libphobos.thread/join_detach.d new file mode 100644 index 00000000000..f1515190171 --- /dev/null +++ b/libphobos/testsuite/libphobos.thread/join_detach.d @@ -0,0 +1,20 @@ +import core.thread; +import core.sync.semaphore; + +__gshared Semaphore sem; + +void thread_main () +{ + sem.notify(); +} + +void main() +{ + auto th = new Thread(&thread_main); + sem = new Semaphore(); + th.start(); + sem.wait(); + while (th.isRunning()) {} + destroy(th); // force detach + th.join(); +} diff --git a/libphobos/testsuite/libphobos.thread/test_import.d b/libphobos/testsuite/libphobos.thread/test_import.d new file mode 100644 index 00000000000..dfa0487d916 --- /dev/null +++ b/libphobos/testsuite/libphobos.thread/test_import.d @@ -0,0 +1,7 @@ +// https://issues.dlang.org/show_bug.cgi?id=20447 +void main() +{ + import core.thread; + int[] x; + auto b = x.dup; +} diff --git a/libphobos/testsuite/libphobos.thread/tlsgc_sections.d b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d index 1421d926a38..1bd3f26cffc 100644 --- a/libphobos/testsuite/libphobos.thread/tlsgc_sections.d +++ b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d @@ -1,39 +1,70 @@ -final class Class +import core.memory; +import core.sync.condition; +import core.sync.mutex; +import core.thread; + +__gshared Condition g_cond; +__gshared Mutex g_mutex; +__gshared int g_step = 0; + +class C { - // This gets triggered although the instance always stays referenced. ~this() { import core.stdc.stdlib; - abort(); + abort(); // this gets triggered although the instance always stays referenced } } -Class obj; +C c; static this() { - obj = new Class; + c = new C; } static ~this() { - // Free without destruction to avoid triggering abort() import core.memory; - GC.free(cast(void*)obj); + GC.free(cast(void*)c); // free without destruction to avoid triggering abort() } -void doit() +void test() { - foreach (i; 0 .. 10_000) - new ubyte[](100_000); + assert(c !is null); + + // notify the main thread of the finished initialization + synchronized (g_mutex) g_step = 1; + g_cond.notifyAll(); + + // wait until the GC collection is done + synchronized (g_mutex) { + while (g_step != 2) + g_cond.wait(); + } } + void main() { - import core.thread; - auto t = new Thread(&doit); - t.start(); + g_mutex = new Mutex; + g_cond = new Condition(g_mutex); + + auto th = new Thread(&test); + th.start(); + + // wait for thread to be fully initialized + synchronized (g_mutex) { + while (g_step != 1) + g_cond.wait(); + } + + // this causes the other thread's C instance to be reaped with the bug present + GC.collect(); + + // allow the thread to shut down + synchronized (g_mutex) g_step = 2; + g_cond.notifyAll(); - // This triggers the GC that frees the still referenced Class instance. - doit(); + th.join(); } diff --git a/libphobos/testsuite/libphobos.thread/tlsstack.d b/libphobos/testsuite/libphobos.thread/tlsstack.d new file mode 100644 index 00000000000..dbd93213bfe --- /dev/null +++ b/libphobos/testsuite/libphobos.thread/tlsstack.d @@ -0,0 +1,38 @@ +module core.thread.test; // needs access to getStackTop()/getStackBottom() + +import core.stdc.stdio; +import core.thread; + +ubyte[16384] data; + +void showThreadInfo() nothrow +{ + try + { + auto top = getStackTop(); + auto bottom = getStackBottom(); + printf("tlsdata: %p\n", data.ptr); + printf("stack top: %p\n", getStackTop()); + printf("stack bottom:%p\n", getStackBottom()); + printf("used stack: %lld\n", cast(ulong)(bottom - top)); + } + catch(Exception e) + { + assert(false, e.msg); + } +} + +void main() +{ + printf("### main\n"); + showThreadInfo(); + + printf("### thread\n"); + auto th = new Thread(&showThreadInfo, 16384); + th.start(); + th.join(); + + printf("### lowlevel thread\n"); + auto llth = createLowLevelThread(() { showThreadInfo(); }); + joinLowLevelThread(llth); +} diff --git a/libphobos/testsuite/libphobos.typeinfo/enum_.d b/libphobos/testsuite/libphobos.typeinfo/enum_.d new file mode 100644 index 00000000000..58cfbe34d60 --- /dev/null +++ b/libphobos/testsuite/libphobos.typeinfo/enum_.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=21441 + +int dtorCount; +int postblitCount; + +struct S +{ + this(this) { ++postblitCount; } + ~this() { ++dtorCount; } +} + +enum E : S { _ = S.init } + +void main() +{ + E e; + typeid(e).destroy(&e); + assert(dtorCount == 1); + typeid(e).postblit(&e); + assert(postblitCount == 1); +} diff --git a/libphobos/testsuite/libphobos.typeinfo/isbaseof.d b/libphobos/testsuite/libphobos.typeinfo/isbaseof.d new file mode 100644 index 00000000000..26dd5a66e3e --- /dev/null +++ b/libphobos/testsuite/libphobos.typeinfo/isbaseof.d @@ -0,0 +1,46 @@ +// https://issues.dlang.org/show_bug.cgi?id=20178 + +interface I {} +interface J : I {} +interface K(T) {} +class C1 : I {} +class C2 : C1 {} +class C3 : J {} +class C4(T) : C3, K!T {} +class C5(T) : C4!T {} + +void main() @nogc nothrow pure @safe +{ + assert(typeid(C1).isBaseOf(typeid(C1))); + assert(typeid(C1).isBaseOf(typeid(C2))); + + assert(!typeid(C2).isBaseOf(typeid(C1))); + assert(typeid(C2).isBaseOf(typeid(C2))); + + assert(!typeid(C1).isBaseOf(typeid(Object))); + assert(!typeid(C2).isBaseOf(typeid(Object))); + assert(typeid(Object).isBaseOf(typeid(C1))); + assert(typeid(Object).isBaseOf(typeid(C2))); + + assert(typeid(I).isBaseOf(typeid(I))); + assert(typeid(I).isBaseOf(typeid(J))); + assert(typeid(I).isBaseOf(typeid(C1))); + assert(typeid(I).isBaseOf(typeid(C2))); + assert(typeid(I).isBaseOf(typeid(C3))); + assert(!typeid(I).isBaseOf(typeid(Object))); + + assert(!typeid(J).isBaseOf(typeid(I))); + assert(typeid(J).isBaseOf(typeid(J))); + assert(!typeid(J).isBaseOf(typeid(C1))); + assert(!typeid(J).isBaseOf(typeid(C2))); + assert(typeid(J).isBaseOf(typeid(C3))); + assert(!typeid(J).isBaseOf(typeid(Object))); + + assert(typeid(C4!int).isBaseOf(typeid(C5!int))); + assert(typeid(K!int).isBaseOf(typeid(C5!int))); + assert(!typeid(C4!Object).isBaseOf(typeid(C5!int))); + assert(!typeid(K!Object).isBaseOf(typeid(C5!int))); + + static assert(!__traits(compiles, TypeInfo.init.isBaseOf(typeid(C1)))); + static assert(!__traits(compiles, typeid(C1).isBaseOf(TypeInfo.init))); +} diff --git a/libphobos/testsuite/libphobos.unittest/customhandler.d b/libphobos/testsuite/libphobos.unittest/customhandler.d new file mode 100644 index 00000000000..f5a04350d9c --- /dev/null +++ b/libphobos/testsuite/libphobos.unittest/customhandler.d @@ -0,0 +1,21 @@ +import core.runtime; + +UnitTestResult customModuleUnitTester() +{ + version(GoodTests) return UnitTestResult(100, 100, false, true); + version(FailedTests) return UnitTestResult(100, 0, false, true); + version(NoTests) return UnitTestResult(0, 0, true, false); + version(FailNoPrintout) return UnitTestResult(100, 0, false, false); + version(PassNoPrintout) return UnitTestResult(100, 100, false, false); +} + +shared static this() +{ + Runtime.extendedModuleUnitTester = &customModuleUnitTester; +} + +void main() +{ + import core.stdc.stdio; + fprintf(stderr, "main\n"); +}