aboutsummaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-12-09 18:59:38 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-12-11 17:17:58 +0100
commit6d799f0aed18be25a5c908499b6411ab6d06b78c (patch)
tree3e6a91048c7fe3e78bae9f75b24eb37c5504681b /libphobos
parentcc7f509d3c0b3ab63891cf7ca2def0fdfb3642c4 (diff)
downloadgcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.zip
gcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.tar.gz
gcc-6d799f0aed18be25a5c908499b6411ab6d06b78c.tar.bz2
d: Merge upstream dmd, druntime c8ae4adb2e, phobos 792c8b7c1.
D front-end changes: - Import dmd v2.101.0. - Deprecate the ability to call `__traits(getAttributes)' on overload sets. - Deprecate non-empty `for' statement increment clause with no effect. - Array literals assigned to `scope' array variables can now be allocated on the stack. D runtime changes: - Import druntime v2.101.0. Phobos changes: - Import phobos v2.101.0. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd c8ae4adb2e. * typeinfo.cc (check_typeinfo_type): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Remove warning that toHash() must be declared 'nothrow @safe`. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c8ae4adb2e. * src/MERGE: Merge upstream phobos 792c8b7c1.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/core/demangle.d101
-rw-r--r--libphobos/libdruntime/core/exception.d24
-rw-r--r--libphobos/libdruntime/core/internal/gc/os.d3
-rw-r--r--libphobos/libdruntime/core/runtime.d2
-rw-r--r--libphobos/libdruntime/core/sync/condition.d35
-rw-r--r--libphobos/libdruntime/core/sync/mutex.d2
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/wait.d1
-rw-r--r--libphobos/libdruntime/core/sys/windows/winsock2.d4
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/algorithm/mutation.d2
-rw-r--r--libphobos/src/std/algorithm/sorting.d2
-rw-r--r--libphobos/src/std/array.d9
-rw-r--r--libphobos/src/std/base64.d6
-rw-r--r--libphobos/src/std/bitmanip.d4
-rw-r--r--libphobos/src/std/checkedint.d18
-rw-r--r--libphobos/src/std/concurrency.d4
-rw-r--r--libphobos/src/std/container/array.d28
-rw-r--r--libphobos/src/std/container/binaryheap.d4
-rw-r--r--libphobos/src/std/conv.d26
-rw-r--r--libphobos/src/std/datetime/systime.d4
-rw-r--r--libphobos/src/std/digest/hmac.d4
-rw-r--r--libphobos/src/std/exception.d8
-rw-r--r--libphobos/src/std/experimental/allocator/building_blocks/package.d12
-rw-r--r--libphobos/src/std/experimental/allocator/package.d17
-rw-r--r--libphobos/src/std/file.d13
-rw-r--r--libphobos/src/std/format/internal/write.d20
-rw-r--r--libphobos/src/std/format/package.d31
-rw-r--r--libphobos/src/std/format/write.d20
-rw-r--r--libphobos/src/std/getopt.d2
-rw-r--r--libphobos/src/std/math/hardware.d124
-rw-r--r--libphobos/src/std/process.d13
-rw-r--r--libphobos/src/std/range/package.d26
-rw-r--r--libphobos/src/std/socket.d29
-rw-r--r--libphobos/src/std/stdio.d210
-rw-r--r--libphobos/src/std/sumtype.d10
-rw-r--r--libphobos/src/std/traits.d28
-rw-r--r--libphobos/src/std/typecons.d10
-rw-r--r--libphobos/src/std/uni/package.d4
-rw-r--r--libphobos/src/std/utf.d4
-rw-r--r--libphobos/src/std/windows/registry.d2
41 files changed, 554 insertions, 316 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 2398875..5ee6f62 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-e4f89195913be1dc638707b1abb24c4f3ae7e0bf
+c8ae4adb2eda515b09b326948e3a4aa9f489af45
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/core/demangle.d b/libphobos/libdruntime/core/demangle.d
index c2d4032..869ade6 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -24,6 +24,11 @@ else version (WatchOS)
debug(trace) import core.stdc.stdio : printf;
debug(info) import core.stdc.stdio : printf;
+extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name,
+ char* output_buffer,
+ size_t* length,
+ int* status) nothrow pure @trusted;
+
private struct NoHooks
{
// supported hooks
@@ -2115,19 +2120,22 @@ pure @safe:
/**
- * Demangles D mangled names. If it is not a D mangled name, it returns its
- * argument name.
+ * Demangles D/C++ mangled names. If it is not a D/C++ mangled name, it
+ * returns its argument name.
*
* Params:
* buf = The string to demangle.
* dst = An optional destination buffer.
+ * __cxa_demangle = optional C++ demangler
*
* Returns:
- * The demangled name or the original string if the name is not a mangled D
- * name.
+ * The demangled name or the original string if the name is not a mangled
+ * D/C++ name.
*/
-char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe
+char[] demangle(return scope const(char)[] buf, return scope char[] dst = null, CXX_DEMANGLER __cxa_demangle = null) nothrow pure @safe
{
+ if (buf.length > 2 && buf[0..2] == "_Z")
+ return demangleCXX(buf, __cxa_demangle, dst);
auto d = Demangle!()(buf, dst);
// fast path (avoiding throwing & catching exception) for obvious
// non-D mangled names
@@ -2210,7 +2218,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
}
}
- bool parseLName(scope ref Remangle d) scope
+ bool parseLName(scope ref Remangle d) scope @trusted
{
flushPosition(d);
@@ -2261,7 +2269,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
}
else
{
- idpos[id] = refpos;
+ idpos[id] = refpos; //! scope variable id used as AA key, makes this function @trusted
result ~= d.buf[refpos .. d.pos];
}
}
@@ -2706,8 +2714,10 @@ unittest
{
char[] buf = new char[i];
auto ds = demangle(s, buf);
- assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[])" ||
- ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[])");
+ assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[], extern (C) char* function(const(char*), char*, ulong*, int*) pure nothrow @trusted*)" ||
+ ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[], extern (C) char* function(const(char*), char*, ulong*, int*) pure nothrow @trusted*)" ||
+ ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[], extern (C) char* function(const(char*), char*, uint*, int*) pure nothrow @trusted*)" ||
+ ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[], extern (C) char* function(const(char*), char*, uint*, int*) pure nothrow @trusted*)", ds);
}
}
@@ -2901,3 +2911,76 @@ private string toStringConsume (immutable ManglingFlagInfo[] infos, ref ushort b
}
return null;
}
+
+private shared CXX_DEMANGLER __cxa_demangle;
+
+/**
+ * Returns:
+ * a CXX_DEMANGLER if a C++ stdlib is loaded
+ */
+
+CXX_DEMANGLER getCXXDemangler() nothrow @trusted
+{
+ if (__cxa_demangle is null)
+ version (Posix)
+ {
+ import core.sys.posix.dlfcn : dlsym;
+ version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_DEFAULT;
+ version (FreeBSD) import core.sys.freebsd.dlfcn : RTLD_DEFAULT;
+ version (linux) import core.sys.linux.dlfcn : RTLD_DEFAULT;
+ version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_DEFAULT;
+ version (OSX) import core.sys.darwin.dlfcn : RTLD_DEFAULT;
+ version (Solaris) import core.sys.solaris.dlfcn : RTLD_DEFAULT;
+
+ if (auto found = cast(CXX_DEMANGLER) dlsym(RTLD_DEFAULT, "__cxa_demangle"))
+ __cxa_demangle = found;
+ }
+
+ if (__cxa_demangle is null)
+ __cxa_demangle = (const char* mangled_name, char* output_buffer,
+ size_t* length, int* status) nothrow pure @trusted {
+ *status = -1;
+ return null;
+ };
+
+ return __cxa_demangle;
+}
+
+/**
+ * Demangles C++ mangled names. If it is not a C++ mangled name, it
+ * returns its argument name.
+ *
+ * Params:
+ * buf = The string to demangle.
+ * __cxa_demangle = C++ demangler
+ * dst = An optional destination buffer.
+ *
+ * Returns:
+ * The demangled name or the original string if the name is not a mangled
+ * C++ name.
+ */
+private char[] demangleCXX(return scope const(char)[] buf, CXX_DEMANGLER __cxa_demangle, return scope char[] dst = null,) nothrow pure @trusted
+{
+ char[] c_string = dst; // temporarily use dst buffer if possible
+ c_string.length = buf.length + 1;
+ c_string[0 .. buf.length] = buf[0 .. buf.length];
+ c_string[buf.length] = '\0';
+
+ int status;
+ size_t demangled_length;
+ auto demangled = __cxa_demangle(&c_string[0], null, &demangled_length, &status);
+ scope (exit) {
+ import core.memory;
+ pureFree(cast(void*) demangled);
+ }
+ if (status == 0)
+ {
+ dst.length = demangled_length;
+ dst[] = demangled[0 .. demangled_length];
+ return dst;
+ }
+
+ dst.length = buf.length;
+ dst[] = buf[];
+ return dst;
+}
diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d
index a05a24c..62179fe 100644
--- a/libphobos/libdruntime/core/exception.d
+++ b/libphobos/libdruntime/core/exception.d
@@ -608,7 +608,7 @@ extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothr
* Throws:
* $(LREF RangeError).
*/
-extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
+extern (C) noreturn onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
{
throw staticError!RangeError(file, line, null);
}
@@ -626,7 +626,7 @@ extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @
* Throws:
* $(LREF ArraySliceError).
*/
-extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
+extern (C) noreturn onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
{
throw staticError!ArraySliceError(lower, upper, length, file, line, null);
@@ -644,7 +644,7 @@ extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t le
* Throws:
* $(LREF ArrayIndexError).
*/
-extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
+extern (C) noreturn onArrayIndexError( size_t index = 0, size_t length = 0,
string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
{
throw staticError!ArrayIndexError(index, length, file, line, null);
@@ -662,7 +662,7 @@ extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
* Throws:
* $(LREF FinalizeError).
*/
-extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
+extern (C) noreturn onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
{
// This error is thrown during a garbage collection, so no allocation must occur while
// generating this object. So we use a preallocated instance
@@ -679,13 +679,13 @@ version (D_BetterC)
// templates even for ordinary builds instead of providing them as an
// extern(C) library.
- void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
+ noreturn onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
{
assert(0, "Memory allocation failed");
}
alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
- void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
+ noreturn onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
{
assert(0, "Invalid memory operation");
}
@@ -699,14 +699,14 @@ else
* Throws:
* $(LREF OutOfMemoryError).
*/
- extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+ extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
{
// NOTE: Since an out of memory condition exists, no allocation must occur
// while generating this object.
throw staticError!OutOfMemoryError();
}
- extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
+ extern (C) noreturn onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
{
// suppress stacktrace until they are @nogc
throw staticError!OutOfMemoryError(false);
@@ -720,7 +720,7 @@ else
* Throws:
* $(LREF InvalidMemoryOperationError).
*/
-extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
{
// The same restriction applies as for onOutOfMemoryError. The GC is in an
// undefined state, thus no allocation must occur while generating this object.
@@ -738,7 +738,7 @@ extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @t
* Throws:
* $(LREF ConfigurationError).
*/
-extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
+extern (C) noreturn onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
{
throw staticError!ForkError( file, line, null );
}
@@ -755,7 +755,7 @@ extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @t
* Throws:
* $(LREF UnicodeException).
*/
-extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
+extern (C) noreturn onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
{
throw new UnicodeException( msg, idx, file, line );
}
@@ -859,7 +859,7 @@ extern (C)
private align(2 * size_t.sizeof) void[256] _store;
// only Errors for now as those are rarely chained
-private T staticError(T, Args...)(auto ref Args args)
+package T staticError(T, Args...)(auto ref Args args)
if (is(T : Error))
{
// pure hack, what we actually need is @noreturn and allow to call that in pure functions
diff --git a/libphobos/libdruntime/core/internal/gc/os.d b/libphobos/libdruntime/core/internal/gc/os.d
index 64f1203..38b60cb 100644
--- a/libphobos/libdruntime/core/internal/gc/os.d
+++ b/libphobos/libdruntime/core/internal/gc/os.d
@@ -70,10 +70,7 @@ else version (Posix)
else if (errno == ECHILD)
return ChildStatus.done; // someone called posix.syswait
else if (waited_pid != pid || status != 0)
- {
onForkError();
- return ChildStatus.error;
- }
return ChildStatus.done;
}
diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d
index 75e671c..799e525 100644
--- a/libphobos/libdruntime/core/runtime.d
+++ b/libphobos/libdruntime/core/runtime.d
@@ -910,7 +910,7 @@ private:
{
fixbuf[0 .. symBeg] = buf[0 .. symBeg];
- auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $]);
+ auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $], getCXXDemangler());
if (sym.ptr !is fixbuf.ptr + symBeg)
{
diff --git a/libphobos/libdruntime/core/sync/condition.d b/libphobos/libdruntime/core/sync/condition.d
index 674d78d..ddd04ae 100644
--- a/libphobos/libdruntime/core/sync/condition.d
+++ b/libphobos/libdruntime/core/sync/condition.d
@@ -20,6 +20,9 @@ public import core.sync.exception;
public import core.sync.mutex;
public import core.time;
+import core.exception : AssertError, staticError;
+
+
version (Windows)
{
import core.sync.semaphore;
@@ -51,7 +54,6 @@ else
// void notifyAll();
////////////////////////////////////////////////////////////////////////////////
-
/**
* This class represents a condition variable as conceived by C.A.R. Hoare. As
* per Mesa type monitors however, "signal" has been replaced with "notify" to
@@ -74,19 +76,19 @@ class Condition
* Throws:
* SyncError on error.
*/
- this( Mutex m ) nothrow @safe
+ this( Mutex m ) nothrow @safe @nogc
{
this(m, true);
}
/// ditto
- this( shared Mutex m ) shared nothrow @safe
+ this( shared Mutex m ) shared nothrow @safe @nogc
{
this(m, true);
}
//
- private this(this Q, M)( M m, bool _unused_ ) nothrow @trusted
+ private this(this Q, M)( M m, bool _unused_ ) nothrow @trusted @nogc
if ((is(Q == Condition) && is(M == Mutex)) ||
(is(Q == shared Condition) && is(M == shared Mutex)))
{
@@ -102,12 +104,12 @@ class Condition
}
m_blockLock = cast(HANDLE_TYPE) CreateSemaphoreA( null, 1, 1, null );
if ( m_blockLock == m_blockLock.init )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
scope(failure) CloseHandle( cast(void*) m_blockLock );
m_blockQueue = cast(HANDLE_TYPE) CreateSemaphoreA( null, 0, int.max, null );
if ( m_blockQueue == m_blockQueue.init )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
scope(failure) CloseHandle( cast(void*) m_blockQueue );
InitializeCriticalSection( cast(RTL_CRITICAL_SECTION*) &m_unblockLock );
@@ -123,29 +125,28 @@ class Condition
pthread_condattr_t attr = void;
int rc = pthread_condattr_init( &attr );
if ( rc )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
rc = pthread_condattr_setclock( &attr, CLOCK_MONOTONIC );
if ( rc )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
rc = pthread_cond_init( cast(pthread_cond_t*) &m_hndl, &attr );
if ( rc )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
rc = pthread_condattr_destroy( &attr );
if ( rc )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
} ();
}
else
{
int rc = pthread_cond_init( cast(pthread_cond_t*) &m_hndl, null );
if ( rc )
- throw new SyncError( "Unable to initialize condition" );
+ throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__);
}
}
}
-
- ~this()
+ ~this() @nogc
{
version (Windows)
{
@@ -231,7 +232,7 @@ class Condition
{
int rc = pthread_cond_wait( cast(pthread_cond_t*) &m_hndl, (cast(Mutex) m_assocMutex).handleAddr() );
if ( rc )
- throw new SyncError( "Unable to wait for condition" );
+ throw staticError!AssertError("Unable to wait for condition", __FILE__, __LINE__);
}
}
@@ -296,7 +297,7 @@ class Condition
return true;
if ( rc == ETIMEDOUT )
return false;
- throw new SyncError( "Unable to wait for condition" );
+ throw staticError!AssertError("Unable to wait for condition", __FILE__, __LINE__);
}
}
@@ -344,7 +345,7 @@ class Condition
rc = pthread_cond_signal( cast(pthread_cond_t*) &m_hndl );
} while ( rc == EAGAIN );
if ( rc )
- throw new SyncError( "Unable to notify condition" );
+ throw staticError!AssertError("Unable to notify condition", __FILE__, __LINE__);
}
}
@@ -392,7 +393,7 @@ class Condition
rc = pthread_cond_broadcast( cast(pthread_cond_t*) &m_hndl );
} while ( rc == EAGAIN );
if ( rc )
- throw new SyncError( "Unable to notify condition" );
+ throw staticError!AssertError("Unable to notify condition", __FILE__, __LINE__);
}
}
diff --git a/libphobos/libdruntime/core/sync/mutex.d b/libphobos/libdruntime/core/sync/mutex.d
index b848a14..e7380c46 100644
--- a/libphobos/libdruntime/core/sync/mutex.d
+++ b/libphobos/libdruntime/core/sync/mutex.d
@@ -292,7 +292,7 @@ private:
package:
version (Posix)
{
- pthread_mutex_t* handleAddr()
+ pthread_mutex_t* handleAddr() @nogc
{
return &m_hndl;
}
diff --git a/libphobos/libdruntime/core/sys/posix/sys/wait.d b/libphobos/libdruntime/core/sys/posix/sys/wait.d
index 766a4e0..145149b 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/wait.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/wait.d
@@ -451,6 +451,7 @@ else version (NetBSD)
}
else version (OpenBSD)
{
+ int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (DragonFlyBSD)
{
diff --git a/libphobos/libdruntime/core/sys/windows/winsock2.d b/libphobos/libdruntime/core/sys/windows/winsock2.d
index 5225645..b036df3 100644
--- a/libphobos/libdruntime/core/sys/windows/winsock2.d
+++ b/libphobos/libdruntime/core/sys/windows/winsock2.d
@@ -63,11 +63,11 @@ int getsockopt(SOCKET s, int level, int optname, void* optval, socklen_t* optlen
int setsockopt(SOCKET s, int level, int optname, const(void)* optval, socklen_t optlen);
uint inet_addr(const char* cp);
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, const(timeval)* timeout);
-@trusted char* inet_ntoa(in_addr ina);
+char* inet_ntoa(in_addr ina);
hostent* gethostbyname(const char* name);
hostent* gethostbyaddr(const(void)* addr, int len, int type);
protoent* getprotobyname(const char* name);
-@trusted protoent* getprotobynumber(int number);
+protoent* getprotobynumber(int number);
servent* getservbyname(const char* name, const char* proto);
servent* getservbyport(int port, const char* proto);
}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index d02f72d..09da6a8 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-3ad507b5125573c5b47736a0913105bfb1249746
+792c8b7c1d5957767e138f78d04bf175d4b92f10
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/mutation.d b/libphobos/src/std/algorithm/mutation.d
index 839183d..9b1d920 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -573,7 +573,7 @@ $(LINK2 http://en.cppreference.com/w/cpp/algorithm/copy_backward, STL's `copy_ba
Assigns `value` to each element of input range `range`.
Alternatively, instead of using a single `value` to fill the `range`,
-a `filter` $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
+a `filler` $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
can be provided. The length of `filler` and `range` do not need to match, but
`filler` must not be empty.
diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d
index 4fc7ee9..ddb80b8 100644
--- a/libphobos/src/std/algorithm/sorting.d
+++ b/libphobos/src/std/algorithm/sorting.d
@@ -3946,7 +3946,7 @@ if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
{
foreach (T2; ReferenceRanges)
{
- import std.array;
+ import std.array : array;
T1 A;
T2 B;
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index 3e88200..daa103a 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -169,8 +169,8 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
}
/// ditto
-ForeachType!(PointerTarget!Range)[] array(Range)(Range r)
-if (isPointer!Range && isIterable!(PointerTarget!Range) && !isAutodecodableString!Range && !isInfinite!Range)
+ForeachType!(typeof((*Range).init))[] array(Range)(Range r)
+if (is(Range : U*, U) && isIterable!U && !isAutodecodableString!Range && !isInfinite!Range)
{
return array(*r);
}
@@ -3416,7 +3416,8 @@ do
Implements an output range that appends data to an array. This is
recommended over $(D array ~= data) when appending many elements because it is more
efficient. `Appender` maintains its own array metadata locally, so it can avoid
-global locking for each append where $(LREF capacity) is non-zero.
+the $(DDSUBLINK spec/arrays, capacity-reserve, performance hit of looking up slice `capacity`)
+for each append.
Params:
A = the array type to simulate.
@@ -3587,7 +3588,7 @@ if (isDynamicArray!A)
private template canPutItem(U)
{
enum bool canPutItem =
- isImplicitlyConvertible!(Unqual!U, Unqual!T) ||
+ is(Unqual!U : Unqual!T) ||
isSomeChar!T && isSomeChar!U;
}
private template canPutConstRange(Range)
diff --git a/libphobos/src/std/base64.d b/libphobos/src/std/base64.d
index 2f7213b..0fc92ac 100644
--- a/libphobos/src/std/base64.d
+++ b/libphobos/src/std/base64.d
@@ -639,7 +639,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
*/
void popFront()
{
- enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining"));
+ assert(!empty, "Cannot call popFront on Encoder with no data remaining");
range_.popFront();
@@ -757,7 +757,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
*/
void popFront()
{
- enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining"));
+ assert(!empty, "Cannot call popFront on Encoder with no data remaining");
static if (Padding != NoPadding)
if (padding)
@@ -1414,7 +1414,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
*/
void popFront()
{
- enforce(!empty, new Base64Exception("Cannot call popFront on Decoder with no data remaining."));
+ assert(!empty, "Cannot call popFront on Decoder with no data remaining.");
range_.popFront();
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index f131257..559f8da 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -1418,9 +1418,9 @@ public:
/**
Flips a single bit, specified by `pos`
*/
- void flip(size_t i) @nogc pure nothrow
+ void flip(size_t pos) @nogc pure nothrow
{
- bt(_ptr, i) ? btr(_ptr, i) : bts(_ptr, i);
+ bt(_ptr, pos) ? btr(_ptr, pos) : bts(_ptr, pos);
}
///
diff --git a/libphobos/src/std/checkedint.d b/libphobos/src/std/checkedint.d
index 635c420..79597e8 100644
--- a/libphobos/src/std/checkedint.d
+++ b/libphobos/src/std/checkedint.d
@@ -630,36 +630,36 @@ if (isIntegral!T || is(T == Checked!(U, H), U, H))
import core.atomic : atomicLoad, MemoryOrder;
static if (is(typeof(this.payload.atomicLoad!(MemoryOrder.acq)) P))
{
- auto payload = __ctfe ? cast(P) this.payload
+ auto localPayload = __ctfe ? cast(P) this.payload
: this.payload.atomicLoad!(MemoryOrder.acq);
}
else
{
- alias payload = this.payload;
+ alias localPayload = this.payload;
}
static if (hasMember!(Hook, "hookToHash"))
{
- return hook.hookToHash(payload);
+ return hook.hookToHash(localPayload);
}
else static if (stateSize!Hook > 0)
{
- static if (hasMember!(typeof(payload), "toHash"))
+ static if (hasMember!(typeof(localPayload), "toHash"))
{
- return payload.toHash() ^ hashOf(hook);
+ return localPayload.toHash() ^ hashOf(hook);
}
else
{
- return hashOf(payload) ^ hashOf(hook);
+ return hashOf(localPayload) ^ hashOf(hook);
}
}
- else static if (hasMember!(typeof(payload), "toHash"))
+ else static if (hasMember!(typeof(localPayload), "toHash"))
{
- return payload.toHash();
+ return localPayload.toHash();
}
else
{
- return .hashOf(payload);
+ return .hashOf(localPayload);
}
}
diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d
index bc53236..323926a 100644
--- a/libphobos/src/std/concurrency.d
+++ b/libphobos/src/std/concurrency.d
@@ -480,7 +480,7 @@ private template isSpawnable(F, T...)
enum isParamsImplicitlyConvertible = false;
else static if (param1.length == i)
enum isParamsImplicitlyConvertible = true;
- else static if (isImplicitlyConvertible!(param2[i], param1[i]))
+ else static if (is(param2[i] : param1[i]))
enum isParamsImplicitlyConvertible = isParamsImplicitlyConvertible!(F1,
F2, i + 1);
else
@@ -2129,7 +2129,7 @@ private
static assert(T.length, "T must not be empty");
- static if (isImplicitlyConvertible!(T[0], Duration))
+ static if (is(T[0] : Duration))
{
alias Ops = AliasSeq!(T[1 .. $]);
alias ops = vals[1 .. $];
diff --git a/libphobos/src/std/container/array.d b/libphobos/src/std/container/array.d
index ecc4599..f5efe6d 100644
--- a/libphobos/src/std/container/array.d
+++ b/libphobos/src/std/container/array.d
@@ -34,7 +34,7 @@ pure @system unittest
float[] a0;
{
import std.range : iota;
- import std.array;
+ import std.array : array;
import std.algorithm.iteration : map;
a0 = iota (0, n).map!(i => i * 1.1f).array;
}
@@ -991,7 +991,7 @@ if (!is(immutable T == immutable bool))
*/
void removeBack()
{
- enforce(!empty);
+ assert(!empty);
static if (hasElaborateDestructor!T)
.destroy(_data._payload[$ - 1]);
@@ -1812,49 +1812,49 @@ if (is(immutable T == immutable bool))
/// Ditto
@property T front()
{
- enforce(!empty, "Attempting to access the front of an empty Array");
+ assert(!empty, "Attempting to access the front of an empty Array");
return _outer[_a];
}
/// Ditto
@property void front(bool value)
{
- enforce(!empty, "Attempting to set the front of an empty Array");
+ assert(!empty, "Attempting to set the front of an empty Array");
_outer[_a] = value;
}
/// Ditto
T moveFront()
{
- enforce(!empty, "Attempting to move the front of an empty Array");
+ assert(!empty, "Attempting to move the front of an empty Array");
return _outer.moveAt(_a);
}
/// Ditto
void popFront()
{
- enforce(!empty, "Attempting to popFront an empty Array");
+ assert(!empty, "Attempting to popFront an empty Array");
++_a;
}
/// Ditto
@property T back()
{
- enforce(!empty, "Attempting to access the back of an empty Array");
+ assert(!empty, "Attempting to access the back of an empty Array");
return _outer[_b - 1];
}
/// Ditto
@property void back(bool value)
{
- enforce(!empty, "Attempting to set the back of an empty Array");
+ assert(!empty, "Attempting to set the back of an empty Array");
_outer[_b - 1] = value;
}
/// Ditto
T moveBack()
{
- enforce(!empty, "Attempting to move the back of an empty Array");
+ assert(!empty, "Attempting to move the back of an empty Array");
return _outer.moveAt(_b - 1);
}
/// Ditto
void popBack()
{
- enforce(!empty, "Attempting to popBack an empty Array");
+ assert(!empty, "Attempting to popBack an empty Array");
--_b;
}
/// Ditto
@@ -2029,14 +2029,14 @@ if (is(immutable T == immutable bool))
*/
@property bool front()
{
- enforce(!empty);
+ assert(!empty);
return data.ptr[0] & 1;
}
/// Ditto
@property void front(bool value)
{
- enforce(!empty);
+ assert(!empty);
if (value) data.ptr[0] |= 1;
else data.ptr[0] &= ~cast(size_t) 1;
}
@@ -2052,14 +2052,14 @@ if (is(immutable T == immutable bool))
*/
@property bool back()
{
- enforce(!empty);
+ assert(!empty);
return cast(bool)(data.back & (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord)));
}
/// Ditto
@property void back(bool value)
{
- enforce(!empty);
+ assert(!empty);
if (value)
{
data.back |= (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord));
diff --git a/libphobos/src/std/container/binaryheap.d b/libphobos/src/std/container/binaryheap.d
index 723630c..7ff14fc 100644
--- a/libphobos/src/std/container/binaryheap.d
+++ b/libphobos/src/std/container/binaryheap.d
@@ -249,7 +249,7 @@ according to `less`.
*/
@property ElementType!Store front()
{
- enforce(!empty, "Cannot call front on an empty heap.");
+ assert(!empty, "Cannot call front on an empty heap.");
return _store.front;
}
@@ -317,7 +317,7 @@ Removes the largest element from the heap.
*/
void removeFront()
{
- enforce(!empty, "Cannot call removeFront on an empty heap.");
+ assert(!empty, "Cannot call removeFront on an empty heap.");
if (_length > 1)
{
auto t1 = _store[].moveFront();
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 0f66065..d1b6421 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -162,12 +162,12 @@ private
template isEnumStrToStr(S, T)
{
- enum isEnumStrToStr = isImplicitlyConvertible!(S, T) &&
+ enum isEnumStrToStr = is(S : T) &&
is(S == enum) && isExactSomeString!T;
}
template isNullToStr(S, T)
{
- enum isNullToStr = isImplicitlyConvertible!(S, T) &&
+ enum isNullToStr = is(S : T) &&
(is(immutable S == immutable typeof(null))) && isExactSomeString!T;
}
}
@@ -542,7 +542,7 @@ If the source type is implicitly convertible to the target type, $(D
to) simply performs the implicit conversion.
*/
private T toImpl(T, S)(S value)
-if (isImplicitlyConvertible!(S, T) &&
+if (is(S : T) &&
!isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
{
template isSignedInt(T)
@@ -699,7 +699,7 @@ if (isStaticArray!S)
When source type supports member template function opCast, it is used.
*/
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
is(typeof(S.init.opCast!T()) : T) &&
!isExactSomeString!T &&
!is(typeof(T(value))))
@@ -750,7 +750,7 @@ $(UL $(LI If target type is struct, `T(value)` is used.)
$(LI If target type is class, $(D new T(value)) is used.))
*/
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
is(T == struct) && is(typeof(T(value))))
{
return T(value);
@@ -799,7 +799,7 @@ if (!isImplicitlyConvertible!(S, T) &&
/// ditto
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
is(T == class) && is(typeof(new T(value))))
{
return new T(value);
@@ -872,7 +872,7 @@ Object-to-object conversions by dynamic casting throw exception when the source
non-null and the target is null.
*/
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
(is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
(is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
{
@@ -957,7 +957,7 @@ if (!isImplicitlyConvertible!(S, T) &&
alias tgtmod = AddModifier!m2;
// Compile time convertible equals to modifier convertible.
- static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object))
+ static if (is(srcmod!Object : tgtmod!Object))
{
// Test runtime conversions: class to class, class to interface,
// interface to class, and interface to interface
@@ -993,7 +993,7 @@ if (!isImplicitlyConvertible!(S, T) &&
Handles type _to string conversions
*/
private T toImpl(T, S)(S value)
-if (!(isImplicitlyConvertible!(S, T) &&
+if (!(is(S : T) &&
!isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
!isInfinite!S && isExactSomeString!T)
{
@@ -1138,7 +1138,7 @@ if (!(isImplicitlyConvertible!(S, T) &&
To string conversion for non copy-able structs
*/
private T toImpl(T, S)(ref S value)
-if (!(isImplicitlyConvertible!(S, T) &&
+if (!(is(S : T) &&
!isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
!isInfinite!S && isExactSomeString!T && !isCopyable!S && !isStaticArray!S)
{
@@ -1528,7 +1528,7 @@ Narrowing numeric-numeric conversions throw when the value does not
fit in the narrower type.
*/
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
(isNumeric!S || isSomeChar!S || isBoolean!S) &&
(isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
{
@@ -1643,7 +1643,7 @@ Array-to-array conversion (except when target is a string type)
converts each element in turn by using `to`.
*/
private T toImpl(T, S)(scope S value)
-if (!isImplicitlyConvertible!(S, T) &&
+if (!is(S : T) &&
!isSomeString!S && isDynamicArray!S &&
!isExactSomeString!T && isArray!T)
{
@@ -1725,7 +1725,7 @@ Associative array to associative array conversion converts each key
and each value in turn.
*/
private T toImpl(T, S)(S value)
-if (!isImplicitlyConvertible!(S, T) && isAssociativeArray!S &&
+if (!is(S : T) && isAssociativeArray!S &&
isAssociativeArray!T && !is(T == enum))
{
/* This code is potentially unsafe.
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index e80f122..6898934 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -10095,7 +10095,7 @@ else version (Windows)
static void testScope(scope ref SysTime st) @safe
{
- auto result = SysTimeToSYSTEMTIME(st);
+ auto localResult = SysTimeToSYSTEMTIME(st);
}
}
@@ -10178,7 +10178,7 @@ else version (Windows)
static void testScope(scope ref SysTime st) @safe
{
- auto result = SysTimeToFILETIME(st);
+ auto local_result = SysTimeToFILETIME(st);
}
}
}
diff --git a/libphobos/src/std/digest/hmac.d b/libphobos/src/std/digest/hmac.d
index 6864fc3..6688ba7 100644
--- a/libphobos/src/std/digest/hmac.d
+++ b/libphobos/src/std/digest/hmac.d
@@ -202,14 +202,14 @@ if (hashBlockSize % 8 == 0)
import std.string : representation;
string data1 = "Hello, world", data2 = "Hola mundo";
auto hmac = HMAC!SHA1("My s3cR3T keY".representation);
- auto digest = hmac.put(data1.representation)
+ auto testDigest = hmac.put(data1.representation)
.put(data2.representation)
.finish();
static immutable expected = [
197, 57, 52, 3, 13, 194, 13,
36, 117, 228, 8, 11, 111, 51,
165, 3, 123, 31, 251, 113];
- assert(digest == expected);
+ assert(testDigest == expected);
}
}
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index 129c05d..b699a8e 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -1069,9 +1069,9 @@ as the language is free to assume objects don't have internal pointers
*/
bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow
if (__traits(isRef, source) || isDynamicArray!S ||
- isPointer!S || is(S == class))
+ is(S : U*, U) || is(S == class))
{
- static if (isPointer!S || is(S == class) || is(S == interface))
+ static if (is(S : U*, U) || is(S == class) || is(S == interface))
{
const m = *cast(void**) &source;
const b = cast(void*) &target;
@@ -1115,9 +1115,9 @@ bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target
/// ditto
bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
if (__traits(isRef, source) || isDynamicArray!S ||
- isPointer!S || is(S == class))
+ is(S : U*, U) || is(S == class))
{
- static if (isPointer!S || is(S == class) || is(S == interface))
+ static if (is(S : U*, U) || is(S == class) || is(S == interface))
{
const m = *cast(void**) &source;
const b = cast(void*) &target;
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/package.d b/libphobos/src/std/experimental/allocator/building_blocks/package.d
index 962ed91..6bc527d 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/package.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/package.d
@@ -147,7 +147,11 @@ Sizes through 3584 bytes are handled via freelists of staggered sizes. Sizes
from 3585 bytes through 4072 KB are handled by a `BitmappedBlock` with a
block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`.
-----
+$(RUNNABLE_EXAMPLE
+ ----
+ import std.experimental.allocator;
+ import std.algorithm.comparison : max;
+
alias FList = FreeList!(GCAllocator, 0, unbounded);
alias A = Segregator!(
8, FreeList!(GCAllocator, 0, 8),
@@ -157,8 +161,7 @@ block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`.
1024, Bucketizer!(FList, 513, 1024, 128),
2048, Bucketizer!(FList, 1025, 2048, 256),
3584, Bucketizer!(FList, 2049, 3584, 512),
- 4072 * 1024, AllocatorList!(
- () => BitmappedBlock!(GCAllocator, 4096)(4072 * 1024)),
+ 4072 * 1024, AllocatorList!(n => Region!GCAllocator(max(n, 1024 * 4096))),
GCAllocator
);
A tuMalloc;
@@ -169,7 +172,8 @@ block size of 4 KB. Sizes above that are passed direct to the `GCAllocator`.
assert(tuMalloc.expand(c, 14));
tuMalloc.deallocate(b);
tuMalloc.deallocate(c);
-----
+ ----
+)
$(H2 Allocating memory for sharing across threads)
diff --git a/libphobos/src/std/experimental/allocator/package.d b/libphobos/src/std/experimental/allocator/package.d
index 2177926..7dbc47a 100644
--- a/libphobos/src/std/experimental/allocator/package.d
+++ b/libphobos/src/std/experimental/allocator/package.d
@@ -27,13 +27,22 @@ $(TR $(TD Global) $(TD
$(LREF theAllocator)
))
$(TR $(TD Class interface) $(TD
- $(LREF allocatorObject)
$(LREF CAllocatorImpl)
+ $(LREF CSharedAllocatorImpl)
$(LREF IAllocator)
+ $(LREF ISharedAllocator)
+))
+$(TR $(TD Structs) $(TD
+ $(LREF allocatorObject)
+ $(LREF RCIAllocator)
+ $(LREF RCISharedAllocator)
+ $(LREF sharedAllocatorObject)
+ $(LREF ThreadLocal)
))
)
Synopsis:
+$(RUNNABLE_EXAMPLE
---
// Allocate an int, initialize it with 42
int* p = theAllocator.make!int(42);
@@ -46,7 +55,10 @@ p = processAllocator.make!int(100);
assert(*p == 100);
// Destroy and deallocate
processAllocator.dispose(p);
-
+---
+)
+$(RUNNABLE_EXAMPLE
+---
// Create an array of 50 doubles initialized to -1.0
double[] arr = theAllocator.makeArray!double(50, -1.0);
// Append two zeros to it
@@ -56,6 +68,7 @@ theAllocator.shrinkArray(arr, 2);
// Destroy and deallocate
theAllocator.dispose(arr);
---
+)
$(H2 Layered Structure)
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 8d1b431..d031096 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -4986,21 +4986,20 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
{
string[] listdir(string pathname)
{
- import std.algorithm;
- import std.array;
- import std.file;
- import std.path;
+ import std.algorithm.iteration : map, filter;
+ import std.array : array;
+ import std.path : baseName;
- return std.file.dirEntries(pathname, SpanMode.shallow)
+ return dirEntries(pathname, SpanMode.shallow)
.filter!(a => a.isFile)
- .map!((return a) => std.path.baseName(a.name))
+ .map!((return a) => baseName(a.name))
.array;
}
// Can be safe only with -preview=dip1000
@safe void main(string[] args)
{
- import std.stdio;
+ import std.stdio : writefln;
string[] files = listdir(args[1]);
writefln("%s", files);
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 8089cfa..32c82995 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -3011,7 +3011,7 @@ void enforceValidFormatSpec(T, Char)(scope const ref FormatSpec!Char f)
/*
`enum`s are formatted like their base value
*/
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) val, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, T val, scope const ref FormatSpec!Char f)
if (is(T == enum))
{
import std.array : appender;
@@ -3020,21 +3020,15 @@ if (is(T == enum))
if (f.spec != 's')
return formatValueImpl(w, cast(OriginalType!T) val, f);
- static foreach (e; EnumMembers!T)
- {
- if (val == e)
- {
- formatValueImpl(w, __traits(identifier, e), f);
- return;
- }
- }
+ foreach (immutable member; __traits(allMembers, T))
+ if (val == __traits(getMember, T, member))
+ return formatValueImpl(w, member, f);
auto w2 = appender!string();
// val is not a member of T, output cast(T) rawValue instead.
- put(w2, "cast(");
- put(w2, T.stringof);
- put(w2, ")");
+ enum prefix = "cast(" ~ T.stringof ~ ")";
+ put(w2, prefix);
static assert(!is(OriginalType!T == T), "OriginalType!" ~ T.stringof ~
"must not be equal to " ~ T.stringof);
@@ -3154,7 +3148,7 @@ if (isPointer!T && !is(T == enum) && !hasToString!(T, Char))
auto a = iota(0, 10);
auto b = iota(0, 10);
- auto p = () @trusted { auto p = &a; return p; }();
+ auto p = () @trusted { auto result = &a; return result; }();
assert(format("%s",p) != format("%s",b));
}
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index d83f028..f1d4705 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -212,17 +212,17 @@ There are several flags that affect the outcome of the formatting.
$(BOOKTABLE ,
$(TR $(TH Flag) $(TH Semantics))
$(TR $(TD $(B '-'))
- $(TD When the formatted result is shorter then the value
- given by the width parameter, the output is right
- justified. With the $(B '-') flag this is changed
- to left justification.
+ $(TD When the formatted result is shorter than the value
+ given by the width parameter, the output is left
+ justified. Without the $(B '-') flag, the output remains
+ right justified.
There are two exceptions where the $(B '-') flag has a
different meaning: (1) with $(B 'r') it denotes to use little
endian and (2) in case of a compound indicator it means that
no special handling of the members is applied.))
$(TR $(TD $(B '='))
- $(TD When the formatted result is shorter then the value
+ $(TD When the formatted result is shorter than the value
given by the width parameter, the output is centered.
If the central position is not possible it is moved slightly
to the right. In this case, if $(B '-') flag is present in
@@ -1563,6 +1563,14 @@ char[] sformat(Char, Args...)(return scope char[] buf, scope const(Char)[] fmt,
{
char[] buf;
size_t i;
+ void put(char c)
+ {
+ if (buf.length <= i)
+ throw new RangeError(__FILE__, __LINE__);
+
+ buf[i] = c;
+ i += 1;
+ }
void put(dchar c)
{
char[4] enc;
@@ -1687,6 +1695,19 @@ if (isSomeString!(typeof(fmt)))
assert(u == v);
}
+@safe unittest // https://issues.dlang.org/show_bug.cgi?id=23488
+{
+ static struct R
+ {
+ string s = "Ü";
+ bool empty() { return s.length == 0; }
+ char front() { return s[0]; }
+ void popFront() { s = s[1 .. $]; }
+ }
+ char[2] buf;
+ assert(sformat(buf, "%s", R()) == "Ü");
+}
+
version (StdUnittest)
private void formatReflectTest(T)(ref T val, string fmt, string formatted, string fn = __FILE__, size_t ln = __LINE__)
{
diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d
index cbab512..2aa45d7 100644
--- a/libphobos/src/std/format/write.d
+++ b/libphobos/src/std/format/write.d
@@ -1310,3 +1310,23 @@ void formatValue(Writer, T, Char)(auto ref Writer w, auto ref T val, scope const
writer.formatValue(a, spec);
assert(writer.data == "0");
}
+
+// https://issues.dlang.org/show_bug.cgi?id=23400
+@safe pure unittest
+{
+ import std.range : nullSink;
+ import std.format.spec : singleSpec;
+
+ static struct S
+ {
+ // non-const opEquals method
+ bool opEquals(S rhs) { return false; }
+ }
+
+ enum E { a = S() }
+
+ E e;
+ auto writer = nullSink;
+ const spec = singleSpec("%s");
+ writer.formatValue(e, spec);
+}
diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d
index b239901..c85247f 100644
--- a/libphobos/src/std/getopt.d
+++ b/libphobos/src/std/getopt.d
@@ -558,7 +558,7 @@ private template optionValidator(A...)
import std.format : format;
enum fmt = "getopt validator: %s (at position %d)";
- enum isReceiver(T) = isPointer!T || (is(T == function)) || (is(T == delegate));
+ enum isReceiver(T) = is(T : U*, U) || (is(T == function)) || (is(T == delegate));
enum isOptionStr(T) = isSomeString!T || isSomeChar!T;
auto validator()
diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d
index 40e42da..81c7302 100644
--- a/libphobos/src/std/math/hardware.d
+++ b/libphobos/src/std/math/hardware.d
@@ -37,13 +37,6 @@ version (RISCV64) version = RISCV_Any;
version (D_InlineAsm_X86) version = InlineAsm_X86_Any;
version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
-version (InlineAsm_X86_Any) version = InlineAsm_X87;
-version (InlineAsm_X87)
-{
- static assert(real.mant_dig == 64);
- version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC;
-}
-
version (X86_64) version = StaticallyHaveSSE;
version (X86) version (OSX) version = StaticallyHaveSSE;
@@ -76,19 +69,6 @@ version (D_HardFloat)
version (IeeeFlagsSupport) version = FloatingPointControlSupport;
}
-version (GNU)
-{
- // The compiler can unexpectedly rearrange floating point operations and
- // access to the floating point status flags when optimizing. This means
- // ieeeFlags tests cannot be reliably checked in optimized code.
- // See https://github.com/ldc-developers/ldc/issues/888
-}
-else
-{
- version = IeeeFlagsUnittest;
- version = FloatingPointControlUnittest;
-}
-
version (IeeeFlagsSupport)
{
@@ -368,7 +348,7 @@ public:
}
///
-version (IeeeFlagsUnittest)
+version (StdDdoc)
@safe unittest
{
import std.math.traits : isNaN;
@@ -376,17 +356,14 @@ version (IeeeFlagsUnittest)
static void func() {
int a = 10 * 10;
}
- pragma(inline, false) static void blockopt(ref real x) {}
real a = 3.5;
// Set all the flags to zero
resetIeeeFlags();
assert(!ieeeFlags.divByZero);
- blockopt(a); // avoid constant propagation by the optimizer
// Perform a division by zero.
a /= 0.0L;
assert(a == real.infinity);
assert(ieeeFlags.divByZero);
- blockopt(a); // avoid constant propagation by the optimizer
// Create a NaN
a *= 0.0L;
assert(ieeeFlags.invalid);
@@ -399,7 +376,33 @@ version (IeeeFlagsUnittest)
assert(ieeeFlags == f);
}
-version (IeeeFlagsUnittest)
+@safe unittest
+{
+ import std.math.traits : isNaN;
+
+ static void func() {
+ int a = 10 * 10;
+ }
+ real a = 3.5;
+ // Set all the flags to zero
+ resetIeeeFlags();
+ assert(!ieeeFlags.divByZero);
+ // Perform a division by zero.
+ a = forceDivOp(a, 0.0L);
+ assert(a == real.infinity);
+ assert(ieeeFlags.divByZero);
+ // Create a NaN
+ a = forceMulOp(a, 0.0L);
+ assert(ieeeFlags.invalid);
+ assert(isNaN(a));
+
+ // Check that calling func() has no effect on the
+ // status flags.
+ IeeeFlags f = ieeeFlags;
+ func();
+ assert(ieeeFlags == f);
+}
+
@safe unittest
{
import std.meta : AliasSeq;
@@ -412,27 +415,26 @@ version (IeeeFlagsUnittest)
static foreach (T; AliasSeq!(float, double, real))
{{
- T x; /* Needs to be here to trick -O. It would optimize away the
- calculations if x were local to the function literals. */
+ T x; // Needs to be here to avoid `call without side effects` warning.
auto tests = [
Test(
- () { x = 1; x += 0.1L; },
+ () { x = forceAddOp!T(1, 0.1L); },
() => ieeeFlags.inexact
),
Test(
- () { x = T.min_normal; x /= T.max; },
+ () { x = forceDivOp!T(T.min_normal, T.max); },
() => ieeeFlags.underflow
),
Test(
- () { x = T.max; x += T.max; },
+ () { x = forceAddOp!T(T.max, T.max); },
() => ieeeFlags.overflow
),
Test(
- () { x = 1; x /= 0; },
+ () { x = forceDivOp!T(1, 0); },
() => ieeeFlags.divByZero
),
Test(
- () { x = 0; x /= 0; },
+ () { x = forceDivOp!T(0, 0); },
() => ieeeFlags.invalid
)
];
@@ -453,14 +455,24 @@ void resetIeeeFlags() @trusted nothrow @nogc
}
///
+version (StdDdoc)
@safe unittest
{
- pragma(inline, false) static void blockopt(ref real x) {}
resetIeeeFlags();
real a = 3.5;
- blockopt(a); // avoid constant propagation by the optimizer
a /= 0.0L;
- blockopt(a); // avoid constant propagation by the optimizer
+ assert(a == real.infinity);
+ assert(ieeeFlags.divByZero);
+
+ resetIeeeFlags();
+ assert(!ieeeFlags.divByZero);
+}
+
+@safe unittest
+{
+ resetIeeeFlags();
+ real a = 3.5;
+ a = forceDivOp(a, 0.0L);
assert(a == real.infinity);
assert(ieeeFlags.divByZero);
@@ -475,25 +487,39 @@ void resetIeeeFlags() @trusted nothrow @nogc
}
///
+version (StdDdoc)
@safe nothrow unittest
{
import std.math.traits : isNaN;
- pragma(inline, false) static void blockopt(ref real x) {}
resetIeeeFlags();
real a = 3.5;
- blockopt(a); // avoid constant propagation by the optimizer
a /= 0.0L;
assert(a == real.infinity);
assert(ieeeFlags.divByZero);
- blockopt(a); // avoid constant propagation by the optimizer
a *= 0.0L;
assert(isNaN(a));
assert(ieeeFlags.invalid);
}
+@safe nothrow unittest
+{
+ import std.math.traits : isNaN;
+
+ resetIeeeFlags();
+ real a = 3.5;
+
+ a = forceDivOp(a, 0.0L);
+ assert(a == real.infinity);
+ assert(ieeeFlags.divByZero);
+
+ a = forceMulOp(a, 0.0L);
+ assert(isNaN(a));
+ assert(ieeeFlags.invalid);
+}
+
} // IeeeFlagsSupport
@@ -1100,7 +1126,6 @@ private:
}
///
-version (FloatingPointControlUnittest)
@safe unittest
{
import std.math.rounding : lrint;
@@ -1154,32 +1179,27 @@ version (FloatingPointControlUnittest)
ensureDefaults();
}
-version (FloatingPointControlUnittest)
@safe unittest // rounding
{
import std.meta : AliasSeq;
static T addRound(T)(uint rm)
{
- pragma(inline, false) static void blockopt(ref T x) {}
pragma(inline, false);
FloatingPointControl fpctrl;
fpctrl.rounding = rm;
T x = 1;
- blockopt(x); // avoid constant propagation by the optimizer
- x += 0.1L;
+ x = forceAddOp(x, 0.1L);
return x;
}
static T subRound(T)(uint rm)
{
- pragma(inline, false) static void blockopt(ref T x) {}
pragma(inline, false);
FloatingPointControl fpctrl;
fpctrl.rounding = rm;
T x = -1;
- blockopt(x); // avoid constant propagation by the optimizer
- x -= 0.1L;
+ x = forceSubOp(x, 0.1L);
return x;
}
@@ -1210,4 +1230,16 @@ version (FloatingPointControlUnittest)
}}
}
+} // FloatingPointControlSupport
+
+version (StdUnittest)
+{
+ // These helpers are intended to avoid constant propagation by the optimizer.
+ pragma(inline, false) private @safe
+ {
+ T forceAddOp(T)(T x, T y) { return x + y; }
+ T forceSubOp(T)(T x, T y) { return x - y; }
+ T forceMulOp(T)(T x, T y) { return x * y; }
+ T forceDivOp(T)(T x, T y) { return x / y; }
+ }
}
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index d4fe8a1..3eaa283 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -1428,7 +1428,7 @@ version (Posix) @system unittest
for (; environ[i] != null; ++i)
{
assert(e2[i] != null);
- import core.stdc.string;
+ import core.stdc.string : strcmp;
assert(strcmp(e2[i], environ[i]) == 0);
}
assert(e2[i] == null);
@@ -1732,7 +1732,9 @@ version (Posix) @system unittest
// Pipes
void testPipes(Config config)
{
- import std.file, std.uuid, core.thread, std.exception;
+ import std.file : tempDir, exists, remove;
+ import std.uuid : randomUUID;
+ import std.exception : collectException;
auto pipei = pipe();
auto pipeo = pipe();
auto pipee = pipe();
@@ -1753,11 +1755,14 @@ version (Posix) @system unittest
// Files
void testFiles(Config config)
{
- import std.ascii, std.file, std.uuid, core.thread, std.exception;
+ import std.ascii : newline;
+ import std.file : tempDir, exists, remove, readText, write;
+ import std.uuid : randomUUID;
+ import std.exception : collectException;
auto pathi = buildPath(tempDir(), randomUUID().toString());
auto patho = buildPath(tempDir(), randomUUID().toString());
auto pathe = buildPath(tempDir(), randomUUID().toString());
- std.file.write(pathi, "INPUT"~std.ascii.newline);
+ write(pathi, "INPUT" ~ newline);
auto filei = File(pathi, "r");
auto fileo = File(patho, "w");
auto filee = File(pathe, "w");
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 9197134..888ac1a 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -3774,10 +3774,17 @@ private:
alias fun = Fun[0];
enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
+
+ import std.traits : hasIndirections;
+ static if (!hasIndirections!(ReturnType!fun))
+ alias RetType = Unqual!(ReturnType!fun);
+ else
+ alias RetType = ReturnType!fun;
+
static if (returnByRef_)
- ReturnType!fun *elem_;
+ RetType *elem_;
else
- ReturnType!fun elem_;
+ RetType elem_;
public:
/// Range primitives
enum empty = false;
@@ -3866,6 +3873,13 @@ public:
assert(g.front == f + 5);
}
+// https://issues.dlang.org/show_bug.cgi?id=23319
+@safe pure nothrow unittest
+{
+ auto b = generate!(() => const(int)(42));
+ assert(b.front == 42);
+}
+
/**
Repeats the given forward range ad infinitum. If the original range is
infinite (fact that would make `Cycle` the identity application),
@@ -6856,6 +6870,7 @@ if (!isIntegral!(CommonType!(B, E)) &&
assert(!empty);
++current;
}
+ @property auto save() { return this; }
}
return Result(begin, end);
}
@@ -6890,6 +6905,13 @@ if (!isIntegral!(CommonType!(B, E)) &&
assert(i2.equal([3, 4, 0, 1 ]));
}
+// https://issues.dlang.org/show_bug.cgi?id=23453
+@safe unittest
+{
+ auto r = iota('a', 'z');
+ static assert(isForwardRange!(typeof(r)));
+}
+
/**
Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
(below).
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index fb2c2d4..593052e 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -2628,7 +2628,7 @@ private:
AddressFamily _family;
version (Windows)
- bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
+ bool _blocking = true; /// Property to get or set whether the socket is blocking or nonblocking.
// The WinSock timeouts seem to be effectively skewed by a constant
// offset of about half a second (value in milliseconds). This has
@@ -2641,22 +2641,22 @@ private:
{
if (runSlowTests)
softUnittest({
- import std.datetime.stopwatch;
- import std.typecons;
+ import std.datetime.stopwatch : StopWatch;
+ import std.typecons : Yes;
enum msecs = 1000;
auto pair = socketPair();
- auto sock = pair[0];
- sock.setOption(SocketOptionLevel.SOCKET,
+ auto testSock = pair[0];
+ testSock.setOption(SocketOptionLevel.SOCKET,
SocketOption.RCVTIMEO, dur!"msecs"(msecs));
auto sw = StopWatch(Yes.autoStart);
ubyte[1] buf;
- sock.receive(buf);
+ testSock.receive(buf);
sw.stop();
Duration readBack = void;
- sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack);
+ testSock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack);
assert(readBack.total!"msecs" == msecs);
assert(sw.peek().total!"msecs" > msecs - 100 && sw.peek().total!"msecs" < msecs + 100);
@@ -2751,6 +2751,21 @@ public:
}
/**
+ * Releases the underlying socket handle from the Socket object. Once it
+ * is released, you cannot use the Socket object's methods anymore. This
+ * also means the Socket destructor will no longer close the socket - it
+ * becomes your responsibility.
+ *
+ * To get the handle without releasing it, use the `handle` property.
+ */
+ @property socket_t release() pure nothrow @nogc
+ {
+ auto h = sock;
+ this.sock = socket_t.init;
+ return h;
+ }
+
+ /**
* Get/set socket's blocking flag.
*
* When a socket is blocking, calls to receive(), accept(), and send()
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index ffd6da8..802aa128 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -52,7 +52,7 @@ import std.algorithm.mutation : copy;
import std.meta : allSatisfy;
import std.range : ElementEncodingType, empty, front, isBidirectionalRange,
isInputRange, isSomeFiniteCharInputRange, put;
-import std.traits : isSomeChar, isSomeString, Unqual, isPointer;
+import std.traits : isSomeChar, isSomeString, Unqual;
import std.typecons : Flag, No, Yes;
/++
@@ -768,7 +768,7 @@ Throws: `ErrnoException` in case of error.
_name = name;
}
- @system unittest // Test changing filename
+ @safe unittest // Test changing filename
{
import std.exception : assertThrown, assertNotThrown;
static import std.file;
@@ -790,7 +790,7 @@ Throws: `ErrnoException` in case of error.
version (CRuntime_DigitalMars) {} else // Not implemented
version (CRuntime_Microsoft) {} else // Not implemented
- @system unittest // Test changing mode
+ @safe unittest // Test changing mode
{
import std.exception : assertThrown, assertNotThrown;
static import std.file;
@@ -1853,15 +1853,15 @@ void main()
}
---
*/
- S readln(S = string)(dchar terminator = '\n')
+ S readln(S = string)(dchar terminator = '\n') @safe
if (isSomeString!S)
{
Unqual!(ElementEncodingType!S)[] buf;
readln(buf, terminator);
- return cast(S) buf;
+ return (() @trusted => cast(S) buf)();
}
- @system unittest
+ @safe unittest
{
import std.algorithm.comparison : equal;
static import std.file;
@@ -1885,7 +1885,7 @@ void main()
}}
}
- @system unittest
+ @safe unittest
{
static import std.file;
import std.typecons : Tuple;
@@ -1984,7 +1984,7 @@ void main()
This is actually what $(LREF byLine) does internally, so its usage
is recommended if you want to process a complete file.
*/
- size_t readln(C)(ref C[] buf, dchar terminator = '\n')
+ size_t readln(C)(ref C[] buf, dchar terminator = '\n') @safe
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum))
{
import std.exception : enforce;
@@ -2020,9 +2020,8 @@ is recommended if you want to process a complete file.
}
}
- @system unittest
+ @safe unittest
{
- // @system due to readln
static import std.file;
auto deleteme = testFilename();
std.file.write(deleteme, "123\n456789");
@@ -2039,7 +2038,7 @@ is recommended if you want to process a complete file.
}
// https://issues.dlang.org/show_bug.cgi?id=15293
- @system unittest
+ @safe unittest
{
// @system due to readln
static import std.file;
@@ -2063,7 +2062,7 @@ is recommended if you want to process a complete file.
}
/** ditto */
- size_t readln(C, R)(ref C[] buf, R terminator)
+ size_t readln(C, R)(ref C[] buf, R terminator) @safe
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
isBidirectionalRange!R && is(typeof(terminator.front == dchar.init)))
{
@@ -2093,7 +2092,7 @@ is recommended if you want to process a complete file.
return buf.length;
}
- @system unittest
+ @safe unittest
{
static import std.file;
import std.typecons : Tuple;
@@ -3735,9 +3734,8 @@ void main()
assert(f.tell == 0);
}
-@system unittest
+@safe unittest
{
- // @system due to readln
static import std.file;
import std.range : chain, only, repeat;
import std.range.primitives : isOutputRange;
@@ -5169,13 +5167,13 @@ Initialize with a message and an error code.
}
/** Convenience functions that throw an `StdioException`. */
- static void opCall(string msg)
+ static void opCall(string msg) @safe
{
throw new StdioException(msg);
}
/// ditto
- static void opCall()
+ static void opCall() @safe
{
throw new StdioException(null, core.stdc.errno.errno);
}
@@ -5388,7 +5386,7 @@ private struct ReadlnAppender
size_t pos;
bool safeAppend = false;
- void initialize(char[] b)
+ void initialize(char[] b) @safe
{
buf = b;
pos = 0;
@@ -5445,7 +5443,7 @@ private struct ReadlnAppender
foreach (c; ubuf)
buf.ptr[pos++] = c;
}
- void putonly(char[] b) @trusted
+ void putonly(const char[] b) @trusted
{
import core.stdc.string : memcpy;
assert(pos == 0); // assume this is the only put call
@@ -5457,28 +5455,60 @@ private struct ReadlnAppender
}
}
-// Private implementation of readln
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
+private struct LockedFile
{
- version (DIGITAL_MARS_STDIO)
+ private @system _iobuf* fp;
+
+ this(FILE* fps) @trusted
{
_FLOCK(fps);
- scope(exit) _FUNLOCK(fps);
+ // Since fps is now locked, we can cast away shared
+ fp = cast(_iobuf*) fps;
+ }
+
+ @disable this();
+ @disable this(this);
+ @disable void opAssign(LockedFile);
- /* Since fps is now locked, we can create an "unshared" version
- * of fp.
- */
- auto fp = cast(_iobuf*) fps;
+ // these use unlocked fgetc calls
+ @trusted fgetc() { return _FGETC(fp); }
+ @trusted fgetwc() { return _FGETWC(fp); }
+ ~this() @trusted
+ {
+ _FUNLOCK(cast(FILE*) fp);
+ }
+}
+
+@safe unittest
+{
+ void f() @safe
+ {
+ FILE* fps;
+ auto lf = LockedFile(fps);
+ static assert(!__traits(compiles, lf = LockedFile(fps)));
+ version (ShouldFail)
+ {
+ lf.fps = null; // error with -preview=systemVariables
+ }
+ }
+}
+
+// Private implementation of readln
+private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) @safe
+{
+ version (DIGITAL_MARS_STDIO)
+ return () @trusted {
+ auto lf = LockedFile(fps);
ReadlnAppender app;
app.initialize(buf);
- if (__fhnd_info[fp._file] & FHND_WCHAR)
+ if (__fhnd_info[lf.fp._file] & FHND_WCHAR)
{ /* Stream is in wide characters.
* Read them and convert to chars.
*/
static assert(wchar_t.sizeof == 2);
- for (int c = void; (c = _FGETWC(fp)) != -1; )
+ for (int c = void; (c = lf.fgetwc()) != -1; )
{
if ((c & ~0x7F) == 0)
{
@@ -5491,7 +5521,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
if (c >= 0xD800 && c <= 0xDBFF)
{
int c2 = void;
- if ((c2 = _FGETWC(fp)) != -1 ||
+ if ((c2 = lf.fgetwc()) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
@@ -5504,8 +5534,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
if (ferror(fps))
StdioException();
}
-
- else if (fp._flag & _IONBF)
+ else if (lf.fp._flag & _IONBF)
{
/* Use this for unbuffered I/O, when running
* across buffer boundaries, or for any but the common
@@ -5513,7 +5542,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
*/
L1:
int c;
- while ((c = _FGETC(fp)) != -1)
+ while ((c = lf.fgetc()) != -1)
{
app.putchar(cast(char) c);
if (c == terminator)
@@ -5529,10 +5558,10 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
else
{
- int u = fp._cnt;
- char* p = fp._ptr;
+ int u = lf.fp._cnt;
+ char* p = lf.fp._ptr;
int i;
- if (fp._flag & _IOTRAN)
+ if (lf.fp._flag & _IOTRAN)
{ /* Translated mode ignores \r and treats ^Z as end-of-file
*/
char c;
@@ -5574,28 +5603,22 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
app.putonly(p[0 .. i]);
}
- fp._cnt -= i;
- fp._ptr += i;
+ lf.fp._cnt -= i;
+ lf.fp._ptr += i;
}
buf = app.data;
return buf.length;
- }
+ }();
else version (MICROSOFT_STDIO)
{
- _FLOCK(fps);
- scope(exit) _FUNLOCK(fps);
-
- /* Since fps is now locked, we can create an "unshared" version
- * of fp.
- */
- auto fp = cast(_iobuf*) fps;
+ auto lf = LockedFile(fps);
ReadlnAppender app;
app.initialize(buf);
int c;
- while ((c = _FGETC(fp)) != -1)
+ while ((c = lf.fgetc()) != -1)
{
app.putchar(cast(char) c);
if (c == terminator)
@@ -5613,21 +5636,18 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
else static if (__traits(compiles, core.sys.posix.stdio.getdelim))
{
- import core.stdc.stdlib : free;
- import core.stdc.wchar_ : fwide;
-
if (orientation == File.Orientation.wide)
{
+ import core.stdc.wchar_ : fwide;
+
+ auto lf = LockedFile(fps);
/* Stream is in wide characters.
* Read them and convert to chars.
*/
- _FLOCK(fps);
- scope(exit) _FUNLOCK(fps);
- auto fp = cast(_iobuf*) fps;
version (Windows)
{
buf.length = 0;
- for (int c = void; (c = _FGETWC(fp)) != -1; )
+ for (int c = void; (c = lf.fgetwc()) != -1; )
{
if ((c & ~0x7F) == 0)
{ buf ~= c;
@@ -5639,7 +5659,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
if (c >= 0xD800 && c <= 0xDBFF)
{
int c2 = void;
- if ((c2 = _FGETWC(fp)) != -1 ||
+ if ((c2 = lf.fgetwc()) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
@@ -5650,14 +5670,14 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
encode(buf, c);
}
}
- if (ferror(fp))
+ if (ferror(fps))
StdioException();
return buf.length;
}
else version (Posix)
{
buf.length = 0;
- for (int c; (c = _FGETWC(fp)) != -1; )
+ for (int c; (c = lf.fgetwc()) != -1; )
{
import std.utf : encode;
@@ -5677,47 +5697,49 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
static assert(0);
}
}
+ return () @trusted {
+ import core.stdc.stdlib : free;
- static char *lineptr = null;
- static size_t n = 0;
- scope(exit)
- {
- if (n > 128 * 1024)
+ static char *lineptr = null;
+ static size_t n = 0;
+ scope(exit)
{
- // Bound memory used by readln
- free(lineptr);
- lineptr = null;
- n = 0;
+ if (n > 128 * 1024)
+ {
+ // Bound memory used by readln
+ free(lineptr);
+ lineptr = null;
+ n = 0;
+ }
}
- }
- auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps);
- if (s < 0)
- {
- if (ferror(fps))
- StdioException();
- buf.length = 0; // end of file
- return 0;
- }
+ const s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps);
+ if (s < 0)
+ {
+ if (ferror(fps))
+ StdioException();
+ buf.length = 0; // end of file
+ return 0;
+ }
- if (s <= buf.length)
- {
- buf = buf[0 .. s];
- buf[] = lineptr[0 .. s];
- }
- else
- {
- buf = lineptr[0 .. s].dup;
- }
- return s;
+ const line = lineptr[0 .. s];
+ if (s <= buf.length)
+ {
+ buf = buf[0 .. s];
+ buf[] = line;
+ }
+ else
+ {
+ buf = line.dup;
+ }
+ return s;
+ }();
}
else // version (NO_GETDELIM)
{
import core.stdc.wchar_ : fwide;
- _FLOCK(fps);
- scope(exit) _FUNLOCK(fps);
- auto fp = cast(_iobuf*) fps;
+ auto lf = LockedFile(fps);
if (orientation == File.Orientation.wide)
{
/* Stream is in wide characters.
@@ -5726,7 +5748,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
version (Windows)
{
buf.length = 0;
- for (int c; (c = _FGETWC(fp)) != -1; )
+ for (int c; (c = lf.fgetwc()) != -1; )
{
if ((c & ~0x7F) == 0)
{ buf ~= c;
@@ -5738,7 +5760,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
if (c >= 0xD800 && c <= 0xDBFF)
{
int c2 = void;
- if ((c2 = _FGETWC(fp)) != -1 ||
+ if ((c2 = lf.fgetwc()) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
@@ -5749,7 +5771,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
encode(buf, c);
}
}
- if (ferror(fp))
+ if (ferror(fps))
StdioException();
return buf.length;
}
@@ -5757,7 +5779,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
{
import std.utf : encode;
buf.length = 0;
- for (int c; (c = _FGETWC(fp)) != -1; )
+ for (int c; (c = lf.fgetwc()) != -1; )
{
if ((c & ~0x7F) == 0)
buf ~= cast(char) c;
@@ -5780,7 +5802,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
// First, fill the existing buffer
for (size_t bufPos = 0; bufPos < buf.length; )
{
- immutable c = _FGETC(fp);
+ immutable c = lf.fgetc();
if (c == -1)
{
buf.length = bufPos;
@@ -5795,7 +5817,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
}
// Then, append to it
- for (int c; (c = _FGETC(fp)) != -1; )
+ for (int c; (c = lf.fgetc()) != -1; )
{
buf ~= cast(char) c;
if (c == terminator)
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index ee2d73a..4e76156 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -1952,10 +1952,10 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
// An array that maps caseIds to handler indices ("hids").
enum matches = ()
{
- size_t[numCases] matches;
+ size_t[numCases] result;
// Workaround for https://issues.dlang.org/show_bug.cgi?id=19561
- foreach (ref match; matches)
+ foreach (ref match; result)
{
match = noMatch;
}
@@ -1966,15 +1966,15 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
{
static if (canMatch!(handler, valueTypes!caseId))
{
- if (matches[caseId] == noMatch)
+ if (result[caseId] == noMatch)
{
- matches[caseId] = hid;
+ result[caseId] = hid;
}
}
}
}
- return matches;
+ return result;
}();
import std.algorithm.searching : canFind;
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 1cbff84..e5f305b 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -889,10 +889,10 @@ private template fqnType(T,
);
}
}
- else static if (isPointer!T)
+ else static if (is(T : U*, U))
{
enum fqnType = chain!(
- fqnType!(PointerTarget!T, qualifiers) ~ "*"
+ fqnType!(U, qualifiers) ~ "*"
);
}
else static if (is(T : __vector(V[N]), V, size_t N))
@@ -3925,8 +3925,8 @@ template hasStaticMember(T, string member)
{
static if (__traits(hasMember, T, member))
{
- static if (isPointer!T)
- alias U = PointerTarget!T;
+ static if (is(T : V*, V))
+ alias U = V;
else
alias U = T;
@@ -5446,8 +5446,8 @@ private template isStorageClassImplicitlyConvertible(From, To)
{
alias Pointify(T) = void*;
- enum isStorageClassImplicitlyConvertible = isImplicitlyConvertible!(
- ModifyTypePreservingTQ!(Pointify, From),
+ enum isStorageClassImplicitlyConvertible = is(
+ ModifyTypePreservingTQ!(Pointify, From) :
ModifyTypePreservingTQ!(Pointify, To) );
}
@@ -7138,7 +7138,7 @@ enum bool isSIMDVector(T) = is(T : __vector(V[N]), V, size_t N);
/**
* Detect whether type `T` is a pointer.
*/
-enum bool isPointer(T) = is(T == U*, U) && __traits(isScalar, T);
+enum bool isPointer(T) = is(T == U*, U);
///
@safe unittest
@@ -8847,6 +8847,14 @@ version (StdUnittest)
static assert(__traits(compiles, getSymbolsByUDA!(mixin(__MODULE__), "Issue20054")));
}
+private template isAliasSeq(Args...)
+{
+ static if (Args.length != 1)
+ enum isAliasSeq = true;
+ else
+ enum isAliasSeq = false;
+}
+
private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...)
{
import std.meta : Alias, AliasSeq, Filter;
@@ -8868,12 +8876,12 @@ private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...)
alias member = __traits(getMember, symbol, names[0]);
// Filtering not compiled members such as alias of basic types.
- static if (!__traits(compiles, hasUDA!(member, attribute)))
+ static if (isAliasSeq!member || isType!member)
{
alias getSymbolsByUDAImpl = tail;
}
- // Get overloads for functions, in case different overloads have different sets of UDAs.
- else static if (isFunction!member)
+ // If a symbol is overloaded, get UDAs for each overload (including templated overlaods).
+ else static if (__traits(getOverloads, symbol, names[0], true).length > 0)
{
enum hasSpecificUDA(alias member) = hasUDA!(member, attribute);
alias overloadsWithUDA = Filter!(hasSpecificUDA, __traits(getOverloads, symbol, names[0]));
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 231ac93..e83b6171 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -5536,7 +5536,7 @@ private static:
}
// handle each overload set
- private string generateCodeForOverloadSet(alias oset)() @property
+ string generateCodeForOverloadSet(alias oset)() @property
{
string code = "";
@@ -5666,7 +5666,7 @@ private static:
* "ref int a0, real a1, ..."
*/
static struct GenParams { string imports, params; }
- private GenParams generateParameters(string myFuncInfo, func...)()
+ GenParams generateParameters(string myFuncInfo, func...)()
{
alias STC = ParameterStorageClass;
alias stcs = ParameterStorageClassTuple!(func);
@@ -5716,7 +5716,7 @@ private static:
// Returns D code which enumerates n parameter variables using comma as the
// separator. "a0, a1, a2, a3"
- private string enumerateParameters(size_t n)() @property
+ string enumerateParameters(size_t n)() @property
{
string params = "";
@@ -8782,7 +8782,7 @@ if (alignment > 0 && !((alignment - 1) & alignment))
{
void test(size_t size)
{
- import core.stdc.stdlib;
+ import core.stdc.stdlib : alloca;
cast(void) alloca(size);
alignmentTest();
}
@@ -9253,7 +9253,7 @@ public:
}
Base opCast(B)() const
- if (isImplicitlyConvertible!(Base, B))
+ if (is(Base : B))
{
return mValue;
}
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index 81b949e..c31912a 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -6271,8 +6271,8 @@ struct UnicodeSetParser(Range)
{
if (casefold_)
{
- auto range = simpleCaseFoldings(ch);
- foreach (v; range)
+ auto foldings = simpleCaseFoldings(ch);
+ foreach (v; foldings)
set |= v;
}
else
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index 8d94e12..7a0556d 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -66,7 +66,7 @@ import std.exception : basicExceptionCtors;
import core.exception : UnicodeException;
import std.meta : AliasSeq;
import std.range;
-import std.traits : isAutodecodableString, isConvertibleToString, isPointer,
+import std.traits : isAutodecodableString, isConvertibleToString,
isSomeChar, isSomeString, isStaticArray, Unqual;
import std.typecons : Flag, Yes, No;
@@ -3136,7 +3136,7 @@ private T toUTFImpl(T, S)(scope S s)
collection cycle and cause a nasty bug when the C code tries to use it.
+/
template toUTFz(P)
-if (isPointer!P && isSomeChar!(typeof(*P.init)))
+if (is(P : C*, C) && isSomeChar!C)
{
P toUTFz(S)(S str) @safe pure
if (isSomeString!S)
diff --git a/libphobos/src/std/windows/registry.d b/libphobos/src/std/windows/registry.d
index d66adff..7ee1f7a 100644
--- a/libphobos/src/std/windows/registry.d
+++ b/libphobos/src/std/windows/registry.d
@@ -1856,7 +1856,7 @@ private:
if (i++ > 0)
break;
- import core.memory;
+ import core.memory : GC;
GC.collect();
}
assert(i == 2);