aboutsummaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-03-29 16:57:10 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2022-04-02 23:56:52 +0200
commit235d5a96cb8dad0b4c427602346fcf966a4ec914 (patch)
treeca19c774a19ad923e5d6f09d43ee8d89c275a96e /libphobos
parentbe07535d0f43390b8906826cc119473dea514b54 (diff)
downloadgcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.zip
gcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.tar.gz
gcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.tar.bz2
d: Merge upstream dmd 47871363d, druntime, c52e28b7, phobos 99e9c1b77.
D front-end changes: - Import dmd v2.099.1-beta.1. - The address of NRVO variables is now stored in scoped closures when they have nested references. - Using `__traits(parameters)' in foreach loops now always returns the parameters to the function the foreach appears within. Previously, when used inside a `foreach' using an overloaded `opApply', the trait would yield the parameters to the delegate. - The deprecation period of unannotated `asm' blocks has been ended. - The `inout' attribute no longer implies the `return' attribute. - Added new `D_PreConditions', `D_PostConditions', and `D_Invariants' version identifiers. D runtime changes: - Import druntime v2.099.1-beta.1. Phobos changes: - Import phobos v2.099.1-beta.1. - `Nullable' in `std.typecons' can now act as a range. - std.experimental.logger default level changed to `info' instead of `warning'. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 47871363d. * d-builtins.cc (d_init_versions): Add predefined version identifiers D_PreConditions, D_PostConditions, and D_Invariants. * d-codegen.cc (d_build_call): Update for new front-end interface. (build_frame_type): Generate reference field for NRVO variables with nested references. (build_closure): Generate assignment of return address to closure. * d-tree.h (DECL_INSTANTIATED): Use DECL_LANG_FLAG_2. (bind_expr): Remove. * decl.cc (DeclVisitor::visit (FuncDeclaration *)): Update for new front-end interface. (get_symbol_decl): Likewise. (get_decl_tree): Check DECL_LANG_FRAME_FIELD before DECL_LANG_NRVO. Dereference the field when both are set. * expr.cc (ExprVisitor::visit (DeleteExp *)): Update for new front-end interface. * modules.cc (get_internal_fn): Likewise. * toir.cc (IRVisitor::visit (ReturnStatement *)): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c52e28b7. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/pwd.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 99e9c1b77. * testsuite/libphobos.exceptions/message_with_null.d: New test. gcc/testsuite/ChangeLog: * gdc.dg/nrvo1.d: New test.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/Makefile.am14
-rw-r--r--libphobos/libdruntime/Makefile.in22
-rw-r--r--libphobos/libdruntime/core/atomic.d11
-rw-r--r--libphobos/libdruntime/core/demangle.d2
-rw-r--r--libphobos/libdruntime/core/internal/array/casting.d59
-rw-r--r--libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d11
-rw-r--r--libphobos/libdruntime/core/stdc/stdlib.d4
-rw-r--r--libphobos/libdruntime/core/stdcpp/string.d4
-rw-r--r--libphobos/libdruntime/core/sys/openbsd/pwd.d19
-rw-r--r--libphobos/libdruntime/core/thread/context.d2
-rw-r--r--libphobos/libdruntime/rt/dmain2.d2
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/conv.d24
-rw-r--r--libphobos/src/std/datetime/systime.d29
-rw-r--r--libphobos/src/std/experimental/logger/core.d8
-rw-r--r--libphobos/src/std/experimental/logger/filelogger.d2
-rw-r--r--libphobos/src/std/experimental/logger/multilogger.d2
-rw-r--r--libphobos/src/std/file.d8
-rw-r--r--libphobos/src/std/format/internal/write.d147
-rw-r--r--libphobos/src/std/format/package.d2
-rw-r--r--libphobos/src/std/format/read.d2
-rw-r--r--libphobos/src/std/format/write.d2
-rw-r--r--libphobos/src/std/functional.d12
-rw-r--r--libphobos/src/std/json.d2
-rw-r--r--libphobos/src/std/outbuffer.d4
-rw-r--r--libphobos/src/std/parallelism.d5
-rw-r--r--libphobos/src/std/process.d11
-rw-r--r--libphobos/src/std/socket.d4
-rw-r--r--libphobos/src/std/stdio.d22
-rw-r--r--libphobos/src/std/sumtype.d12
-rw-r--r--libphobos/src/std/typecons.d169
-rw-r--r--libphobos/src/std/uni/package.d44
-rw-r--r--libphobos/src/std/windows/charset.d15
-rw-r--r--libphobos/src/std/windows/syserror.d97
-rw-r--r--libphobos/testsuite/libphobos.exceptions/message_with_null.d8
36 files changed, 580 insertions, 205 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 77b6ad0..b1da32e 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-26b581670ef6e2643d74078f200d1cd21fa40e90
+c52e28b723ccfbe845a95e8e7b528e3cc0b9d790
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index ba64131..6ca4012 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -294,13 +294,13 @@ DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
- core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
- core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
- core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
- core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
- core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
- core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
- core/sys/openbsd/unistd.d
+ core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+ core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+ core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+ core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+ core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+ core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+ core/sys/openbsd/time.d core/sys/openbsd/unistd.d
DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/arpa/inet.d core/sys/posix/config.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 1c64d35..f7f78d7 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -344,9 +344,10 @@ am__objects_14 = core/sys/netbsd/dlfcn.lo core/sys/netbsd/err.lo \
@DRUNTIME_OS_NETBSD_TRUE@am__objects_15 = $(am__objects_14)
am__objects_16 = core/sys/openbsd/dlfcn.lo core/sys/openbsd/err.lo \
core/sys/openbsd/execinfo.lo core/sys/openbsd/pthread_np.lo \
- core/sys/openbsd/stdlib.lo core/sys/openbsd/string.lo \
- core/sys/openbsd/sys/cdefs.lo core/sys/openbsd/sys/elf.lo \
- core/sys/openbsd/sys/elf32.lo core/sys/openbsd/sys/elf64.lo \
+ core/sys/openbsd/pwd.lo core/sys/openbsd/stdlib.lo \
+ core/sys/openbsd/string.lo core/sys/openbsd/sys/cdefs.lo \
+ core/sys/openbsd/sys/elf.lo core/sys/openbsd/sys/elf32.lo \
+ core/sys/openbsd/sys/elf64.lo \
core/sys/openbsd/sys/elf_common.lo \
core/sys/openbsd/sys/link_elf.lo core/sys/openbsd/sys/mman.lo \
core/sys/openbsd/sys/sysctl.lo core/sys/openbsd/time.lo \
@@ -958,13 +959,13 @@ DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
- core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
- core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
- core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
- core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
- core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
- core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
- core/sys/openbsd/unistd.d
+ core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+ core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+ core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+ core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+ core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+ core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+ core/sys/openbsd/time.d core/sys/openbsd/unistd.d
DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/arpa/inet.d core/sys/posix/config.d \
@@ -1619,6 +1620,7 @@ core/sys/openbsd/dlfcn.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/err.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/execinfo.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/pthread_np.lo: core/sys/openbsd/$(am__dirstamp)
+core/sys/openbsd/pwd.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/stdlib.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/string.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/sys/$(am__dirstamp):
diff --git a/libphobos/libdruntime/core/atomic.d b/libphobos/libdruntime/core/atomic.d
index e6a82e5..4af3fdf 100644
--- a/libphobos/libdruntime/core/atomic.d
+++ b/libphobos/libdruntime/core/atomic.d
@@ -292,7 +292,7 @@ template cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
// resolve implicit conversions
- T arg1 = ifThis;
+ const T arg1 = ifThis;
T arg2 = writeThis;
static if (__traits(isFloating, T))
@@ -1276,4 +1276,13 @@ version (CoreUnittest)
shared NoIndirections n;
static assert(is(typeof(atomicLoad(n)) == NoIndirections));
}
+
+ unittest // Issue 21631
+ {
+ shared uint si1 = 45;
+ shared uint si2 = 38;
+ shared uint* psi = &si1;
+
+ assert((&psi).cas(cast(const) psi, &si2));
+ }
}
diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d
index 930e0cd..cb8d433 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -1339,7 +1339,7 @@ pure @safe:
TypeFunction:
CallConvention FuncAttrs Arguments ArgClose Type
*/
- char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return
+ char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
{
debug(trace) printf( "parseTypeFunction+\n" );
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
diff --git a/libphobos/libdruntime/core/internal/array/casting.d b/libphobos/libdruntime/core/internal/array/casting.d
index e862f8e..4366da8 100644
--- a/libphobos/libdruntime/core/internal/array/casting.d
+++ b/libphobos/libdruntime/core/internal/array/casting.d
@@ -17,12 +17,13 @@ builds. It is separate from `__ArrayCast` to minimize code
bloat.
Params:
- fromType = name of the type being cast from
- fromSize = total size in bytes of the array being cast from
- toType = name of the type being cast o
- toSize = total size in bytes of the array being cast to
+ fromType = name of the type being cast from
+ fromSize = total size in bytes of the array being cast from
+ fromLength = length of array being cast from
+ toType = name of the type being cast to
+ toElemSize = element size of array being cast to
*/
-private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
+private void onArrayCastError()(string fromType, size_t fromSize, size_t fromLength, string toType, size_t toElemSize) @trusted
{
import core.internal.string : unsignedToTempString;
import core.memory : pureMalloc;
@@ -45,17 +46,22 @@ private void onArrayCastError()(string fromType, size_t fromSize, string toType,
index += N;
}
- add("An array of size ");
- auto s = unsignedToTempString(fromSize);
+ add("`");
+ add(fromType);
+ add("[]` of length ");
+ auto s = unsignedToTempString(fromLength);
add(s[]);
- add(" does not align on an array of size ");
- s = unsignedToTempString(toSize);
+ add(" cannot be cast to `");
+ add(toType);
+ add("[]` as its length in bytes (");
+ s = unsignedToTempString(fromSize);
add(s[]);
- add(", so `");
- add(fromType);
- add("` cannot be cast to `");
+ add(") is not a multiple of `");
add(toType);
- add("`");
+ add(".sizeof` (");
+ s = unsignedToTempString(toElemSize);
+ add(s[]);
+ add(").");
msg[index] = '\0'; // null-termination
// first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
@@ -64,7 +70,7 @@ private void onArrayCastError()(string fromType, size_t fromSize, string toType,
/**
The compiler lowers expressions of `cast(TTo[])TFrom[]` to
-this implementation.
+this implementation. Note that this does not detect alignment problems.
Params:
from = the array to reinterpret-cast
@@ -79,7 +85,7 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
if ((fromSize % TTo.sizeof) != 0)
{
- onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
+ onArrayCastError(TFrom.stringof, fromSize, from.length, TTo.stringof, TTo.sizeof);
}
struct Array
@@ -113,3 +119,26 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
foreach (v; s)
assert(v == cast(short) 0xabab);
}
+
+@system nothrow unittest
+{
+ string msg;
+ try
+ {
+ auto str = "hello";
+ auto wstr = cast(wstring) str;
+ }
+ catch (Throwable t)
+ msg = t.msg;
+
+ static immutable expected = "`immutable(char)[]` of length 5 cannot be cast to `immutable(wchar)[]` as " ~
+ "its length in bytes (5) is not a multiple of `immutable(wchar).sizeof` (2).";
+
+ if (msg != expected)
+ {
+ import core.stdc.stdio;
+ printf("Expected: |%.*s|\n", cast(int) expected.length, expected.ptr);
+ printf("Actual : |%.*s|\n", cast(int) msg.length, msg.ptr);
+ assert(false);
+ }
+}
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index aa51867..e29e426 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -2935,19 +2935,18 @@ struct Gcx
else version (linux)
{
// clone() fits better as we don't want to do anything but scanning in the child process.
- // no fork-handlera are called, so we can avoid deadlocks due to malloc locks. Probably related:
+ // no fork-handlers are called, so we can avoid deadlocks due to malloc locks. Probably related:
// https://sourceware.org/bugzilla/show_bug.cgi?id=4737
import core.sys.linux.sched : clone;
import core.sys.posix.signal : SIGCHLD;
- enum CLONE_CHILD_CLEARTID = 0x00200000; /* Register exit futex and memory */
- const flags = CLONE_CHILD_CLEARTID | SIGCHLD; // child thread id not needed
+ const flags = SIGCHLD; // exit signal
scope int delegate() scope dg = &child_mark;
extern(C) static int wrap_delegate(void* arg)
{
auto dg = cast(int delegate() scope*)arg;
return (*dg)();
}
- char[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
+ ubyte[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
auto stack = stackbuf.ptr + (isStackGrowingDown ? stackbuf.length : 0);
auto pid = clone(&wrap_delegate, stack, flags, &dg);
}
@@ -2957,7 +2956,6 @@ struct Gcx
auto pid = fork();
fork_needs_lock = true;
}
- assert(pid != -1);
switch (pid)
{
case -1: // fork() failed, retry without forking
@@ -3028,7 +3026,7 @@ struct Gcx
//printf("\tpool address range = %p .. %p\n", minAddr, maxAddr);
version (COLLECT_FORK)
- bool doFork = shouldFork;
+ alias doFork = shouldFork;
else
enum doFork = false;
@@ -3083,6 +3081,7 @@ Lmark:
final switch (forkResult)
{
case ChildStatus.error:
+ // fork() failed, retry without forking
disableFork();
goto Lmark;
case ChildStatus.running:
diff --git a/libphobos/libdruntime/core/stdc/stdlib.d b/libphobos/libdruntime/core/stdc/stdlib.d
index 92f8f70..dbe55a4 100644
--- a/libphobos/libdruntime/core/stdc/stdlib.d
+++ b/libphobos/libdruntime/core/stdc/stdlib.d
@@ -69,8 +69,8 @@ struct div_t
///
struct ldiv_t
{
- int quot,
- rem;
+ c_long quot,
+ rem;
}
///
diff --git a/libphobos/libdruntime/core/stdcpp/string.d b/libphobos/libdruntime/core/stdcpp/string.d
index dfec1ec..defbd83 100644
--- a/libphobos/libdruntime/core/stdcpp/string.d
+++ b/libphobos/libdruntime/core/stdcpp/string.d
@@ -343,7 +343,7 @@ extern(D):
///
inout(T)* data() inout @safe { return _Get_data()._Myptr; }
///
- inout(T)[] as_array() return scope inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
+ inout(T)[] as_array() scope return inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize][i]; }
@@ -1920,7 +1920,7 @@ extern(D):
///
inout(T)* data() inout @safe { return __get_pointer(); }
///
- inout(T)[] as_array() return scope inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
+ inout(T)[] as_array() scope return inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return __get_pointer()[0 .. size()][i]; }
diff --git a/libphobos/libdruntime/core/sys/openbsd/pwd.d b/libphobos/libdruntime/core/sys/openbsd/pwd.d
new file mode 100644
index 0000000..f6a35a8
--- /dev/null
+++ b/libphobos/libdruntime/core/sys/openbsd/pwd.d
@@ -0,0 +1,19 @@
+/**
+ * D header file for OpenBSD pwd.h.
+ *
+ * Copyright: Copyright © 2022, The D Language Foundation
+ * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+ * Authors: Brian Callahan
+ */
+module core.sys.openbsd.pwd;
+
+version (OpenBSD):
+extern (C):
+nothrow:
+@nogc:
+
+public import core.sys.posix.pwd;
+import core.sys.posix.sys.types : uid_t;
+
+passwd* getpwnam_shadow(scope const char*);
+passwd* getpwuid_shadow(uid_t);
diff --git a/libphobos/libdruntime/core/thread/context.d b/libphobos/libdruntime/core/thread/context.d
index 1b3c0ca..e477269 100644
--- a/libphobos/libdruntime/core/thread/context.d
+++ b/libphobos/libdruntime/core/thread/context.d
@@ -6,7 +6,7 @@
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source: $(DRUNTIMESRC core/thread/package.d)
+ * Source: $(DRUNTIMESRC core/thread/context.d)
*/
module core.thread.context;
diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d
index 47b67f1..5ef2695 100644
--- a/libphobos/libdruntime/rt/dmain2.d
+++ b/libphobos/libdruntime/rt/dmain2.d
@@ -669,7 +669,7 @@ extern (C) void _d_print_throwable(Throwable t)
void sink(in char[] buf) scope nothrow
{
- fprintf(stderr, "%.*s", cast(int)buf.length, buf.ptr);
+ fwrite(buf.ptr, char.sizeof, buf.length, stderr);
}
formatThrowable(t, &sink);
}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 6eb555e..7306c10 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-a74fa63e6775d626850d8ebd854d9803c7ffb97d
+99e9c1b7741e0f4e6f2a8c14883c4828d092701d
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/conv.d b/libphobos/src/std/conv.d
index 06b3797..8f6c3bf 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -2850,7 +2850,7 @@ do
static if (isNarrowString!Source)
{
import std.string : representation;
- auto s = source.representation;
+ scope s = source.representation;
}
else
{
@@ -2898,7 +2898,7 @@ do
}
static if (isNarrowString!Source)
- source = cast(Source) s;
+ source = source[$ - s.length .. $];
static if (doCount)
{
@@ -3105,7 +3105,7 @@ if (isSomeString!Source && !is(Source == enum) &&
* A $(LREF ConvException) if `source` is empty, if no number could be
* parsed, or if an overflow occurred.
*/
-auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source source)
+auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
isFloatingPoint!Target && !is(Target == enum))
{
@@ -3115,18 +3115,17 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
static if (isNarrowString!Source)
{
import std.string : representation;
- auto p = source.representation;
+ scope p = source.representation;
}
else
{
alias p = source;
}
- void advanceSource() @trusted
+ void advanceSource()
{
- // p is assigned from source.representation above so the cast is valid
static if (isNarrowString!Source)
- source = cast(Source) p;
+ source = source[$ - p.length .. $];
}
static immutable real[14] negtab =
@@ -5983,3 +5982,14 @@ if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
}
}
}
+
+// Converts an unsigned integer to a compile-time string constant.
+package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
+
+// Check that .stringof does what we expect, since it's not guaranteed by the
+// language spec.
+@safe /*@betterC*/ unittest
+{
+ assert(toCtString!0 == "0");
+ assert(toCtString!123456 == "123456");
+}
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index 949ad7d..e80f122 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -390,6 +390,33 @@ public:
hnsecsToUnixEpoch;
}
}
+ else version (Hurd)
+ {
+ static if (clockType == ClockType.second)
+ return unixTimeToStdTime(core.stdc.time.time(null));
+ else
+ {
+ import core.sys.hurd.time : CLOCK_REALTIME_COARSE;
+ import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
+ static if (clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME_COARSE;
+ else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
+ else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
+ else static assert(0, "Previous static if is wrong.");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
+ return convert!("seconds", "hnsecs")(ts.tv_sec) +
+ ts.tv_nsec / 100 +
+ hnsecsToUnixEpoch;
+ }
+ }
else static assert(0, "Unsupported OS");
}
else static assert(0, "Unsupported OS");
@@ -693,7 +720,7 @@ public:
Returns: The `this` of this `SysTime`.
+/
- ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow
+ ref SysTime opAssign()(auto ref const(SysTime) rhs) scope return @safe pure nothrow
{
_stdTime = rhs._stdTime;
_timezone = rhs._timezone;
diff --git a/libphobos/src/std/experimental/logger/core.d b/libphobos/src/std/experimental/logger/core.d
index afd98ad..6a28de5 100644
--- a/libphobos/src/std/experimental/logger/core.d
+++ b/libphobos/src/std/experimental/logger/core.d
@@ -1633,14 +1633,14 @@ private @property Logger defaultSharedLoggerImpl() @trusted
import std.concurrency : initOnce;
initOnce!stdSharedDefaultLogger({
auto buffer = cast(ubyte[]) _buffer;
- return emplace!FileLogger(buffer, stderr, LogLevel.warning);
+ return emplace!FileLogger(buffer, stderr, LogLevel.info);
}());
return stdSharedDefaultLogger;
}
/** This property sets and gets the default `Logger`. Unless set to another
-logger by the user, the default logger's log level is LogLevel.warning.
+logger by the user, the default logger's log level is LogLevel.info.
Example:
-------------
@@ -2008,7 +2008,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto oldunspecificLogger = sharedLog;
- assert(oldunspecificLogger.logLevel == LogLevel.warning,
+ assert(oldunspecificLogger.logLevel == LogLevel.info,
to!string(oldunspecificLogger.logLevel));
assert(l.logLevel == LogLevel.all);
@@ -3064,7 +3064,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/experimental/logger/filelogger.d b/libphobos/src/std/experimental/logger/filelogger.d
index a0bea77..5112e52 100644
--- a/libphobos/src/std/experimental/logger/filelogger.d
+++ b/libphobos/src/std/experimental/logger/filelogger.d
@@ -263,7 +263,7 @@ class FileLogger : Logger
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/experimental/logger/multilogger.d b/libphobos/src/std/experimental/logger/multilogger.d
index 90bfb58..9acd23a 100644
--- a/libphobos/src/std/experimental/logger/multilogger.d
+++ b/libphobos/src/std/experimental/logger/multilogger.d
@@ -191,7 +191,7 @@ class MultiLogger : Logger
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index b09b82a..6bc7d4d 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -214,7 +214,7 @@ class FileException : Exception
string file = __FILE__,
size_t line = __LINE__) @safe
{
- this(name, sysErrorString(errno), file, line, errno);
+ this(name, generateSysErrorMsg(errno), file, line, errno);
}
else version (Posix) this(scope const(char)[] name,
uint errno = .errno,
@@ -3471,7 +3471,7 @@ else version (Posix) string getcwd() @trusted
while (true)
{
auto len = GetModuleFileNameW(null, buffer.ptr, cast(DWORD) buffer.length);
- enforce(len, sysErrorString(GetLastError()));
+ wenforce(len);
if (len != buffer.length)
return to!(string)(buffer[0 .. len]);
buffer.length *= 2;
@@ -3574,6 +3574,10 @@ else version (Posix) string getcwd() @trusted
// Only Solaris 10 and later
return readLink(format("/proc/%d/path/a.out", getpid()));
}
+ else version (Hurd)
+ {
+ return readLink("/proc/self/exe");
+ }
else
static assert(0, "thisExePath is not supported on this platform");
}
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 68b9e4d..f1d6964 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -2000,8 +2000,7 @@ template hasToString(T, Char)
enum hasToString = HasToStringResult.none;
}
else static if (is(typeof(
- {
- T val = void;
+ (T val) {
const FormatSpec!Char f;
static struct S {void put(scope Char s){}}
S s;
@@ -2015,8 +2014,7 @@ template hasToString(T, Char)
enum hasToString = HasToStringResult.customPutWriterFormatSpec;
}
else static if (is(typeof(
- {
- T val = void;
+ (T val) {
static struct S {void put(scope Char s){}}
S s;
val.toString(s);
@@ -2026,36 +2024,36 @@ template hasToString(T, Char)
{
enum hasToString = HasToStringResult.customPutWriter;
}
- else static if (is(typeof({ T val = void; FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
+ else static if (is(typeof((T val) { FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
{
enum hasToString = HasToStringResult.constCharSinkFormatSpec;
}
- else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}, "%s"); })))
+ else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}, "%s"); })))
{
enum hasToString = HasToStringResult.constCharSinkFormatString;
}
- else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}); })))
+ else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}); })))
{
enum hasToString = HasToStringResult.constCharSink;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; FormatSpec!Char f; val.toString((in char[] s){}, f); })))
+ is(typeof((T val) { FormatSpec!Char f; val.toString((in char[] s){}, f); })))
{
enum hasToString = HasToStringResult.inCharSinkFormatSpec;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; val.toString((in char[] s){}, "%s"); })))
+ is(typeof((T val) { val.toString((in char[] s){}, "%s"); })))
{
enum hasToString = HasToStringResult.inCharSinkFormatString;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; val.toString((in char[] s){}); })))
+ is(typeof((T val) { val.toString((in char[] s){}); })))
{
enum hasToString = HasToStringResult.inCharSink;
}
- else static if (is(typeof({ T val = void; return val.toString(); }()) S) && isSomeString!S)
+ else static if (is(ReturnType!((T val) { return val.toString(); }) S) && isSomeString!S)
{
enum hasToString = HasToStringResult.hasSomeToString;
}
@@ -2171,6 +2169,133 @@ template hasToString(T, Char)
}
}
+// const toString methods
+@safe unittest
+{
+ import std.range.primitives : isOutputRange;
+
+ static struct A
+ {
+ void toString(Writer)(ref Writer w) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct B
+ {
+ void toString(scope void delegate(scope const(char)[]) sink, scope FormatSpec!char fmt) const {}
+ }
+ static struct C
+ {
+ void toString(scope void delegate(scope const(char)[]) sink, string fmt) const {}
+ }
+ static struct D
+ {
+ void toString(scope void delegate(scope const(char)[]) sink) const {}
+ }
+ static struct E
+ {
+ string toString() const {return "";}
+ }
+ static struct F
+ {
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct G
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+ }
+ static struct H
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct I
+ {
+ void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct J
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w, scope ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct K
+ {
+ void toString(Writer)(Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct L
+ {
+ void toString(Writer)(ref Writer w, scope const FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct M
+ {
+ void toString(scope void delegate(in char[]) sink, in FormatSpec!char fmt) const {}
+ }
+ static struct N
+ {
+ void toString(scope void delegate(in char[]) sink, string fmt) const {}
+ }
+ static struct O
+ {
+ void toString(scope void delegate(in char[]) sink) const {}
+ }
+
+ with(HasToStringResult)
+ {
+ static assert(hasToString!(A, char) == customPutWriter);
+ static assert(hasToString!(B, char) == constCharSinkFormatSpec);
+ static assert(hasToString!(C, char) == constCharSinkFormatString);
+ static assert(hasToString!(D, char) == constCharSink);
+ static assert(hasToString!(E, char) == hasSomeToString);
+ static assert(hasToString!(F, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(G, char) == customPutWriter);
+ static assert(hasToString!(H, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(I, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(J, char) == hasSomeToString);
+ static assert(hasToString!(K, char) == constCharSinkFormatSpec);
+ static assert(hasToString!(L, char) == none);
+ static if (hasPreviewIn)
+ {
+ static assert(hasToString!(M, char) == inCharSinkFormatSpec);
+ static assert(hasToString!(N, char) == inCharSinkFormatString);
+ static assert(hasToString!(O, char) == inCharSink);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=22873
+ static assert(hasToString!(inout(A), char) == customPutWriter);
+ static assert(hasToString!(inout(B), char) == constCharSinkFormatSpec);
+ static assert(hasToString!(inout(C), char) == constCharSinkFormatString);
+ static assert(hasToString!(inout(D), char) == constCharSink);
+ static assert(hasToString!(inout(E), char) == hasSomeToString);
+ static assert(hasToString!(inout(F), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(G), char) == customPutWriter);
+ static assert(hasToString!(inout(H), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(I), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(J), char) == hasSomeToString);
+ static assert(hasToString!(inout(K), char) == constCharSinkFormatSpec);
+ static assert(hasToString!(inout(L), char) == none);
+ static if (hasPreviewIn)
+ {
+ static assert(hasToString!(inout(M), char) == inCharSinkFormatSpec);
+ static assert(hasToString!(inout(N), char) == inCharSinkFormatString);
+ static assert(hasToString!(inout(O), char) == inCharSink);
+ }
+ }
+}
+
// object formatting with toString
private void formatObject(Writer, T, Char)(ref Writer w, ref T val, scope const ref FormatSpec!Char f)
if (hasToString!(T, Char))
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index 6c9e9ae..76d68f6 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -1589,7 +1589,7 @@ char[] sformat(alias fmt, Args...)(char[] buf, Args args)
if (isSomeString!(typeof(fmt)))
{
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .sformat(buf, fmt, args);
}
diff --git a/libphobos/src/std/format/read.d b/libphobos/src/std/format/read.d
index b3d8d1f..144fa8c 100644
--- a/libphobos/src/std/format/read.d
+++ b/libphobos/src/std/format/read.d
@@ -305,7 +305,7 @@ if (isSomeString!(typeof(fmt)))
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .formattedRead(r, fmt, args);
}
diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d
index e67d95c..cbab512 100644
--- a/libphobos/src/std/format/write.d
+++ b/libphobos/src/std/format/write.d
@@ -677,7 +677,7 @@ if (isSomeString!(typeof(fmt)))
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .formattedWrite(w, fmt, args);
}
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index 90b0f91..70aaee3 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -65,6 +65,7 @@ module std.functional;
import std.meta : AliasSeq, Reverse;
import std.traits : isCallable, Parameters;
+import std.conv : toCtString;
import std.internal.attributes : betterC;
@@ -1848,17 +1849,6 @@ if (isCallable!(F))
}
}
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
- assert(toCtString!0 == "0");
- assert(toCtString!123456 == "123456");
-}
-
/**
* Passes the fields of a struct as arguments to a function.
*
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index 89def0f..c6e746a 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -321,7 +321,7 @@ struct JSONValue
(*a)[0] = "world"; // segmentation fault
---
*/
- @property ref inout(JSONValue[]) array() return scope inout pure @system
+ @property ref inout(JSONValue[]) array() scope return inout pure @system
{
enforce!JSONException(type == JSONType.array,
"JSONValue is not an array");
diff --git a/libphobos/src/std/outbuffer.d b/libphobos/src/std/outbuffer.d
index 9590238..c434481 100644
--- a/libphobos/src/std/outbuffer.d
+++ b/libphobos/src/std/outbuffer.d
@@ -331,7 +331,7 @@ class OutBuffer
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writef(fmt, args);
}
@@ -377,7 +377,7 @@ class OutBuffer
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writefln(fmt, args);
}
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index 971cfa0..2c97638 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -1039,6 +1039,11 @@ uint totalCPUsImpl() @nogc nothrow @trusted
import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
}
+ else version (Hurd)
+ {
+ import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+ return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+ }
else
{
static assert(0, "Don't know how to get N CPUs on this OS.");
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 2c68f36..28bfb04 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -299,10 +299,9 @@ static:
}
else version (Windows)
{
- import std.exception : enforce;
- enforce(
+ import std.windows.syserror : wenforce;
+ wenforce(
SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
- sysErrorString(GetLastError())
);
return value;
}
@@ -1330,7 +1329,7 @@ private Pid spawnProcessWin(scope const(char)[] commandLine,
{
throw new StdioException(
"Failed to make "~which~" stream inheritable by child process ("
- ~sysErrorString(GetLastError()) ~ ')',
+ ~generateSysErrorMsg() ~ ')',
0);
}
}
@@ -2775,7 +2774,7 @@ Pipe pipe() @trusted //TODO: @safe
if (!CreatePipe(&readHandle, &writeHandle, null, 0))
{
throw new StdioException(
- "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
+ "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
0);
}
@@ -3475,7 +3474,7 @@ class ProcessException : Exception
string file = __FILE__,
size_t line = __LINE__)
{
- auto lastMsg = sysErrorString(GetLastError());
+ auto lastMsg = generateSysErrorMsg();
auto msg = customMsg.empty ? lastMsg
: customMsg ~ " (" ~ lastMsg ~ ')';
return new ProcessException(msg, file, line);
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index cd23232..915159f 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -169,7 +169,7 @@ string formatSocketError(int err) @trusted
else
version (Windows)
{
- return sysErrorString(err);
+ return generateSysErrorMsg(err);
}
else
return "Socket error " ~ to!string(err);
@@ -842,7 +842,7 @@ private string formatGaiError(int err) @trusted
{
version (Windows)
{
- return sysErrorString(err);
+ return generateSysErrorMsg(err);
}
else
{
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index bc2d3fe..1bde73d 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -1458,6 +1458,7 @@ Throws: `Exception` if the file is not opened.
{
import core.sys.windows.winbase : OVERLAPPED;
import core.sys.windows.winnt : BOOL, ULARGE_INTEGER;
+ import std.windows.syserror : wenforce;
private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length,
Flags flags)
@@ -1474,15 +1475,6 @@ Throws: `Exception` if the file is not opened.
return F(windowsHandle, flags, 0, liLength.LowPart,
liLength.HighPart, &overlapped);
}
-
- private static T wenforce(T)(T cond, lazy string str)
- {
- import core.sys.windows.winbase : GetLastError;
- import std.windows.syserror : sysErrorString;
-
- if (cond) return cond;
- throw new Exception(str ~ ": " ~ sysErrorString(GetLastError()));
- }
}
version (Posix)
{
@@ -1783,7 +1775,7 @@ Throws: `Exception` if the file is not opened.
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writef(fmt, args);
}
@@ -1802,7 +1794,7 @@ Throws: `Exception` if the file is not opened.
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writefln(fmt, args);
}
@@ -2151,7 +2143,7 @@ $(CONSOLE
import std.format : checkFormatException;
alias e = checkFormatException!(format, Data);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.readf(format, data);
}
@@ -4388,7 +4380,7 @@ if (isSomeString!(typeof(fmt)))
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .writef(fmt, args);
}
@@ -4429,7 +4421,7 @@ if (isSomeString!(typeof(fmt)))
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .writefln(fmt, args);
}
@@ -4510,7 +4502,7 @@ if (isSomeString!(typeof(format)))
import std.format : checkFormatException;
alias e = checkFormatException!(format, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .readf(format, args);
}
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index f4f4216..dac531f 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -237,21 +237,11 @@ import std.traits : ConstOf, ImmutableOf, InoutOf, TemplateArgsOf;
import std.traits : CommonType, DeducedParameterType;
import std.typecons : ReplaceTypeUnless;
import std.typecons : Flag;
+import std.conv : toCtString;
/// Placeholder used to refer to the enclosing [SumType].
struct This {}
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
- assert(toCtString!0 == "0");
- assert(toCtString!123456 == "123456");
-}
-
// True if a variable of type T can appear on the lhs of an assignment
private enum isAssignableTo(T) =
isAssignable!T || (!isCopyable!T && isRvalueAssignable!T);
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index ea8f8bd..1ee7faa 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3109,6 +3109,64 @@ struct Nullable(T)
{
return isNull ? fallback : _value.payload;
}
+
+ /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
+ alias empty = isNull;
+
+ /// ditto
+ alias popFront = nullify;
+
+ /// ditto
+ alias popBack = nullify;
+
+ /// ditto
+ @property ref inout(T) front() inout @safe pure nothrow
+ {
+ return get();
+ }
+
+ /// ditto
+ alias back = front;
+
+ /// ditto
+ @property inout(typeof(this)) save() inout
+ {
+ return this;
+ }
+
+ /// ditto
+ inout(typeof(this)) opIndex() inout
+ {
+ return this;
+ }
+
+ /// ditto
+ inout(typeof(this)) opIndex(size_t[2] dim) inout
+ in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
+ {
+ return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
+ }
+ /// ditto
+ size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
+ {
+ return [from, to];
+ }
+
+ /// ditto
+ @property size_t length() const @safe pure nothrow
+ {
+ return !empty;
+ }
+
+ /// ditto
+ alias opDollar(size_t dim : 0) = length;
+
+ /// ditto
+ ref inout(T) opIndex(size_t index) inout @safe pure nothrow
+ in (index < length)
+ {
+ return get();
+ }
}
/// ditto
@@ -3162,6 +3220,23 @@ auto nullable(T)(T t)
assert(a.isNull);
assertThrown!Throwable(a.get);
}
+///
+@safe unittest
+{
+ import std.algorithm.iteration : each, joiner;
+ Nullable!int a = 42;
+ Nullable!int b;
+ // Add each value to an array
+ int[] arr;
+ a.each!((n) => arr ~= n);
+ assert(arr == [42]);
+ b.each!((n) => arr ~= n);
+ assert(arr == [42]);
+ // Take first value from an array of Nullables
+ Nullable!int[] c = new Nullable!int[](10);
+ c[7] = Nullable!int(42);
+ assert(c.joiner.front == 42);
+}
@safe unittest
{
auto k = Nullable!int(74);
@@ -3638,6 +3713,42 @@ auto nullable(T)(T t)
a = b = c = nullable(5);
}
+// https://issues.dlang.org/show_bug.cgi?id=18374
+@safe pure nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.range : only, takeNone;
+ import std.range.primitives : hasAssignableElements, hasLength,
+ hasLvalueElements, hasSlicing, hasSwappableElements,
+ isRandomAccessRange;
+ Nullable!int a = 42;
+ assert(!a.empty);
+ assert(a.front == 42);
+ assert(a.back == 42);
+ assert(a[0] == 42);
+ assert(a.equal(only(42)));
+ assert(a[0 .. $].equal(only(42)));
+ a[0] = 43;
+ assert(a.equal(only(43)));
+ --a[0];
+ assert(a.equal(only(42)));
+ Nullable!int b;
+ assert(b.empty);
+ assert(b.equal(takeNone(b)));
+ Nullable!int c = a.save();
+ assert(!c.empty);
+ c.popFront();
+ assert(!a.empty);
+ assert(c.empty);
+
+ assert(isRandomAccessRange!(Nullable!int));
+ assert(hasLength!(Nullable!int));
+ assert(hasSlicing!(Nullable!int));
+ assert(hasAssignableElements!(Nullable!int));
+ assert(hasSwappableElements!(Nullable!int));
+ assert(hasLvalueElements!(Nullable!int));
+}
+
/**
Just like `Nullable!T`, except that the null state is defined as a
particular value. For example, $(D Nullable!(uint, uint.max)) is an
@@ -8793,19 +8904,6 @@ private:
enum isBaseEnumType(T) = is(E == T);
alias Base = OriginalType!E;
Base mValue;
- static struct Negation
- {
- @safe @nogc pure nothrow:
- private:
- Base mValue;
-
- // Prevent non-copy construction outside the module.
- @disable this();
- this(Base value)
- {
- mValue = value;
- }
- }
public:
this(E flag)
@@ -8830,10 +8928,10 @@ public:
return mValue;
}
- Negation opUnary(string op)() const
+ auto opUnary(string op)() const
if (op == "~")
{
- return Negation(~mValue);
+ return BitFlags(cast(E) cast(Base) ~mValue);
}
auto ref opAssign(T...)(T flags)
@@ -8877,12 +8975,6 @@ public:
return this;
}
- auto ref opOpAssign(string op: "&")(Negation negatedFlags)
- {
- mValue &= negatedFlags.mValue;
- return this;
- }
-
auto opBinary(string op)(BitFlags flags) const
if (op == "|" || op == "&")
{
@@ -8899,13 +8991,6 @@ public:
return result;
}
- auto opBinary(string op: "&")(Negation negatedFlags) const
- {
- BitFlags result = this;
- result.opOpAssign!op(negatedFlags);
- return result;
- }
-
auto opBinaryRight(string op)(E flag) const
if (op == "|" || op == "&")
{
@@ -9104,6 +9189,34 @@ public:
assert(flags.A && !flags.B && !flags.C);
}
+// Negation of BitFlags should work with any base type.
+// Double-negation of BitFlags should work.
+@safe @nogc pure nothrow unittest
+{
+ static foreach (alias Base; AliasSeq!(
+ byte,
+ ubyte,
+ short,
+ ushort,
+ int,
+ uint,
+ long,
+ ulong,
+ ))
+ {{
+ enum Enum : Base
+ {
+ A = 1 << 0,
+ B = 1 << 1,
+ C = 1 << 2,
+ }
+
+ auto flags = BitFlags!Enum(Enum.A);
+
+ assert(flags == ~~flags);
+ }}
+}
+
private enum false_(T) = false;
// ReplaceType
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index eeeda72..98735ac 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -9834,25 +9834,29 @@ dchar toLower(dchar c)
Returns:
An array with the same element type as `s`.
+/
-ElementEncodingType!S[] toLower(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toLower(S)(return scope S s) @trusted
+if (isSomeString!S)
{
static import std.ascii;
+ return toCase!(LowerTriple, std.ascii.toLower)(s);
+}
- static if (isSomeString!S)
- return () @trusted { return toCase!(LowerTriple, std.ascii.toLower)(s); } ();
- else
- return toCase!(LowerTriple, std.ascii.toLower)(s);
+/// ditto
+ElementEncodingType!S[] toLower(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+ static import std.ascii;
+ return toCase!(LowerTriple, std.ascii.toLower)(s);
}
// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
- string toLower(string s)
+ string toLower(return scope string s)
{ return toLower!string(s); }
- wstring toLower(wstring s)
+ wstring toLower(return scope wstring s)
{ return toLower!wstring(s); }
- dstring toLower(dstring s)
+ dstring toLower(return scope dstring s)
{ return toLower!dstring(s); }
@safe unittest
@@ -10038,25 +10042,29 @@ dchar toUpper(dchar c)
Returns:
An new array with the same element type as `s`.
+/
-ElementEncodingType!S[] toUpper(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toUpper(S)(return scope S s) @trusted
+if (isSomeString!S)
{
static import std.ascii;
+ return toCase!(UpperTriple, std.ascii.toUpper)(s);
+}
- static if (isSomeString!S)
- return () @trusted { return toCase!(UpperTriple, std.ascii.toUpper)(s); } ();
- else
- return toCase!(UpperTriple, std.ascii.toUpper)(s);
+/// ditto
+ElementEncodingType!S[] toUpper(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+ static import std.ascii;
+ return toCase!(UpperTriple, std.ascii.toUpper)(s);
}
// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
- string toUpper(string s)
+ string toUpper(return scope string s)
{ return toUpper!string(s); }
- wstring toUpper(wstring s)
+ wstring toUpper(return scope wstring s)
{ return toUpper!wstring(s); }
- dstring toUpper(dstring s)
+ dstring toUpper(return scope dstring s)
{ return toUpper!dstring(s); }
@safe unittest
diff --git a/libphobos/src/std/windows/charset.d b/libphobos/src/std/windows/charset.d
index 69626b5..ce33616 100644
--- a/libphobos/src/std/windows/charset.d
+++ b/libphobos/src/std/windows/charset.d
@@ -76,12 +76,7 @@ const(char)* toMBSz(scope const(char)[] s, uint codePage = 0)
to!int(result.length), null, null);
}
- if (!readLen || readLen != result.length)
- {
- throw new Exception("Couldn't convert string: " ~
- sysErrorString(GetLastError()));
- }
-
+ wenforce(readLen && readLen == result.length, "Couldn't convert string");
return result.ptr;
}
}
@@ -107,16 +102,10 @@ string fromMBSz(return scope immutable(char)* s, int codePage = 0)
to!int(result.length));
}
- if (!readLen || readLen != result.length)
- {
- throw new Exception("Couldn't convert string: " ~
- sysErrorString(GetLastError()));
- }
+ wenforce(readLen && readLen == result.length, "Couldn't convert string");
return result[0 .. result.length-1].to!string; // omit trailing null
}
}
return s[0 .. c-s]; // string is ASCII, no conversion necessary
}
-
-
diff --git a/libphobos/src/std/windows/syserror.d b/libphobos/src/std/windows/syserror.d
index 94f8ee5..3d8c5e7 100644
--- a/libphobos/src/std/windows/syserror.d
+++ b/libphobos/src/std/windows/syserror.d
@@ -43,7 +43,7 @@ version (StdDdoc)
{
private alias DWORD = int;
final @property DWORD code(); /// `GetLastError`'s return value.
- this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted;
+ this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted;
}
/++
@@ -66,9 +66,9 @@ else:
version (Windows):
import core.sys.windows.winbase, core.sys.windows.winnt;
-import std.array : appender;
-import std.conv : to;
-import std.format.write : formattedWrite;
+import std.array : appender, Appender;
+import std.conv : to, toTextRange, text;
+import std.exception;
import std.windows.charset;
string sysErrorString(
@@ -79,16 +79,25 @@ string sysErrorString(
{
auto buf = appender!string();
- if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId)))
- {
- throw new Exception(
- "failed getting error string for WinAPI error code: " ~
- sysErrorString(GetLastError()));
- }
+ wenforce(
+ // Ignore unlikely UTF decoding errors, always report the actual error (`errCode`)
+ putSysError(errCode, buf, MAKELANGID(langId, subLangId)).ifThrown(false),
+ text("Could not fetch error string for WinAPI code ", errCode)
+ );
return buf.data;
}
+@safe unittest
+{
+ import std.algorithm.searching;
+
+ assert(sysErrorString(ERROR_PATH_NOT_FOUND) !is null);
+
+ const msg = collectExceptionMsg!WindowsException(sysErrorString(DWORD.max));
+ assert(msg.startsWith(`Could not fetch error string for WinAPI code 4294967295: `));
+}
+
bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0)
{
wchar *lpMsgBuf = null;
@@ -114,7 +123,6 @@ bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0)
return false;
}
-
class WindowsException : Exception
{
import core.sys.windows.windef : DWORD;
@@ -122,11 +130,11 @@ class WindowsException : Exception
final @property DWORD code() { return _code; } /// `GetLastError`'s return value.
private DWORD _code;
- this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted
+ this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted
{
_code = code;
- auto buf = appender!string();
+ auto buf = appender!(char[]);
if (str != null)
{
@@ -135,18 +143,43 @@ class WindowsException : Exception
buf.put(": ");
}
- if (code)
+ if (code && writeErrorMessage(code, buf))
{
- auto success = putSysError(code, buf);
- formattedWrite(buf, success ? " (error %d)" : "Error %d", code);
+ buf.put(" (error ");
+ toTextRange(code, buf);
+ buf.put(')');
}
- super(buf.data, file, line);
+ super(cast(immutable) buf.data, file, line);
}
}
+/// Writes the error string associated to `code` into `buf`.
+/// Writes `Error <code>` when the error message lookup fails
+private bool writeErrorMessage(DWORD code, ref Appender!(char[]) buf) nothrow
+{
+ bool success;
+ try
+ {
+ // Reset the buffer to undo partial changes
+ const len = buf[].length;
+ scope (failure) buf.shrinkTo(len);
-T wenforce(T, S)(T value, lazy S msg = null,
+ success = putSysError(code, buf);
+ }
+ catch (Exception) {}
+
+ // Write the error code instead if we couldn't find the string
+ if (!success)
+ {
+ buf.put("Error ");
+ toTextRange(code, buf);
+ }
+
+ return success;
+}
+
+T wenforce(T, S = string)(T value, lazy S msg = null,
string file = __FILE__, size_t line = __LINE__)
if (isSomeString!S)
{
@@ -177,11 +210,9 @@ T wenforce(T)(T condition, const(char)[] name, const(wchar)* namez, string file
throw new WindowsException(GetLastError(), names, file, line);
}
-version (Windows)
@system unittest
{
import std.algorithm.searching : startsWith, endsWith;
- import std.exception;
import std.string;
auto e = collectException!WindowsException(
@@ -199,3 +230,29 @@ version (Windows)
e = new WindowsException(0, "Test");
assert(e.msg == "Test");
}
+
+@safe nothrow unittest
+{
+ import std.algorithm.searching : endsWith;
+
+ auto e = new WindowsException(ERROR_FILE_NOT_FOUND);
+ assert(e.msg.endsWith("(error 2)"));
+
+ e = new WindowsException(DWORD.max);
+ assert(e.msg == "Error 4294967295");
+}
+
+/// Tries to translate an error code from the Windows API to the corresponding
+/// error message. Returns `Error <code>` on failure
+package (std) string generateSysErrorMsg(DWORD errCode = GetLastError()) nothrow @trusted
+{
+ auto buf = appender!(char[]);
+ cast(void) writeErrorMessage(errCode, buf);
+ return cast(immutable) buf[];
+}
+
+nothrow @safe unittest
+{
+ assert(generateSysErrorMsg(ERROR_PATH_NOT_FOUND) !is null);
+ assert(generateSysErrorMsg(DWORD.max) == "Error 4294967295");
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/message_with_null.d b/libphobos/testsuite/libphobos.exceptions/message_with_null.d
new file mode 100644
index 0000000..64092f0
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/message_with_null.d
@@ -0,0 +1,8 @@
+// { dg-shouldfail " world!" }
+// { dg-output "object.Exception@.*: hello.*world!" }
+module message_with_null;
+
+void main()
+{
+ throw new Exception("hello\0 world!");
+}