From 0cafc3b6272d1dd738e8d7e66e1d8741e08f74d3 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 10 Jul 2023 03:07:41 +0200 Subject: d: Merge upstream dmd, druntime 17ccd12af3, phobos 8d3800bee. D front-end changes: - Import dmd v2.104.0. - Assignment-style syntax is now allowed for `alias this'. - Overloading `extern(C)' functions is now an error. D runtime changes: - Import druntime v2.104.0. Phobos changes: - Import phobos v2.104.0. - Better static assert messages when instantiating `std.algorithm.iteration.permutations' with wrong inputs. - Added `std.system.instructionSetArchitecture' and `std.system.ISA'. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 17ccd12af3. * dmd/VERSION: Bump version to v2.104.0. * Make-lang.in (D_FRONTEND_OBJS): Rename d/apply.o to d/postordervisitor.o. * d-codegen.cc (make_location_t): Update for new front-end interface. (build_filename_from_loc): Likewise. (build_assert_call): Likewise. (build_array_bounds_call): Likewise. (build_bounds_index_condition): Likewise. (build_bounds_slice_condition): Likewise. (build_frame_type): Likewise. (get_frameinfo): Likewise. * d-diagnostic.cc (d_diagnostic_report_diagnostic): Likewise. * decl.cc (build_decl_tree): Likewise. (start_function): Likewise. * expr.cc (ExprVisitor::visit (NewExp *)): Replace code generation of `new pointer' with front-end lowering. * runtime.def (NEWITEMT): Remove. (NEWITEMIT): Remove. * toir.cc (IRVisitor::visit (LabelStatement *)): Update for new front-end interface. * typeinfo.cc (check_typeinfo_type): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 17ccd12af3. * src/MERGE: Merge upstream phobos 8d3800bee. gcc/testsuite/ChangeLog: * gdc.dg/asm4.d: Update test. --- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/__builtins.di | 3 +- libphobos/libdruntime/core/atomic.d | 2 +- libphobos/libdruntime/core/internal/string.d | 8 +- libphobos/libdruntime/core/internal/util/array.d | 16 -- libphobos/libdruntime/core/lifetime.d | 197 ++++++++++++++++++++- libphobos/libdruntime/core/stdc/assert_.d | 31 ++-- libphobos/libdruntime/object.d | 5 +- libphobos/libdruntime/rt/cast_.d | 20 +-- libphobos/libdruntime/rt/lifetime.d | 136 ++------------ libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/iteration.d | 12 +- libphobos/src/std/bigint.d | 10 +- libphobos/src/std/checkedint.d | 8 +- libphobos/src/std/conv.d | 59 ++---- .../src/std/experimental/allocator/mallocator.d | 18 +- libphobos/src/std/getopt.d | 19 +- libphobos/src/std/path.d | 26 ++- libphobos/src/std/range/package.d | 51 ++++-- libphobos/src/std/system.d | 72 ++++++++ libphobos/src/std/typecons.d | 10 +- 21 files changed, 438 insertions(+), 269 deletions(-) (limited to 'libphobos') diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 95ea67d..1cff48a 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -28a3b24c2e45de39cd3df528142fd06b6456e8fd +17ccd12af386543c0b9935bf7e0a8e701b903105 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/__builtins.di b/libphobos/libdruntime/__builtins.di index 1c49035..74147a0 100644 --- a/libphobos/libdruntime/__builtins.di +++ b/libphobos/libdruntime/__builtins.di @@ -67,8 +67,7 @@ version (DigitalMars) ushort __builtin_bswap16()(ushort value) { - import core.bitop; - return core.bitop.byteswap(value); + return cast(ushort) (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00U)); } uint __builtin_bswap32()(uint value) diff --git a/libphobos/libdruntime/core/atomic.d b/libphobos/libdruntime/core/atomic.d index 1fba06c..5a7d00c 100644 --- a/libphobos/libdruntime/core/atomic.d +++ b/libphobos/libdruntime/core/atomic.d @@ -162,7 +162,7 @@ void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, V new } /// Ditto -void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, shared V newval) pure nothrow @nogc @trusted +void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, auto ref shared V newval) pure nothrow @nogc @trusted if (is(T == class)) { static assert (is (V : T), "Can't assign `newval` of type `shared " ~ V.stringof ~ "` to `shared " ~ T.stringof ~ "`."); diff --git a/libphobos/libdruntime/core/internal/string.d b/libphobos/libdruntime/core/internal/string.d index e09bba4..7bb319e 100644 --- a/libphobos/libdruntime/core/internal/string.d +++ b/libphobos/libdruntime/core/internal/string.d @@ -152,7 +152,7 @@ T[] signedToTempString(uint radix = 10, bool upperCase = false, T)(long value, r if (neg) { // about to do a slice without a bounds check - auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } + auto trustedSlice(return scope T[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } r = trustedSlice(r); r[0] = '-'; } @@ -190,6 +190,12 @@ unittest assert(long.max.signedToTempString(buf) == "9223372036854775807"); assert(long.min.signedToTempString(buf) == "-9223372036854775808"); + wchar[65] wbuf = void; + assert(1.signedToTempString(wbuf) == "1"w); + + dchar[65] dbuf = void; + assert(1.signedToTempString(dbuf) == "1"d); + // use stack allocated struct version assert(0.signedToTempString() == "0"); assert(1.signedToTempString == "1"); diff --git a/libphobos/libdruntime/core/internal/util/array.d b/libphobos/libdruntime/core/internal/util/array.d index 6136cfe..066ee7e 100644 --- a/libphobos/libdruntime/core/internal/util/array.d +++ b/libphobos/libdruntime/core/internal/util/array.d @@ -26,14 +26,6 @@ private char[] errorMessage(Args...)(scope const(char*) format, @safe /* pure dmd @@@BUG11461@@@ */ nothrow: -void enforceTypedArraysConformable(T)(const char[] action, - const T[] a1, const T[] a2, const bool allowOverlap = false) -{ - _enforceSameLength(action, a1.length, a2.length); - if (!allowOverlap) - _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length); -} - void enforceRawArraysConformable(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, const bool allowOverlap = false) { @@ -76,14 +68,6 @@ private void _enforceNoOverlap(const char[] action, assert(0, msg); } -void enforceTypedArraysConformableNogc(T)(const char[] action, - const T[] a1, const T[] a2, const bool allowOverlap = false) -{ - _enforceSameLengthNogc(action, a1.length, a2.length); - if (!allowOverlap) - _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length); -} - void enforceRawArraysConformableNogc(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, const bool allowOverlap = false) { diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 5e339c0..ae047cb 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -2777,6 +2777,70 @@ if (is(T == class)) return cast(T) p; } +/** + * TraceGC wrapper around $(REF _d_newclassT, core,lifetime). + */ +T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted +{ + version (D_TypeInfo) + { + import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newclassT")); + + return _d_newclassT!T(); + } + else + assert(0, "Cannot create new class if compiling without support for runtime type information!"); +} + +/** + * Allocate an initialized non-array item. + * + * This is an optimization to avoid things needed for arrays like the __arrayPad(size). + * Used to allocate struct instances on the heap. + * + * --- + * struct Sz {int x = 0;} + * struct Si {int x = 3;} + * + * void main() + * { + * new Sz(); // uses zero-initialization + * new Si(); // uses Si.init + * } + * --- + * + * Returns: + * newly allocated item + */ +T* _d_newitemT(T)() @trusted +{ + import core.internal.lifetime : emplaceInitializer; + import core.internal.traits : hasElaborateDestructor, hasIndirections; + import core.memory : GC; + + auto flags = !hasIndirections!T ? GC.BlkAttr.NO_SCAN : GC.BlkAttr.NONE; + immutable tiSize = hasElaborateDestructor!T ? size_t.sizeof : 0; + immutable itemSize = T.sizeof; + immutable totalSize = itemSize + tiSize; + if (tiSize) + flags |= GC.BlkAttr.STRUCTFINAL | GC.BlkAttr.FINALIZE; + + auto blkInfo = GC.qalloc(totalSize, flags, null); + auto p = blkInfo.base; + + if (tiSize) + { + // The GC might not have cleared the padding area in the block. + *cast(TypeInfo*) (p + (itemSize & ~(size_t.sizeof - 1))) = null; + *cast(TypeInfo*) (p + blkInfo.size - tiSize) = cast() typeid(T); + } + + emplaceInitializer(*(cast(T*) p)); + + return cast(T*) p; +} + // Test allocation @safe unittest { @@ -2805,15 +2869,134 @@ if (is(T == class)) } } -T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted +// Test allocation +@safe unittest +{ + struct S { } + S* s = _d_newitemT!S(); + + assert(s !is null); +} + +// Test initializers +@safe unittest { - version (D_TypeInfo) { - import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure; - mixin(TraceHook!(T.stringof, "_d_newclassT")); + // zero-initialization + struct S { int x, y; } + S* s = _d_newitemT!S(); - return _d_newclassT!T(); + assert(s.x == 0); + assert(s.y == 0); + } + { + // S.init + struct S { int x = 2, y = 3; } + S* s = _d_newitemT!S(); + + assert(s.x == 2); + assert(s.y == 3); + } +} + +// Test GC attributes +version (CoreUnittest) +{ + struct S1 + { + int x = 5; + } + struct S2 + { + int x; + this(int x) { this.x = x; } + } + struct S3 + { + int[4] x; + this(int x) { this.x[] = x; } + } + struct S4 + { + int *x; + } + +} +@system unittest +{ + import core.memory : GC; + + auto s1 = new S1; + assert(s1.x == 5); + assert(GC.getAttr(s1) == GC.BlkAttr.NO_SCAN); + + auto s2 = new S2(3); + assert(s2.x == 3); + assert(GC.getAttr(s2) == GC.BlkAttr.NO_SCAN); + + auto s3 = new S3(1); + assert(s3.x == [1, 1, 1, 1]); + assert(GC.getAttr(s3) == GC.BlkAttr.NO_SCAN); + debug(SENTINEL) {} else + assert(GC.sizeOf(s3) == 16); + + auto s4 = new S4; + assert(s4.x == null); + assert(GC.getAttr(s4) == 0); +} + +// Test struct finalizers exception handling +debug(SENTINEL) {} else +@system unittest +{ + import core.memory : GC; + + bool test(E)() + { + import core.exception; + static struct S1 + { + E exc; + ~this() { throw exc; } + } + + bool caught = false; + S1* s = new S1(new E("test onFinalizeError")); + try + { + GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0 .. 1]); + } + catch (FinalizeError err) + { + caught = true; + } + catch (E) + { + } + GC.free(s); + return caught; + } + + assert(test!Exception); + import core.exception : InvalidMemoryOperationError; + assert(!test!InvalidMemoryOperationError); +} + +version (D_ProfileGC) +{ + /** + * TraceGC wrapper around $(REF _d_newitemT, core,lifetime). + */ + T* _d_newitemTTrace(T)(string file, int line, string funcname) @trusted + { + version (D_TypeInfo) + { + import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newitemT")); + + return _d_newitemT!T(); + } + else + assert(0, "Cannot create new `struct` if compiling without support for runtime type information!"); } - else - assert(0, "Cannot create new class if compiling without support for runtime type information!"); } diff --git a/libphobos/libdruntime/core/stdc/assert_.d b/libphobos/libdruntime/core/stdc/assert_.d index fc9402f..a8909e2 100644 --- a/libphobos/libdruntime/core/stdc/assert_.d +++ b/libphobos/libdruntime/core/stdc/assert_.d @@ -12,7 +12,6 @@ /**************************** * These are the various functions called by the assert() macro. - * They are all noreturn functions, although D doesn't have a specific attribute for that. */ module core.stdc.assert_; @@ -36,7 +35,7 @@ version (CRuntime_DigitalMars) /*** * Assert failure function in the Digital Mars C library. */ - void _assert(const(void)* exp, const(void)* file, uint line); + noreturn _assert(const(void)* exp, const(void)* file, uint line); } else version (CRuntime_Microsoft) { @@ -44,37 +43,37 @@ else version (CRuntime_Microsoft) * Assert failure function in the Microsoft C library. * `_assert` is not in assert.h, but it is in the library. */ - void _wassert(const(wchar)* exp, const(wchar)* file, uint line); + noreturn _wassert(const(wchar)* exp, const(wchar)* file, uint line); /// - void _assert(const(char)* exp, const(char)* file, uint line); + noreturn _assert(const(char)* exp, const(char)* file, uint line); } else version (Darwin) { /*** * Assert failure function in the Darwin C library. */ - void __assert_rtn(const(char)* func, const(char)* file, uint line, const(char)* exp); + noreturn __assert_rtn(const(char)* func, const(char)* file, uint line, const(char)* exp); } else version (FreeBSD) { /*** * Assert failure function in the FreeBSD C library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* exp); } else version (NetBSD) { /*** * Assert failure function in the NetBSD C library. */ - void __assert(const(char)* file, int line, const(char)* exp); + noreturn __assert(const(char)* file, int line, const(char)* exp); } else version (OpenBSD) { /*** * Assert failure function in the OpenBSD C library. */ - void __assert(const(char)* file, int line, const(char)* exp); + noreturn __assert(const(char)* file, int line, const(char)* exp); /// void __assert2(const(char)* file, int line, const(char)* func, const(char)* exp); } @@ -83,37 +82,37 @@ else version (DragonFlyBSD) /*** * Assert failure function in the DragonFlyBSD C library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* exp); } else version (CRuntime_Glibc) { /*** * Assert failure functions in the GLIBC library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line); /// - void __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); /// - void __assert_perror_fail(int errnum, const(char)* file, uint line, const(char)* func); + noreturn __assert_perror_fail(int errnum, const(char)* file, uint line, const(char)* func); } else version (CRuntime_Bionic) { - void __assert(const(char)* __file, int __line, const(char)* __msg); + noreturn __assert(const(char)* __file, int __line, const(char)* __msg); } else version (CRuntime_Musl) { /*** * Assert failure function in the Musl C library. */ - void __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); } else version (CRuntime_UClibc) { - void __assert(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* func); } else version (Solaris) { - void __assert_c99(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_c99(const(char)* exp, const(char)* file, uint line, const(char)* func); } else { diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 610cb7a..337eabf 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -527,7 +527,8 @@ private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) void setSameMutex(shared Object ownee, shared Object owner) { - _d_setSameMutex(ownee, owner); + import core.atomic : atomicLoad; + _d_setSameMutex(atomicLoad(ownee), atomicLoad(owner)); } @system unittest @@ -4532,6 +4533,7 @@ version (D_ProfileGC) { public import core.internal.array.appending : _d_arrayappendTTrace; public import core.internal.array.concatenation : _d_arraycatnTXTrace; + public import core.lifetime : _d_newitemTTrace; } public import core.internal.array.appending : _d_arrayappendcTXImpl; public import core.internal.array.comparison : __cmp; @@ -4560,6 +4562,7 @@ public import core.lifetime : _d_delstructImpl; public import core.lifetime : _d_newThrowable; public import core.lifetime : _d_newclassT; public import core.lifetime : _d_newclassTTrace; +public import core.lifetime : _d_newitemT; public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable); diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index 1604510..925599e 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -117,22 +117,6 @@ int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t o int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe { - if (areClassInfosEqual(oc, c)) - return true; - - do - { - if (oc.base && areClassInfosEqual(oc.base, c)) - return true; - - foreach (iface; oc.interfaces) - { - if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) - return true; - } - - oc = oc.base; - } while (oc); - - return false; + size_t offset = 0; + return _d_isbaseof2(oc, c, offset); } diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index a37541b..40fa3e0 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -676,7 +676,7 @@ Params: ti = `TypeInfo` of array type arr = array to shrink. Its `.length` is element length, not byte length, despite `void` type */ -extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ +extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow { // note, we do not care about shared. We are setting the length no matter // what, so no lock is required. @@ -701,7 +701,17 @@ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ { auto oldsize = __arrayAllocLength(info, tinext); if (oldsize > cursize) - finalize_array(arr.ptr + cursize, oldsize - cursize, sti); + { + try + { + finalize_array(arr.ptr + cursize, oldsize - cursize, sti); + } + catch (Exception e) + { + import core.exception : onFinalizeError; + onFinalizeError(sti, e); + } + } } } // Note: Since we "assume" the append is safe, it means it is not shared. @@ -1148,25 +1158,8 @@ extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak } /** -Allocate an uninitialized non-array item. - -This is an optimization to avoid things needed for arrays like the __arrayPad(size). - -- `_d_newitemU` leaves the item uninitialized -- `_d_newitemT` zero initializes the item -- `_d_newitemiT` uses a non-zero initializer from `TypeInfo` - -Used to allocate struct instances on the heap. ---- -struct Sz {int x = 0;} -struct Si {int x = 3;} - -void main() -{ - new Sz(); // _d_newitemT(typeid(Sz)) - new Si(); // _d_newitemiT(typeid(Si)) -} ---- +Non-template version of $(REF _d_newitemT, core,lifetime) that does not perform +initialization. Needed for $(REF allocEntry, rt,aaA). Params: _ti = `TypeInfo` of item to allocate @@ -1196,26 +1189,6 @@ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak return p; } -/// ditto -extern (C) void* _d_newitemT(const TypeInfo _ti) pure nothrow @weak -{ - import core.stdc.string; - auto p = _d_newitemU(_ti); - memset(p, 0, _ti.tsize); - return p; -} - -/// Same as above, for item with non-zero initializer. -extern (C) void* _d_newitemiT(const TypeInfo _ti) pure nothrow @weak -{ - import core.stdc.string; - auto p = _d_newitemU(_ti); - auto init = _ti.initializer(); - assert(init.length <= _ti.tsize); - memcpy(p, init.ptr, init.length); - return p; -} - debug(PRINTF) { extern(C) void printArrayCache() @@ -2361,52 +2334,6 @@ unittest testPostBlit!(const(S))(); } -// cannot define structs inside unit test block, or they become nested structs. -version (CoreUnittest) -{ - struct S1 - { - int x = 5; - } - struct S2 - { - int x; - this(int x) {this.x = x;} - } - struct S3 - { - int[4] x; - this(int x) - {this.x[] = x;} - } - struct S4 - { - int *x; - } - -} - -unittest -{ - auto s1 = new S1; - assert(s1.x == 5); - assert(GC.getAttr(s1) == BlkAttr.NO_SCAN); - - auto s2 = new S2(3); - assert(s2.x == 3); - assert(GC.getAttr(s2) == BlkAttr.NO_SCAN); - - auto s3 = new S3(1); - assert(s3.x == [1,1,1,1]); - assert(GC.getAttr(s3) == BlkAttr.NO_SCAN); - debug(SENTINEL) {} else - assert(GC.sizeOf(s3) == 16); - - auto s4 = new S4; - assert(s4.x == null); - assert(GC.getAttr(s4) == 0); -} - unittest { // Bugzilla 3454 - Inconsistent flag setting in GC.realloc() @@ -2731,41 +2658,6 @@ unittest assert(!test!InvalidMemoryOperationError); } -// test struct finalizers exception handling -debug(SENTINEL) {} else -unittest -{ - bool test(E)() - { - import core.exception; - static struct S1 - { - E exc; - ~this() { throw exc; } - } - - bool caught = false; - S1* s = new S1(new E("test onFinalizeError")); - try - { - GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); - } - catch (FinalizeError err) - { - caught = true; - } - catch (E) - { - } - GC.free(s); - return caught; - } - - assert( test!Exception); - import core.exception : InvalidMemoryOperationError; - assert(!test!InvalidMemoryOperationError); -} - // test bug 14126 unittest { diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index c6e61f7..d3ebf74 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -8ab95ded5265379e74d507fdc252ff3d2305fc26 +8d3800bee23db56f71ef4066f74bce057fcce256 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/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 9f5a6ac..55ccb51 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -7939,15 +7939,23 @@ See_Also: $(REF nextPermutation, std,algorithm,sorting). */ Permutations!Range permutations(Range)(Range r) -if (isRandomAccessRange!Range && hasLength!Range) { + static assert(isRandomAccessRange!Range, Range.stringof, + " must be a RandomAccessRange"); + static assert(hasLength!Range, Range.stringof + , " must have a length"); + return typeof(return)(r); } /// ditto struct Permutations(Range) -if (isRandomAccessRange!Range && hasLength!Range) { + static assert(isRandomAccessRange!Range, Range.stringof, + " must be a RandomAccessRange"); + static assert(hasLength!Range, Range.stringof + , " must have a length"); + private size_t[] _indices, _state; private Range _r; private bool _empty; diff --git a/libphobos/src/std/bigint.d b/libphobos/src/std/bigint.d index 33d0eae..50f88da 100644 --- a/libphobos/src/std/bigint.d +++ b/libphobos/src/std/bigint.d @@ -254,11 +254,11 @@ public: static if (op=="+") { - data = BigUint.addOrSubInt(data, u, sign != (y<0), sign); + data = BigUint.addOrSubInt!ulong(data, u, wantSub: sign != (y<0), sign); } else static if (op=="-") { - data = BigUint.addOrSubInt(data, u, sign == (y<0), sign); + data = BigUint.addOrSubInt!ulong(data, u, wantSub: sign == (y<0), sign); } else static if (op=="*") { @@ -613,7 +613,7 @@ public: static if (op == "-") { r.sign = sign; - r.data = BigUint.addOrSubInt(data, u, sign == (y<0), r.sign); + r.data = BigUint.addOrSubInt!ulong(data, u, wantSub: sign == (y<0), r.sign); r.negate(); } return r; @@ -670,12 +670,12 @@ public: { static if (op=="++") { - data = BigUint.addOrSubInt(data, 1UL, sign, sign); + data = BigUint.addOrSubInt!ulong(data, 1UL, wantSub: sign, sign); return this; } else static if (op=="--") { - data = BigUint.addOrSubInt(data, 1UL, !sign, sign); + data = BigUint.addOrSubInt!ulong(data, 1UL, wantSub: !sign, sign); return this; } } diff --git a/libphobos/src/std/checkedint.d b/libphobos/src/std/checkedint.d index 79597e8..cec1dc1 100644 --- a/libphobos/src/std/checkedint.d +++ b/libphobos/src/std/checkedint.d @@ -2129,16 +2129,16 @@ static: { // Not value convertible, only viable option is rhs fits within the // bounds of Lhs - static if (ProperCompare.hookOpCmp(Rhs.min, Lhs.min) < 0) + static if (ProperCompare.hookOpCmp!(Rhs, Lhs)(lhs: Rhs.min, rhs: Lhs.min) < 0) { // Example: hookOpCast!short(int(42)), hookOpCast!uint(int(42)) - if (ProperCompare.hookOpCmp(rhs, Lhs.min) < 0) + if (ProperCompare.hookOpCmp!(Rhs, Lhs)(lhs: rhs, rhs: Lhs.min) < 0) return defaultValue!Lhs; } - static if (ProperCompare.hookOpCmp(Rhs.max, Lhs.max) > 0) + static if (ProperCompare.hookOpCmp!(Rhs, Lhs)(lhs: Rhs.max, rhs: Lhs.max) > 0) { // Example: hookOpCast!int(uint(42)) - if (ProperCompare.hookOpCmp(rhs, Lhs.max) > 0) + if (ProperCompare.hookOpCmp!(Rhs, Lhs)(lhs: rhs, rhs: Lhs.max) > 0) return defaultValue!Lhs; } return cast(Lhs) rhs; diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index aef2365..89d4e5e 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -102,21 +102,6 @@ private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE_ return new ConvException(msg, fn, ln); } -private auto convError(S, T)(S source, int radix, string fn = __FILE__, size_t ln = __LINE__) -{ - string msg; - - if (source.empty) - msg = text("Unexpected end of input when converting from type " ~ S.stringof ~ " base ", radix, - " to type " ~ T.stringof); - else - msg = text("Unexpected '", source.front, - "' when converting from type " ~ S.stringof ~ " base ", radix, - " to type " ~ T.stringof); - - return new ConvException(msg, fn, ln); -} - @safe pure/* nothrow*/ // lazy parameter bug private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__) { @@ -1023,7 +1008,15 @@ if (!(is(S : T) && else static if (isIntegral!S && !is(S == enum)) { // other integral-to-string conversions with default radix - return toImpl!(T, S)(value, 10); + + import core.internal.string : signedToTempString, unsignedToTempString; + + alias EEType = Unqual!(ElementEncodingType!T); + EEType[long.sizeof * 3 + 1] buf = void; + EEType[] t = isSigned!S + ? signedToTempString!(10, false, EEType)(value, buf) + : unsignedToTempString!(10, false, EEType)(value, buf); + return t.dup; } else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[])) { @@ -5726,33 +5719,13 @@ if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) && { void initialize(UT value) { - bool neg = false; - if (value < 10) - { - if (value >= 0) - { - lwr = 0; - upr = 1; - buf[0] = cast(char)(cast(uint) value + '0'); - return; - } - value = -value; - neg = true; - } - auto i = cast(uint) buf.length - 1; - while (cast(Unsigned!UT) value >= 10) - { - buf[i] = cast(ubyte)('0' + cast(Unsigned!UT) value % 10); - value = unsigned(value) / 10; - --i; - } - buf[i] = cast(char)(cast(uint) value + '0'); - if (neg) - { - buf[i - 1] = '-'; - --i; - } - lwr = i; + import core.internal.string : signedToTempString, unsignedToTempString; + + char[] t = value < 0 + ? signedToTempString!(10, false, char)(value, buf) + : unsignedToTempString!(10, false, char)(value, buf); + + lwr = cast(uint) (buf.length - t.length); upr = cast(uint) buf.length; } diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d index de9afbb..02d5cf8 100644 --- a/libphobos/src/std/experimental/allocator/mallocator.d +++ b/libphobos/src/std/experimental/allocator/mallocator.d @@ -376,17 +376,17 @@ version (Posix) { // https://issues.dlang.org/show_bug.cgi?id=16398 // test the "pseudo" alignedReallocate for Posix - void[] s = AlignedMallocator.instance.alignedAllocate(16, 32); - (cast(ubyte[]) s)[] = ubyte(1); - AlignedMallocator.instance.alignedReallocate(s, 32, 32); + void[] b = AlignedMallocator.instance.alignedAllocate(16, 32); + (cast(ubyte[]) b)[] = ubyte(1); + AlignedMallocator.instance.alignedReallocate(b, 32, 32); ubyte[16] o; o[] = 1; - assert((cast(ubyte[]) s)[0 .. 16] == o); - AlignedMallocator.instance.alignedReallocate(s, 4, 32); - assert((cast(ubyte[]) s)[0 .. 3] == o[0 .. 3]); - AlignedMallocator.instance.alignedReallocate(s, 128, 32); - assert((cast(ubyte[]) s)[0 .. 3] == o[0 .. 3]); - AlignedMallocator.instance.deallocate(s); + assert((cast(ubyte[]) b)[0 .. 16] == o); + AlignedMallocator.instance.alignedReallocate(b, 4, 32); + assert((cast(ubyte[]) b)[0 .. 3] == o[0 .. 3]); + AlignedMallocator.instance.alignedReallocate(b, 128, 32); + assert((cast(ubyte[]) b)[0 .. 3] == o[0 .. 3]); + AlignedMallocator.instance.deallocate(b); void[] c; AlignedMallocator.instance.alignedReallocate(c, 32, 32); diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d index 42aeb40..cb97eeb 100644 --- a/libphobos/src/std/getopt.d +++ b/libphobos/src/std/getopt.d @@ -685,6 +685,7 @@ private void getoptImpl(T...)(ref string[] args, ref configuration cfg, import std.algorithm.mutation : remove; import std.conv : to; + import std.uni : toLower; static if (opts.length) { static if (is(typeof(opts[0]) : config)) @@ -708,7 +709,10 @@ private void getoptImpl(T...)(ref string[] args, ref configuration cfg, if (optionHelp.optLong.length) { - assert(optionHelp.optLong !in visitedLongOpts, + auto name = optionHelp.optLong; + if (!cfg.caseSensitive) + name = name.toLower(); + assert(name !in visitedLongOpts, "Long option " ~ optionHelp.optLong ~ " is multiply defined"); visitedLongOpts[optionHelp.optLong] = []; @@ -716,7 +720,10 @@ private void getoptImpl(T...)(ref string[] args, ref configuration cfg, if (optionHelp.optShort.length) { - assert(optionHelp.optShort !in visitedShortOpts, + auto name = optionHelp.optShort; + if (!cfg.caseSensitive) + name = name.toLower(); + assert(name !in visitedShortOpts, "Short option " ~ optionHelp.optShort ~ " is multiply defined"); @@ -1779,6 +1786,14 @@ void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt, st assertThrown!AssertError(getopt(args, "abc", &abc, "abc", &abc)); assertThrown!AssertError(getopt(args, "abc|a", &abc, "def|a", &def)); assertNotThrown!AssertError(getopt(args, "abc", &abc, "def", &def)); + + // https://issues.dlang.org/show_bug.cgi?id=23940 + assertThrown!AssertError(getopt(args, + "abc", &abc, "ABC", &def)); + assertThrown!AssertError(getopt(args, config.caseInsensitive, + "abc", &abc, "ABC", &def)); + assertNotThrown!AssertError(getopt(args, config.caseSensitive, + "abc", &abc, "ABC", &def)); } // https://issues.dlang.org/show_bug.cgi?id=17327 repeated option use diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d index 63d60d1..e81f2b6 100644 --- a/libphobos/src/std/path.d +++ b/libphobos/src/std/path.d @@ -3955,7 +3955,7 @@ if (isConvertibleToString!Range) } ----- */ -string expandTilde(string inputPath) @safe nothrow +string expandTilde(return scope const string inputPath) @safe nothrow { version (Posix) { @@ -4138,7 +4138,7 @@ string expandTilde(string inputPath) @safe nothrow } /// -@system unittest +@safe unittest { version (Posix) { @@ -4153,7 +4153,7 @@ string expandTilde(string inputPath) @safe nothrow } } -@system unittest +@safe unittest { version (Posix) { @@ -4205,6 +4205,26 @@ string expandTilde(string inputPath) @safe nothrow } } +@safe unittest +{ + version (Posix) + { + import std.process : environment; + + string testPath(scope const string source_path) { + return source_path.expandTilde; + } + + auto oldHome = environment["HOME"]; + scope(exit) environment["HOME"] = oldHome; + + environment["HOME"] = "dmd/test"; + assert(testPath("~/") == "dmd/test/"); + assert(testPath("~") == "dmd/test"); + } +} + + version (StdUnittest) { private: diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d index 7a724b0..d37c641 100644 --- a/libphobos/src/std/range/package.d +++ b/libphobos/src/std/range/package.d @@ -232,7 +232,7 @@ module std.range; public import std.array; public import std.range.interfaces; public import std.range.primitives; -public import std.typecons : Flag, Yes, No; +public import std.typecons : Flag, Yes, No, Rebindable, rebindable; import std.internal.attributes : betterC; import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap; @@ -978,6 +978,11 @@ if (Ranges.length > 0 && static if (bidirectional) size_t backIndex; else enum backIndex = source.length; + this(typeof(Result.tupleof) fields) + { + this.tupleof = fields; + } + public: this(R input) { @@ -1376,25 +1381,34 @@ if (Ranges.length > 0 && static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) auto opSlice(size_t begin, size_t end) return scope { - auto result = this; + // force staticMap type conversion to Rebindable + static struct ResultRanges + { + staticMap!(Rebindable, Ranges) fields; + } + auto sourceI(size_t i)() => rebindable(this.source[i]); + auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields; + size_t resultFrontIndex = this.frontIndex; + static if (bidirectional) + size_t resultBackIndex = this.backIndex; sw: switch (frontIndex) { static foreach (i; 0 .. R.length) { case i: - immutable len = result.source[i].length; + immutable len = resultRanges[i].length; if (len <= begin) { - result.source[i] = result.source[i] + resultRanges[i] = resultRanges[i] [len .. len]; begin -= len; - result.frontIndex++; + resultFrontIndex++; goto case; } else { - result.source[i] = result.source[i] + resultRanges[i] = resultRanges[i] [begin .. len]; break sw; } @@ -1418,18 +1432,18 @@ if (Ranges.length > 0 && static foreach_reverse (i; 1 .. R.length + 1) { case i: - immutable len = result.source[i-1].length; + immutable len = resultRanges[i-1].length; if (len <= cut) { - result.source[i-1] = result.source[i-1] + resultRanges[i-1] = resultRanges[i-1] [0 .. 0]; cut -= len; - result.backIndex--; + resultBackIndex--; goto case; } else { - result.source[i-1] = result.source[i-1] + resultRanges[i-1] = resultRanges[i-1] [0 .. len - cut]; break sw2; } @@ -1445,7 +1459,10 @@ if (Ranges.length > 0 && assert(0, "Internal library error. Please report it."); } - return result; + static if (bidirectional) + return Result(resultRanges, resultFrontIndex, resultBackIndex); + else + return Result(resultRanges, resultFrontIndex); } } return Result(rs); @@ -1643,6 +1660,18 @@ pure @safe unittest assert(equal(r, "foobar")); } +// https://issues.dlang.org/show_bug.cgi?id=23844 +pure @safe unittest +{ + struct S + { + immutable int value; + } + + auto range = chain(only(S(5)), only(S(6))); + assert(range.array == [S(5), S(6)]); +} + pure @safe nothrow @nogc unittest { // support non-copyable items diff --git a/libphobos/src/std/system.d b/libphobos/src/std/system.d index 55fcfd7..aa672a5 100644 --- a/libphobos/src/std/system.d +++ b/libphobos/src/std/system.d @@ -82,5 +82,77 @@ immutable /// The endianness that the program was compiled for. version (LittleEndian) Endian endian = Endian.littleEndian; else Endian endian = Endian.bigEndian; + /++ + Instruction Set Architecture. + + Note: + This is intended for cases where you need a value representing the + instruction set architecture at runtime. If you're doing something + which should compile differently depending on instruction set + architecture, then please use `version (X86_64)`, `version (ARM)`, + etc. + + See_Also: + $(DDSUBLINK spec/version,PredefinedVersions, Predefined Versions) + +/ + enum ISA + { + x86, /// Intel and AMD 32-bit processors + x86_64, /// Intel and AMD 64-bit processors + arm, /// The ARM architecture (32-bit) (AArch32 et al) + aarch64, /// The Advanced RISC Machine architecture (64-bit) + asmJS, /// The asm.js intermediate programming language + avr, /// 8-bit Atmel AVR Microcontrollers + epiphany, /// The Epiphany architecture + ppc, /// The PowerPC architecture, 32-bit + ppc64, /// The PowerPC architecture, 64-bit + ia64, /// The Itanium architecture (64-bit) + mips32, /// The MIPS architecture, 32-bit + mips64, /// The MIPS architecture, 64-bit + msp430, /// The MSP430 architecture + nvptx, /// The Nvidia Parallel Thread Execution (PTX) architecture, 32-bit + nvptx64, /// The Nvidia Parallel Thread Execution (PTX) architecture, 64-bit + riscv32, /// The RISC-V architecture, 32-bit + riscv64, /// The RISC-V architecture, 64-bit + sparc, /// The SPARC architecture, 32-bit + sparc64, /// The SPARC architecture, 64-bit + s390, /// The System/390 architecture, 32-bit + systemZ, /// The System Z architecture, 64-bit + hppa, /// The HP PA-RISC architecture, 32-bit + hppa64, /// The HP PA-RISC architecture, 64-bit + sh, /// The SuperH architecture, 32-bit + webAssembly, /// The WebAssembly virtual ISA (instruction set architecture), 32-bit + alpha, /// The Alpha architecture + unknown, /// Unknown + } + + /// The instruction set architecture that the program was compiled for. + version (X86) ISA instructionSetArchitecture = ISA.x86; + else version (X86_64) ISA instructionSetArchitecture = ISA.x86_64; + else version (ARM) ISA instructionSetArchitecture = ISA.arm; + else version (AArch64) ISA instructionSetArchitecture = ISA.aarch64; + else version (AsmJS) ISA instructionSetArchitecture = ISA.asmJS; + else version (AVR) ISA instructionSetArchitecture = ISA.avr; + else version (Epiphany) ISA instructionSetArchitecture = ISA.epiphany; + else version (PPC) ISA instructionSetArchitecture = ISA.ppc; + else version (PPC64) ISA instructionSetArchitecture = ISA.ppc64; + else version (IA64) ISA instructionSetArchitecture = ISA.ia64; + else version (MIPS32) ISA instructionSetArchitecture = ISA.mips32; + else version (MIPS64) ISA instructionSetArchitecture = ISA.mips64; + else version (MSP430) ISA instructionSetArchitecture = ISA.msp430; + else version (NVPTX) ISA instructionSetArchitecture = ISA.nvptx; + else version (NVPTX64) ISA instructionSetArchitecture = ISA.nvptx64; + else version (RISCV32) ISA instructionSetArchitecture = ISA.riscv32; + else version (RISCV64) ISA instructionSetArchitecture = ISA.riscv64; + else version (SPARC) ISA instructionSetArchitecture = ISA.sparc; + else version (SPARC64) ISA instructionSetArchitecture = ISA.sparc64; + else version (S390) ISA instructionSetArchitecture = ISA.s390; + else version (SystemZ) ISA instructionSetArchitecture = ISA.systemZ; + else version (HPPA) ISA instructionSetArchitecture = ISA.hppa; + else version (HPPA64) ISA instructionSetArchitecture = ISA.hppa64; + else version (SH) ISA instructionSetArchitecture = ISA.sh; + else version (WebAssembly) ISA instructionSetArchitecture = ISA.webAssembly; + else version (Alpha) ISA instructionSetArchitecture = ISA.alpha; + else ISA instructionSetArchitecture = ISA.unknown; } diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index d267e71..0748d52 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -7406,11 +7406,11 @@ pure @system unittest foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted)) { MyRefCounted!int* p; + auto rc1 = MyRefCounted!int(5); + p = &rc1; + assert(rc1 == 5); + assert(rc1._refCounted._store._count == 1); { - auto rc1 = MyRefCounted!int(5); - p = &rc1; - assert(rc1 == 5); - assert(rc1._refCounted._store._count == 1); auto rc2 = rc1; assert(rc1._refCounted._store._count == 2); // Reference semantics @@ -7421,6 +7421,8 @@ pure @system unittest rc1 = rc2; assert(rc1._refCounted._store._count == 2); } + // Artificially end scope of rc1 by calling ~this() explicitly + rc1.__xdtor(); assert(p._refCounted._store == null); // [Safe]RefCounted as a member -- cgit v1.1