diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-07-26 17:42:23 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-08-03 13:01:53 +0200 |
commit | b6df113247b9f3f7c3db0e65c481dad5bcfddfb4 (patch) | |
tree | 31466a07292ad0cc289de7c23e39ba31b9e8b7c3 /libphobos | |
parent | 64ce76d940501cb04d14a0d36752b4f93473531c (diff) | |
download | gcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.zip gcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.tar.gz gcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.tar.bz2 |
d: Merge upstream dmd d7772a2369, phobos 5748ca43f.
In upstream dmd, the compiler front-end and run-time have been merged
together into one repository. Both dmd and libdruntime now track that.
D front-end changes:
- Deprecated `scope(failure)' blocks that contain `return' statements.
- Deprecated using integers for `version' or `debug' conditions.
- Deprecated returning a discarded void value from a function.
- `new' can now allocate an associative array.
D runtime changes:
- Added avx512f detection to core.cpuid module.
Phobos changes:
- Changed std.experimental.logger.core.sharedLog to return
shared(Logger).
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd d7772a2369.
* dmd/VERSION: Bump version to v2.100.1.
* d-codegen.cc (get_frameinfo): Check whether decision to generate
closure changed since semantic finished.
* d-lang.cc (d_handle_option): Remove handling of -fdebug=level and
-fversion=level.
* decl.cc (DeclVisitor::visit (VarDeclaration *)): Generate evaluation
of noreturn variable initializers before throw.
* expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate
assignment for noreturn types, only evaluate for side effects.
* lang.opt (fdebug=): Undocument -fdebug=level.
(fversion=): Undocument -fversion=level.
libphobos/ChangeLog:
* configure: Regenerate.
* configure.ac (libtool_VERSION): Update to 4:0:0.
* libdruntime/MERGE: Merge upstream druntime d7772a2369.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
core/internal/array/duplication.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 5748ca43f.
* testsuite/libphobos.gc/nocollect.d:
Diffstat (limited to 'libphobos')
55 files changed, 971 insertions, 690 deletions
diff --git a/libphobos/configure b/libphobos/configure index 9da06f0..69d2d44 100755 --- a/libphobos/configure +++ b/libphobos/configure @@ -15554,7 +15554,7 @@ SPEC_PHOBOS_DEPS="$LIBS" # Libdruntime / phobos soname version -libtool_VERSION=3:0:0 +libtool_VERSION=4:0:0 # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/configure.ac b/libphobos/configure.ac index 31209ba..8bdf733 100644 --- a/libphobos/configure.ac +++ b/libphobos/configure.ac @@ -253,7 +253,7 @@ SPEC_PHOBOS_DEPS="$LIBS" AC_SUBST(SPEC_PHOBOS_DEPS) # Libdruntime / phobos soname version -libtool_VERSION=3:0:0 +libtool_VERSION=4:0:0 AC_SUBST(libtool_VERSION) # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 6e25a9d..c358b69 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -651389b52243dcadb338dd0c14dd27e7850cda8d +d7772a236983ec37b92d21b28bad3cd2de57b945 The first line of this file holds the git revision number of the last -merge done from the dlang/druntime repository. +merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 56b332d..2e1e91d 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -174,14 +174,14 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/array/appending.d core/internal/array/capacity.d \ core/internal/array/casting.d core/internal/array/comparison.d \ core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/equality.d core/internal/array/operations.d \ - core/internal/array/utils.d core/internal/atomic.d \ - core/internal/attributes.d core/internal/container/array.d \ - core/internal/container/common.d core/internal/container/hashtab.d \ - core/internal/container/treap.d core/internal/convert.d \ - core/internal/dassert.d core/internal/destruction.d \ - core/internal/entrypoint.d core/internal/gc/bits.d \ - core/internal/gc/impl/conservative/gc.d \ + core/internal/array/duplication.d core/internal/array/equality.d \ + core/internal/array/operations.d core/internal/array/utils.d \ + core/internal/atomic.d core/internal/attributes.d \ + core/internal/container/array.d core/internal/container/common.d \ + core/internal/container/hashtab.d core/internal/container/treap.d \ + core/internal/convert.d core/internal/dassert.d \ + core/internal/destruction.d core/internal/entrypoint.d \ + core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 24865fb..de6656c 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -196,6 +196,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ core/internal/array/comparison.lo \ core/internal/array/concatenation.lo \ core/internal/array/construction.lo \ + core/internal/array/duplication.lo \ core/internal/array/equality.lo \ core/internal/array/operations.lo core/internal/array/utils.lo \ core/internal/atomic.lo core/internal/attributes.lo \ @@ -841,14 +842,14 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/array/appending.d core/internal/array/capacity.d \ core/internal/array/casting.d core/internal/array/comparison.d \ core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/equality.d core/internal/array/operations.d \ - core/internal/array/utils.d core/internal/atomic.d \ - core/internal/attributes.d core/internal/container/array.d \ - core/internal/container/common.d core/internal/container/hashtab.d \ - core/internal/container/treap.d core/internal/convert.d \ - core/internal/dassert.d core/internal/destruction.d \ - core/internal/entrypoint.d core/internal/gc/bits.d \ - core/internal/gc/impl/conservative/gc.d \ + core/internal/array/duplication.d core/internal/array/equality.d \ + core/internal/array/operations.d core/internal/array/utils.d \ + core/internal/atomic.d core/internal/attributes.d \ + core/internal/container/array.d core/internal/container/common.d \ + core/internal/container/hashtab.d core/internal/container/treap.d \ + core/internal/convert.d core/internal/dassert.d \ + core/internal/destruction.d core/internal/entrypoint.d \ + core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ @@ -1208,6 +1209,8 @@ core/internal/array/concatenation.lo: \ core/internal/array/$(am__dirstamp) core/internal/array/construction.lo: \ core/internal/array/$(am__dirstamp) +core/internal/array/duplication.lo: \ + core/internal/array/$(am__dirstamp) core/internal/array/equality.lo: core/internal/array/$(am__dirstamp) core/internal/array/operations.lo: \ core/internal/array/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/cpuid.d b/libphobos/libdruntime/core/cpuid.d index e31f776..1c2ac06 100644 --- a/libphobos/libdruntime/core/cpuid.d +++ b/libphobos/libdruntime/core/cpuid.d @@ -170,6 +170,8 @@ public: bool hle() {return _hle;} /// Is RTM (restricted transactional memory) supported bool rtm() {return _rtm;} + /// Is AVX512F supported + bool avx512f() {return _avx512f;} /// Is rdseed supported bool hasRdseed() {return _hasRdseed;} /// Is SHA supported @@ -279,6 +281,7 @@ private immutable bool _avx2; bool _hle; bool _rtm; + bool _avx512f; bool _hasRdseed; bool _hasSha; bool _amd3dnow; @@ -389,6 +392,7 @@ CpuFeatures* getCpuFeatures() @nogc nothrow enum : uint { FSGSBASE_BIT = 1 << 0, + SGX_BIT = 1 << 2, BMI1_BIT = 1 << 3, HLE_BIT = 1 << 4, AVX2_BIT = 1 << 5, @@ -397,8 +401,19 @@ CpuFeatures* getCpuFeatures() @nogc nothrow ERMS_BIT = 1 << 9, INVPCID_BIT = 1 << 10, RTM_BIT = 1 << 11, + AVX512F_BIT = 1 << 16, + AVX512DQ_BIT = 1 << 17, RDSEED_BIT = 1 << 18, + ADX_BIT = 1 << 19, + AVX512IFMA_BIT = 1 << 21, + CLFLUSHOPT_BIT = 1 << 23, + CLWB_BIT = 1 << 24, + AVX512PF_BIT = 1 << 26, + AVX512ER_BIT = 1 << 27, + AVX512CD_BIT = 1 << 28, SHA_BIT = 1 << 29, + AVX512BW_BIT = 1 << 30, + AVX512VL_BIT = 1 << 31, } // feature flags XFEATURES_ENABLED_MASK enum : ulong @@ -1122,6 +1137,7 @@ shared static this() _avx2 = avx && (cf.extfeatures & AVX2_BIT) != 0; _hle = (cf.extfeatures & HLE_BIT) != 0; _rtm = (cf.extfeatures & RTM_BIT) != 0; + _avx512f = (cf.extfeatures & AVX512F_BIT) != 0; _hasRdseed = (cf.extfeatures&RDSEED_BIT)!=0; _hasSha = (cf.extfeatures&SHA_BIT)!=0; _amd3dnow = (cf.amdfeatures&AMD_3DNOW_BIT)!=0; diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d index e4326fd..46eb9b2 100644 --- a/libphobos/libdruntime/core/int128.d +++ b/libphobos/libdruntime/core/int128.d @@ -943,5 +943,3 @@ unittest assert(rol(C7_9, 1) == rol1(C7_9)); assert(ror(C7_9, 1) == ror1(C7_9)); } - - diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d index d416efe..616d27c 100644 --- a/libphobos/libdruntime/core/internal/array/appending.d +++ b/libphobos/libdruntime/core/internal/array/appending.d @@ -30,26 +30,14 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) * Returns: * The new value of `px` * Bugs: - * This function template was ported from a much older runtime hook that bypassed safety, - * purity, and throwabilty checks. To prevent breaking existing code, this function template - * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations. + * This function template was ported from a much older runtime hook that bypassed safety, + * purity, and throwabilty checks. To prevent breaking existing code, this function template + * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations. */ - static if (isCopyingNothrow!T) // `nothrow` deduction doesn't work, so this is needed - ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow - { - pragma(inline, false); - - mixin(_d_arrayappendcTXBody); - } - else - ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow - { - pragma(inline, false); - - mixin(_d_arrayappendcTXBody); - } - - private enum _d_arrayappendcTXBody = q{ + ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow + { + // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718 + pragma(inline, false); version (D_TypeInfo) { auto ti = typeid(Tarr); @@ -64,7 +52,7 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) } else assert(0, "Cannot append arrays if compiling without support for runtime type information!"); - }; + } /** * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl). diff --git a/libphobos/libdruntime/core/internal/array/duplication.d b/libphobos/libdruntime/core/internal/array/duplication.d new file mode 100644 index 0000000..41dfab6 --- /dev/null +++ b/libphobos/libdruntime/core/internal/array/duplication.d @@ -0,0 +1,346 @@ +/** +The `.dup` and `.idup` properties for Associative Arrays and Dynamic Arrays + +Copyright: Copyright Digital Mars 2000 - 2022. +License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + (See accompanying file LICENSE) +Source: $(DRUNTIMESRC core/internal/_array/_duplication.d) +*/ +module core.internal.array.duplication; + +private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow; + +U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) +{ + if (__ctfe) + return _dupCtfe!(T, U)(a); + + import core.stdc.string : memcpy; + auto arr = _d_newarrayU(typeid(T[]), a.length); + memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); + return *cast(U[]*) &arr; +} + +U[] _dupCtfe(T, U)(scope T[] a) +{ + static if (is(T : void)) + assert(0, "Cannot dup a void[] array at compile time."); + else + { + U[] res; + foreach (ref e; a) + res ~= e; + return res; + } +} + +U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)) +{ + // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch + // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`. + if (__ctfe) + return _dupCtfe!(T, U)(a); + + import core.lifetime: copyEmplace; + U[] res = () @trusted { + auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length); + size_t i; + scope (failure) + { + import core.internal.lifetime: emplaceInitializer; + // Initialize all remaining elements to not destruct garbage + foreach (j; i .. a.length) + emplaceInitializer(cast() arr[j]); + } + for (; i < a.length; i++) + { + copyEmplace(a.ptr[i], arr[i]); + } + return cast(U[])(arr[0..a.length]); + } (); + + return res; +} + +// https://issues.dlang.org/show_bug.cgi?id=22107 +@safe unittest +{ + static int i; + @safe struct S + { + this(this) { i++; } + } + + void fun(scope S[] values...) @safe + { + values.dup; + } +} + +@safe unittest +{ + static struct S1 { int* p; } + static struct S2 { @disable this(); } + static struct S3 { @disable this(this); } + + int dg1() pure nothrow @safe + { + { + char[] m; + string i; + m = m.dup; + i = i.idup; + m = i.dup; + i = m.idup; + } + { + S1[] m; + immutable(S1)[] i; + m = m.dup; + i = i.idup; + static assert(!is(typeof(m.idup))); + static assert(!is(typeof(i.dup))); + } + { + S3[] m; + immutable(S3)[] i; + static assert(!is(typeof(m.dup))); + static assert(!is(typeof(i.idup))); + } + { + shared(S1)[] m; + m = m.dup; + static assert(!is(typeof(m.idup))); + } + { + int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); + } + return 1; + } + + int dg2() pure nothrow @safe + { + { + S2[] m = [S2.init, S2.init]; + immutable(S2)[] i = [S2.init, S2.init]; + m = m.dup; + m = i.dup; + i = m.idup; + i = i.idup; + } + return 2; + } + + enum a = dg1(); + enum b = dg2(); + assert(dg1() == a); + assert(dg2() == b); +} + +@system unittest +{ + static struct Sunpure { this(this) @safe nothrow {} } + static struct Sthrow { this(this) @safe pure {} } + static struct Sunsafe { this(this) @system pure nothrow {} } + static struct Snocopy { @disable this(this); } + + [].dup!Sunpure; + [].dup!Sthrow; + cast(void) [].dup!Sunsafe; + static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); + static assert(!__traits(compiles, () { [].dup!Snocopy; })); + + [].idup!Sunpure; + [].idup!Sthrow; + [].idup!Sunsafe; + static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); + static assert(!__traits(compiles, () { [].idup!Snocopy; })); +} + +@safe unittest +{ + // test that the copy-constructor is called with .dup + static struct ArrElem + { + int a; + this(int a) + { + this.a = a; + } + this(ref const ArrElem) + { + a = 2; + } + this(ref ArrElem) immutable + { + a = 3; + } + } + + auto arr = [ArrElem(1), ArrElem(1)]; + + ArrElem[] b = arr.dup; + assert(b[0].a == 2 && b[1].a == 2); + + immutable ArrElem[] c = arr.idup; + assert(c[0].a == 3 && c[1].a == 3); +} + +@system unittest +{ + static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} } + static struct Sthrow { this(ref const typeof(this)) @safe pure {} } + static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} } + [].dup!Sunpure; + [].dup!Sthrow; + cast(void) [].dup!Sunsafe; + static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); + static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); + static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); + + // for idup to work on structs that have copy constructors, it is necessary + // that the struct defines a copy constructor that creates immutable objects + static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} } + static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} } + static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} } + [].idup!ISunpure; + [].idup!ISthrow; + [].idup!ISunsafe; + static assert(!__traits(compiles, () pure { [].idup!ISunpure; })); + static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; })); + static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; })); +} + +@safe unittest +{ + static int*[] pureFoo() pure { return null; } + { char[] s; immutable x = s.dup; } + { immutable x = (cast(int*[])null).dup; } + { immutable x = pureFoo(); } + { immutable x = pureFoo().dup; } +} + +@safe unittest +{ + auto a = [1, 2, 3]; + auto b = a.dup; + debug(SENTINEL) {} else + assert(b.capacity >= 3); +} + +@system unittest +{ + // Bugzilla 12580 + void[] m = [0]; + shared(void)[] s = [cast(shared)1]; + immutable(void)[] i = [cast(immutable)2]; + + s = s.dup; + static assert(is(typeof(s.dup) == shared(void)[])); + + m = i.dup; + i = m.dup; + i = i.idup; + i = m.idup; + i = s.idup; + i = s.dup; + static assert(!__traits(compiles, m = s.dup)); +} + +@safe unittest +{ + // Bugzilla 13809 + static struct S + { + this(this) {} + ~this() {} + } + + S[] arr; + auto a = arr.dup; +} + +@system unittest +{ + // Bugzilla 16504 + static struct S + { + __gshared int* gp; + int* p; + // postblit and hence .dup could escape + this(this) { gp = p; } + } + + int p; + scope S[1] arr = [S(&p)]; + auto a = arr.dup; // dup does escape +} + +// https://issues.dlang.org/show_bug.cgi?id=21983 +// dup/idup destroys partially constructed arrays on failure +@safe unittest +{ + static struct SImpl(bool postblit) + { + int num; + long l = 0xDEADBEEF; + + static if (postblit) + { + this(this) + { + if (this.num == 3) + throw new Exception(""); + } + } + else + { + this(scope ref const SImpl other) + { + if (other.num == 3) + throw new Exception(""); + + this.num = other.num; + this.l = other.l; + } + } + + ~this() @trusted + { + if (l != 0xDEADBEEF) + { + import core.stdc.stdio; + printf("Unexpected value: %lld\n", l); + fflush(stdout); + assert(false); + } + } + } + + alias Postblit = SImpl!true; + alias Copy = SImpl!false; + + static int test(S)() + { + S[4] arr = [ S(1), S(2), S(3), S(4) ]; + try + { + arr.dup(); + assert(false); + } + catch (Exception) + { + return 1; + } + } + + static assert(test!Postblit()); + assert(test!Postblit()); + + static assert(test!Copy()); + assert(test!Copy()); +} diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d index 2c51b86..07486c2 100644 --- a/libphobos/libdruntime/core/internal/dassert.d +++ b/libphobos/libdruntime/core/internal/dassert.d @@ -14,7 +14,7 @@ * * Copyright: D Language Foundation 2018 - 2020 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/internal/dassert.d, _dassert.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/dassert.d, _dassert.d) * Documentation: https://dlang.org/phobos/core_internal_dassert.html */ module core.internal.dassert; diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index d1378af..75e671c 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -4,7 +4,7 @@ * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/runtime.d, _runtime.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/runtime.d, _runtime.d) * Documentation: https://dlang.org/phobos/core_runtime.html */ diff --git a/libphobos/libdruntime/core/stdc/errno.d b/libphobos/libdruntime/core/stdc/errno.d index 24b4138..c992a5f 100644 --- a/libphobos/libdruntime/core/stdc/errno.d +++ b/libphobos/libdruntime/core/stdc/errno.d @@ -8,7 +8,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Alex Rønne Petersen - * Source: https://github.com/dlang/druntime/blob/master/src/core/stdc/errno.d + * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/errno.d * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d index 2e83811..fc98350 100644 --- a/libphobos/libdruntime/core/stdc/stdio.d +++ b/libphobos/libdruntime/core/stdc/stdio.d @@ -9,7 +9,7 @@ * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen - * Source: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d + * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/stdio.d * Standards: ISO/IEC 9899:1999 (E) */ @@ -1286,6 +1286,57 @@ version (MinGW) /// alias __mingw_scanf scanf; } +else version (CRuntime_Glibc) +{ + /// + pragma(printf) + int fprintf(FILE* stream, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_fscanf(FILE* stream, scope const char* format, scope ...); + /// + alias fscanf = __isoc99_fscanf; + /// + pragma(printf) + int sprintf(scope char* s, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_sscanf(scope const char* s, scope const char* format, scope ...); + /// + alias sscanf = __isoc99_sscanf; + /// + pragma(printf) + int vfprintf(FILE* stream, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vfscanf(FILE* stream, scope const char* format, va_list arg); + /// + alias vfscanf = __isoc99_vfscanf; + /// + pragma(printf) + int vsprintf(scope char* s, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vsscanf(scope const char* s, scope const char* format, va_list arg); + /// + alias vsscanf = __isoc99_vsscanf; + /// + pragma(printf) + int vprintf(scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vscanf(scope const char* format, va_list arg); + /// + alias vscanf = __isoc99_vscanf; + /// + pragma(printf) + int printf(scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_scanf(scope const char* format, scope ...); + /// + alias scanf = __isoc99_scanf; +} else { /// diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d index e8fb94b..d087029 100644 --- a/libphobos/libdruntime/core/stdc/wchar_.d +++ b/libphobos/libdruntime/core/stdc/wchar_.d @@ -127,30 +127,72 @@ alias wchar_t wint_t; /// enum wchar_t WEOF = 0xFFFF; -/// -int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); -/// -int fwscanf(FILE* stream, const scope wchar_t* format, scope ...); -/// -int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); -/// -int swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); -/// -int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); -/// -int vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); -/// -int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); -/// -int vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); -/// -int vwprintf(const scope wchar_t* format, va_list arg); -/// -int vwscanf(const scope wchar_t* format, va_list arg); -/// -int wprintf(const scope wchar_t* format, scope const ...); -/// -int wscanf(const scope wchar_t* format, scope ...); +version (CRuntime_Glibc) +{ + /// + int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); + /// + int __isoc99_fwscanf(FILE* stream, const scope wchar_t* format, scope ...); + /// + alias fwscanf = __isoc99_fwscanf; + /// + int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); + /// + int __isoc99_swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); + /// + alias swscanf = __isoc99_swscanf; + /// + int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int __isoc99_vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + alias vfwscanf = __isoc99_vfwscanf; + /// + int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); + /// + int __isoc99_vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); + /// + alias vswscanf = __isoc99_vswscanf; + /// + int vwprintf(const scope wchar_t* format, va_list arg); + /// + int __isoc99_vwscanf(const scope wchar_t* format, va_list arg); + /// + alias vwscanf = __isoc99_vwscanf; + /// + int wprintf(const scope wchar_t* format, scope const ...); + /// + int __isoc99_wscanf(const scope wchar_t* format, scope ...); + /// + alias wscanf = __isoc99_wscanf; +} +else +{ + /// + int fwprintf(FILE* stream, const scope wchar_t* format, scope const ...); + /// + int fwscanf(FILE* stream, const scope wchar_t* format, scope ...); + /// + int swprintf(wchar_t* s, size_t n, const scope wchar_t* format, scope const ...); + /// + int swscanf(const scope wchar_t* s, const scope wchar_t* format, scope ...); + /// + int vfwprintf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int vfwscanf(FILE* stream, const scope wchar_t* format, va_list arg); + /// + int vswprintf(wchar_t* s, size_t n, const scope wchar_t* format, va_list arg); + /// + int vswscanf(const scope wchar_t* s, const scope wchar_t* format, va_list arg); + /// + int vwprintf(const scope wchar_t* format, va_list arg); + /// + int vwscanf(const scope wchar_t* format, va_list arg); + /// + int wprintf(const scope wchar_t* format, scope const ...); + /// + int wscanf(const scope wchar_t* format, scope ...); +} // No unsafe pointer manipulation. @trusted diff --git a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d index fd1a8e4..dc42a2d 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d @@ -468,4 +468,3 @@ const(section)* getsectbynamefromheaderwithswap_64( const scope char* section, int fSwap ); - diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/string.d b/libphobos/libdruntime/core/sys/dragonflybsd/string.d index 4b84227..1a85ba6 100644 --- a/libphobos/libdruntime/core/sys/dragonflybsd/string.d +++ b/libphobos/libdruntime/core/sys/dragonflybsd/string.d @@ -19,4 +19,3 @@ static if (__BSD_VISIBLE) { pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } - diff --git a/libphobos/libdruntime/core/sys/linux/sys/time.d b/libphobos/libdruntime/core/sys/linux/sys/time.d index 6ea626e..4b56229 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/time.d +++ b/libphobos/libdruntime/core/sys/linux/sys/time.d @@ -65,4 +65,3 @@ extern (D) pure @safe @nogc nothrow { } } - diff --git a/libphobos/libdruntime/core/sys/linux/sys/xattr.d b/libphobos/libdruntime/core/sys/linux/sys/xattr.d index 2f8d3f37..6446ff8 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/xattr.d +++ b/libphobos/libdruntime/core/sys/linux/sys/xattr.d @@ -66,4 +66,3 @@ ssize_t flistxattr (int __fd, char *list, size_t size); int removexattr (const scope char *path, const scope char *name); int lremovexattr (const scope char *path, const scope char *name); int fremovexattr (int fd, const scope char *name); - diff --git a/libphobos/libdruntime/core/sys/linux/tipc.d b/libphobos/libdruntime/core/sys/linux/tipc.d index 3246e62..4d5d886 100644 --- a/libphobos/libdruntime/core/sys/linux/tipc.d +++ b/libphobos/libdruntime/core/sys/linux/tipc.d @@ -208,4 +208,3 @@ enum: int TIPC_DEST_DROPPABLE = 129, TIPC_CONN_TIMEOUT = 130, } - diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d index 68aee98..542e83a 100644 --- a/libphobos/libdruntime/core/sys/posix/signal.d +++ b/libphobos/libdruntime/core/sys/posix/signal.d @@ -14,7 +14,7 @@ module core.sys.posix.signal; import core.sys.posix.config; public import core.stdc.signal; public import core.sys.posix.sys.types; // for pid_t -//public import core.sys.posix.time; // for timespec, now defined here +public import core.sys.posix.time; // for timespec version (OSX) version = Darwin; @@ -2805,83 +2805,6 @@ else } // -// Timer (TMR) -// -/* -NOTE: This should actually be defined in core.sys.posix.time. - It is defined here instead to break a circular import. - -struct timespec -{ - time_t tv_sec; - int tv_nsec; -} -*/ - -version (linux) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (Darwin) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (FreeBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (NetBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (OpenBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (DragonFlyBSD) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } -} -else version (Solaris) -{ - struct timespec - { - time_t tv_sec; - c_long tv_nsec; - } - - alias timespec timestruc_t; -} -else -{ - static assert(false, "Unsupported platform"); -} - -// // Realtime Signals (RTS) // /* diff --git a/libphobos/libdruntime/core/sys/posix/spawn.d b/libphobos/libdruntime/core/sys/posix/spawn.d index cfa3a40..2064962 100644 --- a/libphobos/libdruntime/core/sys/posix/spawn.d +++ b/libphobos/libdruntime/core/sys/posix/spawn.d @@ -4,7 +4,7 @@ * Copyright: Copyright (C) 2018 by The D Language Foundation, All Rights Reserved * Authors: Petar Kirov * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/sys/posix/spawn.d, _spawn.d) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/sys/posix/spawn.d, _spawn.d) * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ module core.sys.posix.spawn; diff --git a/libphobos/libdruntime/core/sys/posix/stdio.d b/libphobos/libdruntime/core/sys/posix/stdio.d index 077838d..d0d3d60 100644 --- a/libphobos/libdruntime/core/sys/posix/stdio.d +++ b/libphobos/libdruntime/core/sys/posix/stdio.d @@ -487,7 +487,7 @@ else version (CRuntime_Musl) version (HaveMemstream) { - FILE* fmemopen(const scope void* buf, in size_t size, const scope char* mode); + FILE* fmemopen(const scope void* buf, size_t size, const scope char* mode); FILE* open_memstream(char** ptr, size_t* sizeloc); version (CRuntime_UClibc) {} else FILE* open_wmemstream(wchar_t** ptr, size_t* sizeloc); diff --git a/libphobos/libdruntime/core/sys/posix/sys/select.d b/libphobos/libdruntime/core/sys/posix/sys/select.d index 2a659c3..925976d 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/select.d +++ b/libphobos/libdruntime/core/sys/posix/sys/select.d @@ -608,4 +608,3 @@ pure unittest assert(!FD_ISSET(i, &fd)); } } - diff --git a/libphobos/libdruntime/core/sys/posix/time.d b/libphobos/libdruntime/core/sys/posix/time.d index a9be87c8..ff3a3c4 100644 --- a/libphobos/libdruntime/core/sys/posix/time.d +++ b/libphobos/libdruntime/core/sys/posix/time.d @@ -167,9 +167,6 @@ else CLOCK_PROCESS_CPUTIME_ID (TMR|CPT) CLOCK_THREAD_CPUTIME_ID (TMR|TCT) -NOTE: timespec must be defined in core.sys.posix.signal to break - a circular import. - struct timespec { time_t tv_sec; @@ -199,6 +196,69 @@ int timer_getoverrun(timer_t); int timer_settime(timer_t, int, const scope itimerspec*, itimerspec*); */ +version (linux) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (Darwin) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (FreeBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (NetBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (OpenBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (DragonFlyBSD) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } +} +else version (Solaris) +{ + struct timespec + { + time_t tv_sec; + c_long tv_nsec; + } + + alias timespec timestruc_t; +} +else +{ + static assert(false, "Unsupported platform"); +} + version (CRuntime_Glibc) { enum CLOCK_PROCESS_CPUTIME_ID = 2; diff --git a/libphobos/libdruntime/core/sys/posix/ucontext.d b/libphobos/libdruntime/core/sys/posix/ucontext.d index 20297f5..e8c2f87 100644 --- a/libphobos/libdruntime/core/sys/posix/ucontext.d +++ b/libphobos/libdruntime/core/sys/posix/ucontext.d @@ -1628,4 +1628,3 @@ version (Solaris) int addrtosymstr(uintptr_t, char*, int); int printstack(int); } - diff --git a/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d b/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d index bfbf3ee..c56be3b 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/priocntl.d @@ -113,4 +113,3 @@ struct pcadmin_t id_t pc_cid; caddr_t pc_cladmin; } - diff --git a/libphobos/libdruntime/core/sys/solaris/sys/procset.d b/libphobos/libdruntime/core/sys/solaris/sys/procset.d index 43fa997..8bd9115 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/procset.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/procset.d @@ -50,4 +50,3 @@ void setprocset(ref procset_t psp, idop_t op, idtype_t ltype, id_t lid, idtype_t psp.p_ridtype = rtype; psp.p_rid = rid; } - diff --git a/libphobos/libdruntime/core/sys/windows/cguid.d b/libphobos/libdruntime/core/sys/windows/cguid.d index 0afbc42..d0a8fb9 100644 --- a/libphobos/libdruntime/core/sys/windows/cguid.d +++ b/libphobos/libdruntime/core/sys/windows/cguid.d @@ -10,4 +10,3 @@ module core.sys.windows.cguid; version (Windows): import core.sys.windows.basetyps; - diff --git a/libphobos/libdruntime/core/sys/windows/ntsecpkg.d b/libphobos/libdruntime/core/sys/windows/ntsecpkg.d index d4c93d7..d8c5e95 100644 --- a/libphobos/libdruntime/core/sys/windows/ntsecpkg.d +++ b/libphobos/libdruntime/core/sys/windows/ntsecpkg.d @@ -444,4 +444,3 @@ alias NTSTATUS function(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG) SpLsaModeInitializeFn; alias NTSTATUS function(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG) SpUserModeInitializeFn; - diff --git a/libphobos/libdruntime/core/sys/windows/olectlid.d b/libphobos/libdruntime/core/sys/windows/olectlid.d index 8bbe657..b58c14a 100644 --- a/libphobos/libdruntime/core/sys/windows/olectlid.d +++ b/libphobos/libdruntime/core/sys/windows/olectlid.d @@ -10,4 +10,3 @@ module core.sys.windows.olectlid; version (Windows): import core.sys.windows.basetyps; - diff --git a/libphobos/libdruntime/core/sys/windows/shlguid.d b/libphobos/libdruntime/core/sys/windows/shlguid.d index 1c0c98f..e0c1af1 100644 --- a/libphobos/libdruntime/core/sys/windows/shlguid.d +++ b/libphobos/libdruntime/core/sys/windows/shlguid.d @@ -16,4 +16,3 @@ import core.sys.windows.basetyps, core.sys.windows.w32api; // I think this is just a helper macro for other win32 headers? //MACRO #define DEFINE_SHLGUID(n,l,w1,w2) DEFINE_GUID(n,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) - diff --git a/libphobos/libdruntime/core/sys/windows/sspi.d b/libphobos/libdruntime/core/sys/windows/sspi.d index 07a2596..21e982d 100644 --- a/libphobos/libdruntime/core/sys/windows/sspi.d +++ b/libphobos/libdruntime/core/sys/windows/sspi.d @@ -380,4 +380,3 @@ version (Unicode) { alias QUERY_SECURITY_PACKAGE_INFO_FN_A QUERY_SECURITY_PACKAGE_INFO_FN; alias INIT_SECURITY_INTERFACE_A INIT_SECURITY_INTERFACE; } - diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index fe65c09..8ef65489 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -3765,6 +3765,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, if (!is(const(T) : T)) { import core.internal.traits : Unconst; + import core.internal.array.duplication : _dup; static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~ " to "~Unconst!T.stringof~" in dup."); @@ -3786,6 +3787,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, @property T[] dup(T)(const(T)[] a) if (is(const(T) : T)) { + import core.internal.array.duplication : _dup; return _dup!(const(T), T)(a); } @@ -3793,6 +3795,7 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, /// Provide the .idup array property. @property immutable(T)[] idup(T)(T[] a) { + import core.internal.array.duplication : _dup; static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~ " to immutable in idup."); return _dup!(T, immutable(T))(a); @@ -3813,73 +3816,6 @@ private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, assert(s == "abc"); } -private U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) -{ - if (__ctfe) - return _dupCtfe!(T, U)(a); - - import core.stdc.string : memcpy; - auto arr = _d_newarrayU(typeid(T[]), a.length); - memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); - return *cast(U[]*) &arr; -} - -private U[] _dupCtfe(T, U)(scope T[] a) -{ - static if (is(T : void)) - assert(0, "Cannot dup a void[] array at compile time."); - else - { - U[] res; - foreach (ref e; a) - res ~= e; - return res; - } -} - -private U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)) -{ - // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch - // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`. - if (__ctfe) - return _dupCtfe!(T, U)(a); - - import core.lifetime: copyEmplace; - U[] res = () @trusted { - auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length); - size_t i; - scope (failure) - { - import core.internal.lifetime: emplaceInitializer; - // Initialize all remaining elements to not destruct garbage - foreach (j; i .. a.length) - emplaceInitializer(cast() arr[j]); - } - for (; i < a.length; i++) - { - copyEmplace(a.ptr[i], arr[i]); - } - return cast(U[])(arr[0..a.length]); - } (); - - return res; -} - -// https://issues.dlang.org/show_bug.cgi?id=22107 -@safe unittest -{ - static int i; - @safe struct S - { - this(this) { i++; } - } - - void fun(scope S[] values...) @safe - { - values.dup; - } -} - // HACK: This is a lie. `_d_arraysetcapacity` is neither `nothrow` nor `pure`, but this lie is // necessary for now to prevent breaking code. private extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow; @@ -4067,8 +4003,6 @@ auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system assert(is(typeof(b3) == immutable(int[]))); } -private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow; - private void _doPostblit(T)(T[] arr) { // infer static postblit type, run postblit if any @@ -4085,274 +4019,6 @@ private void _doPostblit(T)(T[] arr) } } -@safe unittest -{ - static struct S1 { int* p; } - static struct S2 { @disable this(); } - static struct S3 { @disable this(this); } - - int dg1() pure nothrow @safe - { - { - char[] m; - string i; - m = m.dup; - i = i.idup; - m = i.dup; - i = m.idup; - } - { - S1[] m; - immutable(S1)[] i; - m = m.dup; - i = i.idup; - static assert(!is(typeof(m.idup))); - static assert(!is(typeof(i.dup))); - } - { - S3[] m; - immutable(S3)[] i; - static assert(!is(typeof(m.dup))); - static assert(!is(typeof(i.idup))); - } - { - shared(S1)[] m; - m = m.dup; - static assert(!is(typeof(m.idup))); - } - { - int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); - } - return 1; - } - - int dg2() pure nothrow @safe - { - { - S2[] m = [S2.init, S2.init]; - immutable(S2)[] i = [S2.init, S2.init]; - m = m.dup; - m = i.dup; - i = m.idup; - i = i.idup; - } - return 2; - } - - enum a = dg1(); - enum b = dg2(); - assert(dg1() == a); - assert(dg2() == b); -} - -@system unittest -{ - static struct Sunpure { this(this) @safe nothrow {} } - static struct Sthrow { this(this) @safe pure {} } - static struct Sunsafe { this(this) @system pure nothrow {} } - static struct Snocopy { @disable this(this); } - - [].dup!Sunpure; - [].dup!Sthrow; - cast(void) [].dup!Sunsafe; - static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); - static assert(!__traits(compiles, () { [].dup!Snocopy; })); - - [].idup!Sunpure; - [].idup!Sthrow; - [].idup!Sunsafe; - static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); - static assert(!__traits(compiles, () { [].idup!Snocopy; })); -} - -@safe unittest -{ - // test that the copy-constructor is called with .dup - static struct ArrElem - { - int a; - this(int a) - { - this.a = a; - } - this(ref const ArrElem) - { - a = 2; - } - this(ref ArrElem) immutable - { - a = 3; - } - } - - auto arr = [ArrElem(1), ArrElem(1)]; - - ArrElem[] b = arr.dup; - assert(b[0].a == 2 && b[1].a == 2); - - immutable ArrElem[] c = arr.idup; - assert(c[0].a == 3 && c[1].a == 3); -} - -@system unittest -{ - static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} } - static struct Sthrow { this(ref const typeof(this)) @safe pure {} } - static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} } - [].dup!Sunpure; - [].dup!Sthrow; - cast(void) [].dup!Sunsafe; - static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); - static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); - static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); - - // for idup to work on structs that have copy constructors, it is necessary - // that the struct defines a copy constructor that creates immutable objects - static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} } - static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} } - static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} } - [].idup!ISunpure; - [].idup!ISthrow; - [].idup!ISunsafe; - static assert(!__traits(compiles, () pure { [].idup!ISunpure; })); - static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; })); - static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; })); -} - -@safe unittest -{ - static int*[] pureFoo() pure { return null; } - { char[] s; immutable x = s.dup; } - { immutable x = (cast(int*[])null).dup; } - { immutable x = pureFoo(); } - { immutable x = pureFoo().dup; } -} - -@safe unittest -{ - auto a = [1, 2, 3]; - auto b = a.dup; - debug(SENTINEL) {} else - assert(b.capacity >= 3); -} - -@system unittest -{ - // Bugzilla 12580 - void[] m = [0]; - shared(void)[] s = [cast(shared)1]; - immutable(void)[] i = [cast(immutable)2]; - - s = s.dup; - static assert(is(typeof(s.dup) == shared(void)[])); - - m = i.dup; - i = m.dup; - i = i.idup; - i = m.idup; - i = s.idup; - i = s.dup; - static assert(!__traits(compiles, m = s.dup)); -} - -@safe unittest -{ - // Bugzilla 13809 - static struct S - { - this(this) {} - ~this() {} - } - - S[] arr; - auto a = arr.dup; -} - -@system unittest -{ - // Bugzilla 16504 - static struct S - { - __gshared int* gp; - int* p; - // postblit and hence .dup could escape - this(this) { gp = p; } - } - - int p; - scope S[1] arr = [S(&p)]; - auto a = arr.dup; // dup does escape -} - -// https://issues.dlang.org/show_bug.cgi?id=21983 -// dup/idup destroys partially constructed arrays on failure -@safe unittest -{ - static struct SImpl(bool postblit) - { - int num; - long l = 0xDEADBEEF; - - static if (postblit) - { - this(this) - { - if (this.num == 3) - throw new Exception(""); - } - } - else - { - this(scope ref const SImpl other) - { - if (other.num == 3) - throw new Exception(""); - - this.num = other.num; - this.l = other.l; - } - } - - ~this() @trusted - { - if (l != 0xDEADBEEF) - { - import core.stdc.stdio; - printf("Unexpected value: %lld\n", l); - fflush(stdout); - assert(false); - } - } - } - - alias Postblit = SImpl!true; - alias Copy = SImpl!false; - - static int test(S)() - { - S[4] arr = [ S(1), S(2), S(3), S(4) ]; - try - { - arr.dup(); - assert(false); - } - catch (Exception) - { - return 1; - } - } - - static assert(test!Postblit()); - assert(test!Postblit()); - - static assert(test!Copy()); - assert(test!Copy()); -} - /** Destroys the given object and optionally resets to initial state. It's used to _destroy an object, calling its destructor or finalizer so it no longer diff --git a/libphobos/libdruntime/rt/dylib_fixes.c b/libphobos/libdruntime/rt/dylib_fixes.c index e484fed..c1391b8 100644 --- a/libphobos/libdruntime/rt/dylib_fixes.c +++ b/libphobos/libdruntime/rt/dylib_fixes.c @@ -25,4 +25,3 @@ __attribute__((destructor)) static void finalizer () { rt_term(); } - diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 744e5ad..1f0cfbf 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -1516ecad932d88a1618163384e6f69009d125391 +5748ca43fd5c3e31ce7a8511f542b67e5d5a3dc6 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/etc/c/curl.d b/libphobos/src/etc/c/curl.d index 0c5b727..e6a1043 100644 --- a/libphobos/src/etc/c/curl.d +++ b/libphobos/src/etc/c/curl.d @@ -1372,9 +1372,9 @@ alias curl_TimeCond = int; /** curl_strequal() and curl_strnequal() are subject for removal in a future libcurl, see lib/README.curlx for details */ extern (C) { -int curl_strequal(in const(char) *s1, in const(char) *s2); +int curl_strequal(scope const(char) *s1, scope const(char) *s2); /// ditto -int curl_strnequal(in const(char) *s1, in const(char) *s2, size_t n); +int curl_strnequal(scope const(char) *s1, scope const(char) *s2, size_t n); } enum CurlForm { nothing, /********** the first one is unused ************/ @@ -1464,7 +1464,7 @@ CURLFORMcode curl_formadd(curl_httppost **httppost, curl_httppost **last_post,. * Should return the buffer length passed to it as the argument "len" on * success. */ -alias curl_formget_callback = size_t function(void *arg, in const(char) *buf, size_t len); +alias curl_formget_callback = size_t function(void *arg, const(char) *buf, size_t len); /** * Name: curl_formget() @@ -1494,7 +1494,7 @@ void curl_formfree(curl_httppost *form); * Returns a malloc()'ed string that MUST be curl_free()ed after usage is * complete. DEPRECATED - see lib/README.curlx */ -char * curl_getenv(in const(char) *variable); +char * curl_getenv(scope const(char) *variable); /** * Name: curl_version() @@ -1514,10 +1514,10 @@ char * curl_version(); * %XX versions). This function returns a new allocated string or NULL if an * error occurred. */ -char * curl_easy_escape(CURL *handle, in const(char) *string, int length); +char * curl_easy_escape(CURL *handle, scope const(char) *string, int length); /** the previous version: */ -char * curl_escape(in const(char) *string, int length); +char * curl_escape(scope const(char) *string, int length); /** @@ -1531,10 +1531,10 @@ char * curl_escape(in const(char) *string, int length); * Conversion Note: On non-ASCII platforms the ASCII %XX codes are * converted into the host encoding. */ -char * curl_easy_unescape(CURL *handle, in const(char) *string, int length, int *outlength); +char * curl_easy_unescape(CURL *handle, scope const(char) *string, int length, int *outlength); /** the previous version */ -char * curl_unescape(in const(char) *string, int length); +char * curl_unescape(scope const(char) *string, int length); /** * Name: curl_free() @@ -1608,7 +1608,7 @@ struct curl_slist * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ -curl_slist * curl_slist_append(curl_slist *, in const(char) *); +curl_slist * curl_slist_append(curl_slist *, const(char) *); /** * Name: curl_slist_free_all() diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d index 2fcc2ba..b810fbb 100644 --- a/libphobos/src/std/algorithm/comparison.d +++ b/libphobos/src/std/algorithm/comparison.d @@ -1027,7 +1027,7 @@ template equal(alias pred = "a == b") } } - private bool equalLoop(Rs...)(Rs rs) + private bool equalLoop(Rs...)(ref Rs rs) { for (; !rs[0].empty; rs[0].popFront) static foreach (r; rs[1 .. $]) diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index af665c4..300a897 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -1263,19 +1263,22 @@ public: // filter /** -Implements the higher order filter function. The predicate is passed to -$(REF unaryFun, std,functional), and can either accept a string, or any callable -that can be executed via `pred(element)`. +`filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for +which `predicate(x)` returns `true`. + +The predicate is passed to $(REF unaryFun, std,functional), and can be either a string, or +any callable that can be executed via `pred(element)`. Params: predicate = Function to apply to each element of range Returns: - `filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for - which `predicate(x)` returns `true`. + An input range that contains the filtered elements. If `range` is at least a forward range, the return value of `filter` + will also be a forward range. See_Also: - $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)) + $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)), + $(REF filterBidirectional, std,algorithm,iteration) */ template filter(alias predicate) if (is(typeof(unaryFun!predicate))) diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 55a1438..daa4b99 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -2512,6 +2512,8 @@ RandomAccessRange find(RandomAccessRange, alias pred, InputRange)( Convenience function. Like find, but only returns whether or not the search was successful. +For more information about `pred` see $(LREF find). + See_Also: $(REF among, std,algorithm,comparison) for checking a value against multiple possibilities. +/ @@ -2622,6 +2624,8 @@ Advances `r` until it finds the first two adjacent elements `a`, `b` that satisfy `pred(a, b)`. Performs $(BIGOH r.length) evaluations of `pred`. +For more information about `pred` see $(LREF find). + Params: pred = The predicate to satisfy. r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to @@ -2698,6 +2702,8 @@ Advances `seq` by calling `seq.popFront` until either `find!(pred)(choices, seq.front)` is `true`, or `seq` becomes empty. Performs $(BIGOH seq.length * choices.length) evaluations of `pred`. +For more information about `pred` see $(LREF find). + Params: pred = The predicate to use for determining a match. seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to @@ -2758,6 +2764,8 @@ if (isInputRange!InputRange && isForwardRange!ForwardRange) * Similarly, the haystack is positioned so as `pred` evaluates to `false` for * `haystack.front`. * + * For more information about `pred` see $(LREF find). + * Params: * haystack = The * $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search @@ -2882,6 +2890,8 @@ $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and the type of `result[0]` and `result[1]` is the same as $(REF takeExactly, std,range). +For more information about `pred` see $(LREF find). + Params: pred = Predicate to use for comparing needle against haystack. haystack = The range to search. @@ -4595,6 +4605,8 @@ $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one of) the given needle(s) or, if no needles are given, if its front element fulfils predicate `pred`. +For more information about `pred` see $(LREF find). + Params: pred = Predicate to use in comparing the elements of the haystack and the diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 8f6c3bf..9164e07 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -3419,17 +3419,20 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum } } + Target result = cast(Target) (sign ? -ldval : ldval); + // if overflow occurred - enforce(ldval != real.infinity, new ConvException("Range error")); + import std.math : isFinite; + enforce(isFinite(result), new ConvException("Range error")); advanceSource(); static if (doCount) { - return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count); + return tuple!("data", "count")(result, count); } else { - return cast (Target) (sign ? -ldval : ldval); + return result; } } @@ -3785,6 +3788,16 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum assertThrown!ConvException(parse!double(s)); } +@safe unittest // https://issues.dlang.org/show_bug.cgi?id=22637 +{ + import std.exception : assertThrown, assertNotThrown; + auto src = "9991232549867999698999493543521458974414359998784641646846435132132543645435456345634541999999999999999" + ~ "9999999943321231321311999231345312413646846354354354399999934153465464654646464654134135354199999999996515734999" + ~ "9999999320135273486741354354731567431324134999999999999999999999999999999999999999999999135411.9"; + assertThrown!ConvException(parse!double(src)); + static if (real.max_10_exp > 310) assertNotThrown!ConvException(parse!real(src)); +} + /** Parsing one character off a range returns the first element and calls `popFront`. diff --git a/libphobos/src/std/experimental/checkedint.d b/libphobos/src/std/experimental/checkedint.d index 9237341..2be5a2e 100644 --- a/libphobos/src/std/experimental/checkedint.d +++ b/libphobos/src/std/experimental/checkedint.d @@ -1,6 +1,6 @@ /** - * This module is now deprecated, use $(MREF std, experimental) + * This module is now deprecated, use $(MREF std, checkedint) * instead. * * Copyright: Copyright The D Language Foundation 2005 - 2015. diff --git a/libphobos/src/std/experimental/logger/core.d b/libphobos/src/std/experimental/logger/core.d index d899db7..f3c6932 100644 --- a/libphobos/src/std/experimental/logger/core.d +++ b/libphobos/src/std/experimental/logger/core.d @@ -4,6 +4,7 @@ Source: $(PHOBOSSRC std/experimental/logger/core.d) */ module std.experimental.logger.core; +import core.atomic : atomicLoad, atomicOp, atomicStore, MemoryOrder; import core.sync.mutex : Mutex; import std.datetime.date : DateTime; import std.datetime.systime : Clock, SysTime; @@ -555,14 +556,14 @@ abstract class Logger Params: lv = `LogLevel` to use for this `Logger` instance. */ - this(LogLevel lv) @safe + this(this This)(LogLevel lv) { this.logLevel_ = lv; this.fatalHandler_ = delegate() { throw new Error("A fatal log message was logged"); }; - this.mutex = new Mutex(); + this.mutex = new typeof(mutex)(); } /** A custom logger must implement this method in order to work in a @@ -661,7 +662,7 @@ abstract class Logger /// Ditto @property final void logLevel(const LogLevel lv) @safe @nogc { - synchronized (mutex) this.logLevel_ = lv; + atomicStore(this.logLevel_, lv); } /** This `delegate` is called in case a log message with @@ -1403,28 +1404,28 @@ abstract class Logger // Thread Global -private __gshared Logger stdSharedDefaultLogger; +private shared Logger stdSharedDefaultLogger; private shared Logger stdSharedLogger; private shared LogLevel stdLoggerGlobalLogLevel = LogLevel.all; /* This method returns the global default Logger. * Marked @trusted because of excessive reliance on __gshared data */ -private @property Logger defaultSharedLoggerImpl() @trusted +private @property shared(Logger) defaultSharedLoggerImpl() @trusted { import core.lifetime : emplace; import std.stdio : stderr; __gshared align(__traits(classInstanceAlignment, FileLogger)) - void[__traits(classInstanceSize, FileLogger)] _buffer; + void[__traits(classInstanceSize, FileLogger)] _buffer = void; import std.concurrency : initOnce; initOnce!stdSharedDefaultLogger({ auto buffer = cast(ubyte[]) _buffer; - return emplace!FileLogger(buffer, stderr, LogLevel.info); + return cast(shared) emplace!(FileLogger)(buffer, stderr, LogLevel.info); }()); - return stdSharedDefaultLogger; + return atomicLoad(stdSharedDefaultLogger); } /** This property sets and gets the default `Logger`. Unless set to another @@ -1452,19 +1453,12 @@ if (sharedLog !is myLogger) sharedLog = new myLogger; ------------- */ -@property Logger sharedLog() @safe +@property shared(Logger) sharedLog() @safe { - static auto trustedLoad(ref shared Logger logger) @trusted - { - import core.atomic : atomicLoad, MemoryOrder; - return cast() atomicLoad!(MemoryOrder.acq)(logger); - //FIXME: Casting shared away here. Not good. See issue 16232. - } - // If we have set up our own logger use that - if (auto logger = trustedLoad(stdSharedLogger)) + if (auto logger = atomicLoad!(MemoryOrder.seq)(stdSharedLogger)) { - return logger; + return atomicLoad(logger); } else { @@ -1474,10 +1468,9 @@ if (sharedLog !is myLogger) } /// Ditto -@property void sharedLog(Logger logger) @trusted +@property void sharedLog(shared(Logger) logger) @safe { - import core.atomic : atomicStore, MemoryOrder; - atomicStore!(MemoryOrder.rel)(stdSharedLogger, cast(shared) logger); + atomicStore!(MemoryOrder.seq)(stdSharedLogger, atomicLoad(logger)); } /** This methods get and set the global `LogLevel`. @@ -1523,9 +1516,12 @@ class StdForwardLogger : Logger this.fatalHandler = delegate() {}; } - override protected void writeLogMsg(ref LogEntry payload) + override protected void writeLogMsg(ref LogEntry payload) @trusted { - sharedLog.forwardMsg(payload); + synchronized (sharedLog.mutex) + { + (cast() sharedLog).forwardMsg(payload); + } } } @@ -1535,6 +1531,40 @@ class StdForwardLogger : Logger auto nl1 = new StdForwardLogger(LogLevel.all); } +@safe unittest +{ + import core.thread : Thread, msecs; + + static class RaceLogger : Logger + { + int value; + this() @safe shared + { + super(LogLevel.init); + } + override void writeLogMsg(ref LogEntry payload) @safe + { + import core.thread : Thread, msecs; + if (payload.msg == "foo") + { + value = 42; + () @trusted { Thread.sleep(100.msecs); }(); + assert(value == 42, "Another thread changed the value"); + } + else + { + () @trusted { Thread.sleep(50.msecs); } (); + value = 13; + } + } + } + + sharedLog = new shared RaceLogger; + scope(exit) { sharedLog = null; } + () @trusted { new Thread(() { log("foo"); }).start(); }(); + log("bar"); +} + /** This `LogLevel` is unqiue to every thread. The thread local `Logger` will use this `LogLevel` to filter log calls @@ -1561,7 +1591,7 @@ private @property Logger stdThreadLocalLogImpl() @trusted } /** This function returns a thread unique `Logger`, that by default -propergates all data logged to it to the `sharedLog`. +propagates all data logged to it to the `sharedLog`. These properties can be used to set and get this `Logger`. Every modification to this `Logger` will only be visible in the thread the @@ -1671,10 +1701,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto oldunspecificLogger = sharedLog; scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); } - sharedLog = tl1; + () @trusted { + sharedLog = cast(shared) tl1; + }(); log(); assert(tl1.line == __LINE__ - 1); @@ -1793,22 +1825,34 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); - auto oldunspecificLogger = sharedLog; + Logger oldunspecificLogger; + () @trusted { + oldunspecificLogger = cast() sharedLog; + }(); assert(oldunspecificLogger.logLevel == LogLevel.info, to!string(oldunspecificLogger.logLevel)); assert(l.logLevel == LogLevel.all); - sharedLog = l; + + () @trusted { + sharedLog = cast(shared) l; + }(); + assert(globalLogLevel == LogLevel.all, to!string(globalLogLevel)); scope(exit) { - sharedLog = oldunspecificLogger; + () @trusted { + sharedLog = atomicLoad(cast(shared) oldunspecificLogger); + }(); } - assert(sharedLog.logLevel == LogLevel.all); + () @trusted { + assert((cast() sharedLog).logLevel == LogLevel.all); + }(); + assert(stdThreadLocalLog.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); @@ -1880,13 +1924,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; FileLogger l = new FileLogger(filename); auto oldunspecificLogger = sharedLog; - sharedLog = l; + + sharedLog = cast(shared) l; scope(exit) { remove(filename); assert(!exists(filename)); - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -1923,7 +1968,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { remove(filename); - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -1931,8 +1976,11 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe string written = "this should be written to file"; auto l = new FileLogger(filename); - sharedLog = l; - sharedLog.logLevel = LogLevel.critical; + sharedLog = cast(shared) l; + + () @trusted { + (cast() sharedLog).logLevel = LogLevel.critical; + }(); log(LogLevel.error, false, notWritten); log(LogLevel.critical, true, written); @@ -1974,11 +2022,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto mem = new TestLogger; mem.fatalHandler = delegate() {}; - sharedLog = mem; + + () @trusted { + sharedLog = cast(shared) mem; + }(); scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2221,11 +2272,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto mem = new TestLogger; mem.fatalHandler = delegate() {}; - sharedLog = mem; + + () @trusted { + sharedLog = cast(shared) mem; + }(); scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2477,10 +2531,13 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe stdThreadLocalLog.logLevel = LogLevel.all; - sharedLog = mem; + () @trusted { + sharedLog = cast(shared) mem; + }(); + scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2707,12 +2764,15 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } auto tl = new TestLogger(LogLevel.info); - sharedLog = tl; + + () @trusted { + sharedLog = cast(shared) tl; + }(); trace("trace"); assert(tl.msg.indexOf("trace") == -1); @@ -2730,7 +2790,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe scope(exit) { - sharedLog = oldunspecificLogger; + sharedLog = atomicLoad(oldunspecificLogger); globalLogLevel = LogLevel.all; } @@ -2738,7 +2798,10 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe auto tl = new TestLogger(LogLevel.info); logger.insertLogger("required", tl); - sharedLog = logger; + + () @trusted { + sharedLog = cast(shared) logger; + }(); trace("trace"); assert(tl.msg.indexOf("trace") == -1); @@ -2774,14 +2837,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe // Workaround for atomics not allowed in @safe code private auto trustedLoad(T)(ref shared T value) @trusted { - import core.atomic : atomicLoad, MemoryOrder; return atomicLoad!(MemoryOrder.acq)(value); } // ditto private void trustedStore(T)(ref shared T dst, ref T src) @trusted { - import core.atomic : atomicStore, MemoryOrder; atomicStore!(MemoryOrder.rel)(dst, src); } @@ -2789,7 +2850,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted // to shared logger @system unittest { - import core.atomic, core.thread, std.concurrency; + import core.thread, std.concurrency; static shared logged_count = 0; @@ -2826,10 +2887,13 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto oldSharedLog = sharedLog; scope(exit) { - sharedLog = oldSharedLog; + sharedLog = atomicLoad(oldSharedLog); } - sharedLog = new IgnoredLog; + () @trusted { + sharedLog = cast(shared) new IgnoredLog; + }(); + Thread[] spawned; foreach (i; 0 .. 4) @@ -2849,7 +2913,9 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted @safe unittest { - auto dl = cast(FileLogger) sharedLog; + auto dl = () @trusted { + return cast(FileLogger) cast() sharedLog; + }(); assert(dl !is null); assert(dl.logLevel == LogLevel.info); assert(globalLogLevel == LogLevel.all); @@ -2946,7 +3012,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto oldShared = sharedLog; scope(exit) { - sharedLog = oldShared; + sharedLog = atomicLoad(oldShared); if (exists(fn)) { remove(fn); @@ -2956,7 +3022,11 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted auto ts = [ "Test log 1", "Test log 2", "Test log 3"]; auto fl = new FileLogger(fn); - sharedLog = fl; + + () @trusted { + sharedLog = cast(shared) fl; + }(); + assert(exists(fn)); foreach (t; ts) diff --git a/libphobos/src/std/experimental/logger/filelogger.d b/libphobos/src/std/experimental/logger/filelogger.d index 5112e52..457012e 100644 --- a/libphobos/src/std/experimental/logger/filelogger.d +++ b/libphobos/src/std/experimental/logger/filelogger.d @@ -259,7 +259,7 @@ class FileLogger : Logger file.close(); } -@safe unittest +@system unittest { auto dl = cast(FileLogger) sharedLog; assert(dl !is null); diff --git a/libphobos/src/std/experimental/logger/multilogger.d b/libphobos/src/std/experimental/logger/multilogger.d index 9acd23a..3593690 100644 --- a/libphobos/src/std/experimental/logger/multilogger.d +++ b/libphobos/src/std/experimental/logger/multilogger.d @@ -187,7 +187,7 @@ class MultiLogger : Logger assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg); } -@safe unittest +@system unittest { auto dl = cast(FileLogger) sharedLog; assert(dl !is null); diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index b8b4a8c..d6cac41 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -1510,7 +1510,7 @@ private ushort bitmapcount, reserved; attrgroup_t commonattr, volattr, dirattr, fileattr, forkattr; } - extern(C) int setattrlist(in char* path, scope ref attrlist attrs, + extern(C) int setattrlist(scope const(char)* path, scope ref attrlist attrs, scope void* attrbuf, size_t attrBufSize, c_ulong options) nothrow @nogc @system; } diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d index f1d6964..2fd6ff7 100644 --- a/libphobos/src/std/format/internal/write.d +++ b/libphobos/src/std/format/internal/write.d @@ -1337,7 +1337,7 @@ if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToSt /* Static-size arrays are formatted as dynamic arrays. */ -void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref const(T) obj, +void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref T obj, scope const ref FormatSpec!Char f) if (is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { @@ -1782,13 +1782,13 @@ void formatChar(Writer)(ref Writer w, in dchar c, in char quote) Associative arrays are formatted by using `':'` and $(D ", ") as separators, and enclosed by `'['` and `']'`. */ -void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) +void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f) if (is(AssocArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { import std.format : enforceFmt, formatValue; import std.range.primitives : put; - AssocArrayTypeOf!(const(T)) val = obj; + AssocArrayTypeOf!T val = obj; const spec = f.spec; enforceFmt(spec == 's' || spec == '(', diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d index 76d68f6..3f6f33a 100644 --- a/libphobos/src/std/format/package.d +++ b/libphobos/src/std/format/package.d @@ -1356,6 +1356,30 @@ if (isSomeChar!Char) assert(result == " 1"); } +// https://issues.dlang.org/show_bug.cgi?id=23245 +@safe unittest +{ + static struct S + { + string toString() { return "S"; } + } + + S[1] s; + assert(format("%s", s) == "[S]"); +} + +// https://issues.dlang.org/show_bug.cgi?id=23246 +@safe unittest +{ + static struct S + { + string toString() { return "S"; } + } + + S[int] s = [0 : S()]; + assert(format("%s", s) == "[0:S]"); +} + /// ditto typeof(fmt) format(alias fmt, Args...)(Args args) if (isSomeString!(typeof(fmt))) diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d index 7443b0d..19982ec 100644 --- a/libphobos/src/std/math/package.d +++ b/libphobos/src/std/math/package.d @@ -383,6 +383,7 @@ template floatTraits(T) enum ushort EXPBIAS = 0x3FE0; enum uint EXPMASK_INT = 0x7FF0_0000; enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only + enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF; enum realFormat = RealFormat.ieeeDouble; version (LittleEndian) { diff --git a/libphobos/src/std/math/rounding.d b/libphobos/src/std/math/rounding.d index 5c8d708..7dbe89b 100644 --- a/libphobos/src/std/math/rounding.d +++ b/libphobos/src/std/math/rounding.d @@ -908,7 +908,9 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc // Other kinds of extractors for real formats. static if (F.realFormat == RealFormat.ieeeSingle) - int vi; + uint vi; + else static if (F.realFormat == RealFormat.ieeeDouble) + ulong vi; } floatBits y = void; y.rv = x; @@ -919,15 +921,14 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc static if (F.realFormat == RealFormat.ieeeSingle) { int exp = ((y.vi >> (T.mant_dig - 1)) & 0xff) - 0x7f; + enum mantissa_mask = F.MANTISSAMASK_INT; + enum sign_shift = 31; } else static if (F.realFormat == RealFormat.ieeeDouble) { - int exp = ((y.vu[F.EXPPOS_SHORT] >> 4) & 0x7ff) - 0x3ff; - - version (LittleEndian) - int pos = 0; - else - int pos = 3; + long exp = ((y.vi >> (T.mant_dig - 1)) & 0x7ff) - 0x3ff; + enum mantissa_mask = F.MANTISSAMASK_LONG; + enum sign_shift = 63; } else static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeExtended53) @@ -959,18 +960,21 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc return 0.0; } - static if (F.realFormat == RealFormat.ieeeSingle) + static if (F.realFormat == RealFormat.ieeeSingle || + F.realFormat == RealFormat.ieeeDouble) { if (exp < (T.mant_dig - 1)) { // Clear all bits representing the fraction part. - const uint fraction_mask = F.MANTISSAMASK_INT >> exp; + // Note: the fraction mask represents the floating point number 0.999999... + // i.e: `2.0 ^^ (exp - T.mant_dig + 1) * (fraction_mask + 1) == 1.0` + const fraction_mask = mantissa_mask >> exp; if ((y.vi & fraction_mask) != 0) { - // If 'x' is negative, then first substract 1.0 from the value. - if (y.vi < 0) - y.vi += 0x00800000 >> exp; + // If 'x' is negative, then first substract (1.0 - T.epsilon) from the value. + if (y.vi >> sign_shift) + y.vi += fraction_mask; y.vi &= ~fraction_mask; } } diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index 106e51c..b2206ce 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -2762,7 +2762,7 @@ Returns: return a `ref` to the $(D range element), otherwise it will return a copy. */ -auto ref choice(Range, RandomGen = Random)(auto ref Range range, ref RandomGen urng) +auto ref choice(Range, RandomGen = Random)(Range range, ref RandomGen urng) if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) { assert(range.length > 0, @@ -2772,7 +2772,22 @@ if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) } /// ditto -auto ref choice(Range)(auto ref Range range) +auto ref choice(Range)(Range range) +{ + return choice(range, rndGen); +} + +/// ditto +auto ref choice(Range, RandomGen = Random)(ref Range range, ref RandomGen urng) +if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen) +{ + assert(range.length > 0, + __PRETTY_FUNCTION__ ~ ": invalid Range supplied. Range cannot be empty"); + return range[uniform(size_t(0), $, urng)]; +} + +/// ditto +auto ref choice(Range)(ref Range range) { return choice(range, rndGen); } @@ -2827,6 +2842,39 @@ auto ref choice(Range)(auto ref Range range) "Choice did not return a valid element from the given Range"); } +@safe unittest // issue 18631 +{ + auto rng = MinstdRand0(42); + const a = [0,1,2]; + const(int[]) b = [0, 1, 2]; + auto x = choice(a); + auto y = choice(b); + auto z = choice(cast(const)[1, 2, 3]); + auto x1 = choice(a, rng); + auto y1 = choice(b, rng); + auto z1 = choice(cast(const)[1, 2, 3], rng); +} + +@safe unittest // Ref range (issue 18631 PR) +{ + struct TestRange + { + int x; + ref int front() return {return x;} + ref int back() return {return x;} + void popFront() {} + void popBack() {} + bool empty = false; + TestRange save() {return this;} + size_t length = 10; + alias opDollar = length; + ref int opIndex(size_t i) return {return x;} + } + + TestRange r = TestRange(10); + int* s = &choice(r); +} + /** Shuffles elements of `r` using `gen` as a shuffler. `r` must be a random-access range with length. If no RNG is specified, `rndGen` @@ -3008,8 +3056,16 @@ if (isRandomAccessRange!Range) } /** -Rolls a dice with relative probabilities stored in $(D -proportions). Returns the index in `proportions` that was chosen. +Get a random index into a list of weights corresponding to each index + +Similar to rolling a die with relative probabilities stored in `proportions`. +Returns the index in `proportions` that was chosen. + +Note: + Usually, dice are 'fair', meaning that each side has equal probability + to come up, in which case `1 + uniform(0, 6)` can simply be used. + In future Phobos versions, this function might get renamed to something like + `weightedChoice` to avoid confusion. Params: rnd = (optional) random number generator to use; if not @@ -3055,6 +3111,9 @@ if (isNumeric!Num) /// @safe unittest { + auto d6 = 1 + dice(1, 1, 1, 1, 1, 1); // fair dice roll + auto d6b = 1 + dice(2, 1, 1, 1, 1, 1); // double the chance to roll '1' + auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions auto y = dice(50, 50); // y is 0 or 1 in equal proportions auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index 8614dc9..a1fe962 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -1132,10 +1132,9 @@ each item is inferred from the size and type of the input array, respectively. Returns: The slice of `buffer` containing the data that was actually read. This will be shorter than `buffer` if EOF was reached before the buffer -could be filled. +could be filled. If the buffer is empty, it will be returned. -Throws: `Exception` if `buffer` is empty. - `ErrnoException` if the file is not opened or the call to `fread` fails. +Throws: `ErrnoException` if the file is not opened or the call to `fread` fails. `rawRead` always reads in binary mode on Windows. */ @@ -1144,7 +1143,7 @@ Throws: `Exception` if `buffer` is empty. import std.exception : enforce, errnoEnforce; if (!buffer.length) - throw new Exception("rawRead must take a non-empty buffer"); + return buffer; enforce(isOpen, "Attempting to read from an unopened file"); version (Windows) { @@ -1211,6 +1210,16 @@ Throws: `Exception` if `buffer` is empty. } } + // https://issues.dlang.org/show_bug.cgi?id=13893 + @system unittest + { + import std.exception : assertNotThrown; + + File f; + ubyte[0] u; + assertNotThrown(f.rawRead(u)); + } + /** Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fwrite.html, fwrite) for the file handle. The number of items to write and the size of each diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 1d375ef..160665c 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -1941,79 +1941,8 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) auto ref matchImpl(SumTypes...)(auto ref SumTypes args) if (allSatisfy!(isSumType, SumTypes) && args.length > 0) { - enum typeCount(SumType) = SumType.Types.length; alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes)); - - /* A TagTuple represents a single possible set of tags that `args` - * could have at runtime. - * - * Because D does not allow a struct to be the controlling expression - * of a switch statement, we cannot dispatch on the TagTuple directly. - * Instead, we must map each TagTuple to a unique integer and generate - * a case label for each of those integers. - * - * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses - * the same technique that's used to map index tuples to memory offsets - * in a multidimensional static array. - * - * For example, when `args` consists of two SumTypes with two member - * types each, the TagTuples corresponding to each case label are: - * - * case 0: TagTuple([0, 0]) - * case 1: TagTuple([1, 0]) - * case 2: TagTuple([0, 1]) - * case 3: TagTuple([1, 1]) - * - * When there is only one argument, the caseId is equal to that - * argument's tag. - */ - static struct TagTuple - { - size_t[SumTypes.length] tags; - alias tags this; - - invariant - { - static foreach (i; 0 .. tags.length) - { - assert(tags[i] < SumTypes[i].Types.length, "Invalid tag"); - } - } - - this(ref const(SumTypes) args) - { - static foreach (i; 0 .. tags.length) - { - tags[i] = args[i].tag; - } - } - - static TagTuple fromCaseId(size_t caseId) - { - TagTuple result; - - // Most-significant to least-significant - static foreach_reverse (i; 0 .. result.length) - { - result[i] = caseId / stride!i; - caseId %= stride!i; - } - - return result; - } - - size_t toCaseId() - { - size_t result; - - static foreach (i; 0 .. tags.length) - { - result += tags[i] * stride!i; - } - - return result; - } - } + alias TagTuple = .TagTuple!(SumTypes); /* * A list of arguments to be passed to a handler needed for the case @@ -2149,6 +2078,81 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) } } +private enum typeCount(SumType) = SumType.Types.length; + +/* A TagTuple represents a single possible set of tags that `args` + * could have at runtime. + * + * Because D does not allow a struct to be the controlling expression + * of a switch statement, we cannot dispatch on the TagTuple directly. + * Instead, we must map each TagTuple to a unique integer and generate + * a case label for each of those integers. + * + * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses + * the same technique that's used to map index tuples to memory offsets + * in a multidimensional static array. + * + * For example, when `args` consists of two SumTypes with two member + * types each, the TagTuples corresponding to each case label are: + * + * case 0: TagTuple([0, 0]) + * case 1: TagTuple([1, 0]) + * case 2: TagTuple([0, 1]) + * case 3: TagTuple([1, 1]) + * + * When there is only one argument, the caseId is equal to that + * argument's tag. + */ +private struct TagTuple(SumTypes...) +{ + size_t[SumTypes.length] tags; + alias tags this; + + alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes)); + + invariant + { + static foreach (i; 0 .. tags.length) + { + assert(tags[i] < SumTypes[i].Types.length, "Invalid tag"); + } + } + + this(ref const(SumTypes) args) + { + static foreach (i; 0 .. tags.length) + { + tags[i] = args[i].tag; + } + } + + static TagTuple fromCaseId(size_t caseId) + { + TagTuple result; + + // Most-significant to least-significant + static foreach_reverse (i; 0 .. result.length) + { + result[i] = caseId / stride!i; + caseId %= stride!i; + } + + return result; + } + + size_t toCaseId() + { + size_t result; + + static foreach (i; 0 .. tags.length) + { + result += tags[i] * stride!i; + } + + return result; + } +} + // Matching @safe unittest { diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index 8a3e22f..4ecfb10 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -4905,8 +4905,14 @@ if (is(Interface == interface) && is(BaseClass == class)) // - try default first // - only on a failure run & return fallback enum fallback = q{ - scope (failure) return fallback.%1$s(args); - return default_.%1$s(args); + try + { + return default_.%1$s(args); + } + catch (Exception) + { + return fallback.%1$s(args); + } }.format(__traits(identifier, func)); } @@ -6589,15 +6595,11 @@ if (!is(T == class) && !(is(T == interface))) private enum enableGCScan = hasIndirections!T; } - // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed extern(C) private pure nothrow @nogc static { pragma(mangle, "free") void pureFree( void *ptr ); static if (enableGCScan) - { - pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null ); - pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p ); - } + import core.memory : GC; } /// `RefCounted` storage implementation. @@ -6637,7 +6639,7 @@ if (!is(T == class) && !(is(T == interface))) { import std.internal.memory : enforceCalloc; _store = cast(Impl*) enforceCalloc(1, Impl.sizeof); - pureGcAddRange(&_store._payload, T.sizeof); + GC.addRange(&_store._payload, T.sizeof); } else { @@ -6650,7 +6652,7 @@ if (!is(T == class) && !(is(T == interface))) { static if (enableGCScan) { - pureGcRemoveRange(&this._store._payload); + GC.removeRange(&this._store._payload); } pureFree(_store); _store = null; diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 98735ac..e12a70c 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -7032,9 +7032,7 @@ template genericDecodeGrapheme(bool getValue) case RI: if (isRegionalIndicator(ch)) mixin(eat); - else - goto L_End_Extend; - break; + goto L_End_Extend; case L: if (isHangL(ch)) mixin(eat); @@ -7166,6 +7164,10 @@ if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar)) s = "\u11A8\u0308\uAC01"; assert(equal(decodeGrapheme(s)[], "\u11A8\u0308")); assert(equal(decodeGrapheme(s)[], "\uAC01")); + + // Two Union Jacks of the Great Britain + s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + assert(equal(decodeGrapheme(s)[], "\U0001F1EC\U0001F1E7")); } /++ diff --git a/libphobos/testsuite/libphobos.gc/nocollect.d b/libphobos/testsuite/libphobos.gc/nocollect.d index 5df1483..64ed222 100644 --- a/libphobos/testsuite/libphobos.gc/nocollect.d +++ b/libphobos/testsuite/libphobos.gc/nocollect.d @@ -12,4 +12,4 @@ void main() stats = GC.profileStats(); assert(stats.numCollections == 0); -}
\ No newline at end of file +} |