aboutsummaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2025-01-06 23:11:02 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2025-01-11 00:51:15 +0100
commitc82395e03592e5858c34f0b824f494eb94b37404 (patch)
tree8fddc3a6b179866de8e4950888cef1c6b4e834a5 /libphobos
parenta7ae0c31245a7db7abf2e80d0016510afe9c8ad0 (diff)
downloadgcc-c82395e03592e5858c34f0b824f494eb94b37404.zip
gcc-c82395e03592e5858c34f0b824f494eb94b37404.tar.gz
gcc-c82395e03592e5858c34f0b824f494eb94b37404.tar.bz2
d: Merge dmd, druntime 4ccb01fde5, phobos eab6595ad
D front-end changes: - Added pragma for ImportC to allow setting `nothrow', `@nogc' or `pure'. - Mixin templates can now use assignment syntax. D runtime changes: - Removed `ThreadBase.criticalRegionLock' from `core.thread'. - Added `expect', `[un]likely', `trap' to `core.builtins'. Phobos changes: - Import latest fixes from phobos v2.110.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 4ccb01fde5. * Make-lang.in (D_FRONTEND_OBJS): Rename d/foreachvar.o to d/visitor-foreachvar.o, d/visitor.o to d/visitor-package.o, and d/statement_rewrite_walker.o to d/visitor-statement_rewrite_walker.o. (D_FRONTEND_OBJS): Rename d/{parsetime,permissive,postorder,transitive}visitor.o to d/visitor-{parsetime,permissive,postorder,transitive}.o. (D_FRONTEND_OBJS): Remove d/sapply.o. (d.tags): Add dmd/common/*.h. (d/visitor-%.o:): New rule. * d-codegen.cc (get_frameinfo): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 4ccb01fde5. * src/MERGE: Merge upstream phobos eab6595ad.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/core/builtins.d43
-rw-r--r--libphobos/libdruntime/core/stdc/fenv.d8
-rw-r--r--libphobos/libdruntime/core/sys/posix/signal.d5
-rw-r--r--libphobos/libdruntime/core/sys/windows/winsock2.d64
-rw-r--r--libphobos/libdruntime/core/thread/osthread.d158
-rw-r--r--libphobos/libdruntime/core/thread/threadbase.d103
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/algorithm/sorting.d20
-rw-r--r--libphobos/src/std/format/package.d12
-rw-r--r--libphobos/src/std/format/write.d2
-rw-r--r--libphobos/src/std/uni/package.d6
12 files changed, 196 insertions, 229 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 654fbed..acb7d98 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-6884b433d21d9b6356e5c83ffc6eb06a62a5cad1
+4ccb01fde535c7ad6ad4bdae2516c99420751814
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/builtins.d b/libphobos/libdruntime/core/builtins.d
index 1ed80f7..f10bb9f 100644
--- a/libphobos/libdruntime/core/builtins.d
+++ b/libphobos/libdruntime/core/builtins.d
@@ -51,3 +51,46 @@ version (LDC)
/// Writes `s` to `stderr` during CTFE (does nothing at runtime).
void __ctfeWrite(scope const(char)[] s) @nogc @safe pure nothrow {}
+
+version (GNU)
+{
+ /// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fexpect
+ alias expect = __builtin_expect;
+ /// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005ftrap
+ alias trap = __builtin_trap;
+}
+else version (LDC)
+{
+ /// https://llvm.org/docs/LangRef.html#llvm-expect-intrinsic
+ alias expect = llvm_expect;
+ debug
+ /// https://llvm.org/docs/LangRef.html#llvm-debugtrap-intrinsic
+ alias trap = llvm_debugtrap;
+ else
+ /// https://llvm.org/docs/LangRef.html#llvm-trap-intrinsic
+ alias trap = llvm_trap;
+}
+else version (DigitalMars)
+{
+ pragma(inline, true)
+ T expect(T)(T val, T expected) if (__traits(isIntegral, T))
+ {
+ return val;
+ }
+
+ pragma(inline, true)
+ void trap()
+ {
+ debug
+ {
+ version(D_InlineAsm_X86)
+ asm nothrow @nogc pure @trusted { int 3; }
+ }
+ assert(0);
+ }
+}
+
+/// Provide static branch hints
+pragma(inline, true) bool likely(bool b) { return !!expect(b, true); }
+///
+pragma(inline, true) bool unlikely(bool b) { return !!expect(b, false); }
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index b9b10aa..ce77d5c 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -432,6 +432,14 @@ else version (CRuntime_Musl)
}
alias ushort fexcept_t;
}
+ else version (LoongArch64)
+ {
+ struct fenv_t
+ {
+ uint __cw;
+ }
+ alias uint fexcept_t;
+ }
else
{
static assert(false, "Architecture not supported.");
diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d
index ed4ec12..e3d80fb 100644
--- a/libphobos/libdruntime/core/sys/posix/signal.d
+++ b/libphobos/libdruntime/core/sys/posix/signal.d
@@ -2758,6 +2758,11 @@ else version (CRuntime_Musl)
enum MINSIGSTKSZ = 2048;
enum SIGSTKSZ = 8192;
}
+ else version (LoongArch64)
+ {
+ enum MINSIGSTKSZ = 4096;
+ enum SIGSTKSZ = 16384;
+ }
else
static assert(0, "unimplemented");
diff --git a/libphobos/libdruntime/core/sys/windows/winsock2.d b/libphobos/libdruntime/core/sys/windows/winsock2.d
index b036df3..626f79e 100644
--- a/libphobos/libdruntime/core/sys/windows/winsock2.d
+++ b/libphobos/libdruntime/core/sys/windows/winsock2.d
@@ -405,7 +405,7 @@ const(SOCKET)* stop = start + set.fd_count;
// Adds.
-void FD_SET(SOCKET fd, fd_set* set) pure @nogc
+void FD_SET(SOCKET fd, fd_set* set) pure @nogc
{
uint c = set.fd_count;
set.fd_array.ptr[c] = fd;
@@ -547,13 +547,29 @@ enum: uint
enum: int
{
- AI_PASSIVE = 0x1,
- AI_CANONNAME = 0x2,
- AI_NUMERICHOST = 0x4,
- AI_ADDRCONFIG = 0x0400,
- AI_NON_AUTHORITATIVE = 0x04000,
- AI_SECURE = 0x08000,
- AI_RETURN_PREFERRED_NAMES = 0x010000,
+ AI_PASSIVE = 0x1, // Socket address will be used in bind() call
+ AI_CANONNAME = 0x2, // Return canonical name in first ai_canonname
+ AI_NUMERICHOST = 0x4, // Nodename must be a numeric address string
+ AI_NUMERICSERV = 0x8, // Servicename must be a numeric port number
+ AI_DNS_ONLY = 0x10, // Restrict queries to unicast DNS only (no LLMNR, netbios, etc.)
+ AI_FORCE_CLEAR_TEXT = 0x20, // Force clear text DNS query
+ AI_BYPASS_DNS_CACHE = 0x40, // Bypass DNS cache
+ AI_RETURN_TTL = 0x80, // Return record TTL
+ AI_ALL = 0x0100, // Query both IP6 and IP4 with AI_V4MAPPED
+ AI_ADDRCONFIG = 0x0400, // Resolution only if global address configured
+ AI_V4MAPPED = 0x0800, // On v6 failure, query v4 and convert to V4MAPPED format
+ AI_NON_AUTHORITATIVE = 0x04000, // LUP_NON_AUTHORITATIVE
+ AI_SECURE = 0x08000, // LUP_SECURE
+ AI_RETURN_PREFERRED_NAMES = 0x010000, // LUP_RETURN_PREFERRED_NAMES
+ AI_FQDN = 0x00020000, // Return the FQDN in ai_canonname
+ AI_FILESERVER = 0x00040000, // Resolving fileserver name resolution
+ AI_DISABLE_IDN_ENCODING = 0x00080000, // Disable Internationalized Domain Names handling
+ AI_SECURE_WITH_FALLBACK = 0x00100000, // Forces clear text fallback if the secure DNS query fails
+ AI_EXCLUSIVE_CUSTOM_SERVERS = 0x00200000, // Use exclusively the custom DNS servers
+ AI_RETURN_RESPONSE_FLAGS = 0x10000000, // Requests extra information about the DNS results
+ AI_REQUIRE_SECURE = 0x20000000, // Forces the DNS query to be done over seucre protocols
+ AI_RESOLUTION_HANDLE = 0x40000000, // Request resolution handle
+ AI_EXTENDED = 0x80000000, // Indicates this is extended ADDRINFOEX(2/..) struct
}
@@ -702,12 +718,12 @@ struct hostent
// Note: These are Winsock2!!
struct WSAOVERLAPPED;
alias LPWSAOVERLAPPED = WSAOVERLAPPED*;
-alias LPWSAOVERLAPPED_COMPLETION_ROUTINE = void function(uint, uint, LPWSAOVERLAPPED, uint);
+alias LPWSAOVERLAPPED_COMPLETION_ROUTINE = void function(uint, uint, LPWSAOVERLAPPED, uint) nothrow @nogc;
int WSAIoctl(SOCKET s, uint dwIoControlCode,
void* lpvInBuffer, uint cbInBuffer,
void* lpvOutBuffer, uint cbOutBuffer,
uint* lpcbBytesReturned,
- LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) @nogc;
enum IOC_VENDOR = 0x18000000;
@@ -720,3 +736,31 @@ struct tcp_keepalive
uint keepalivetime;
uint keepaliveinterval;
}
+
+
+struct pollfd
+{
+ SOCKET fd; // Socket handle
+ short events; // Requested events to monitor
+ short revents; // Returned events indicating status
+}
+alias WSAPOLLFD = pollfd;
+alias PWSAPOLLFD = pollfd*;
+alias LPWSAPOLLFD = pollfd*;
+
+enum: short {
+ POLLRDNORM = 0x0100,
+ POLLRDBAND = 0x0200,
+ POLLIN = (POLLRDNORM | POLLRDBAND),
+ POLLPRI = 0x0400,
+
+ POLLWRNORM = 0x0010,
+ POLLOUT = (POLLWRNORM),
+ POLLWRBAND = 0x0020,
+
+ POLLERR = 0x0001,
+ POLLHUP = 0x0002,
+ POLLNVAL = 0x0004
+}
+
+int WSAPoll(LPWSAPOLLFD fdArray, uint fds, int timeout) @nogc;
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 3070481..cf93094 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -1154,52 +1154,6 @@ unittest
t.join();
}
-unittest
-{
- // NOTE: This entire test is based on the assumption that no
- // memory is allocated after the child thread is
- // started. If an allocation happens, a collection could
- // trigger, which would cause the synchronization below
- // to cause a deadlock.
- // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE.
-
- import core.sync.semaphore;
-
- auto sema = new Semaphore(),
- semb = new Semaphore();
-
- auto thr = new Thread(
- {
- thread_enterCriticalRegion();
- assert(thread_inCriticalRegion());
- sema.notify();
-
- semb.wait();
- assert(thread_inCriticalRegion());
-
- thread_exitCriticalRegion();
- assert(!thread_inCriticalRegion());
- sema.notify();
-
- semb.wait();
- assert(!thread_inCriticalRegion());
- });
-
- thr.start();
-
- sema.wait();
- synchronized (ThreadBase.criticalRegionLock)
- assert(thr.m_isInCriticalRegion);
- semb.notify();
-
- sema.wait();
- synchronized (ThreadBase.criticalRegionLock)
- assert(!thr.m_isInCriticalRegion);
- semb.notify();
-
- thr.join();
-}
-
// https://issues.dlang.org/show_bug.cgi?id=22124
unittest
{
@@ -1212,36 +1166,6 @@ unittest
static assert(!__traits(compiles, () @nogc => fun(thread, 3) ));
}
-unittest
-{
- import core.sync.semaphore;
-
- shared bool inCriticalRegion;
- auto sema = new Semaphore(),
- semb = new Semaphore();
-
- auto thr = new Thread(
- {
- thread_enterCriticalRegion();
- inCriticalRegion = true;
- sema.notify();
- semb.wait();
-
- Thread.sleep(dur!"msecs"(1));
- inCriticalRegion = false;
- thread_exitCriticalRegion();
- });
- thr.start();
-
- sema.wait();
- assert(inCriticalRegion);
- semb.notify();
-
- thread_suspendAll();
- assert(!inCriticalRegion);
- thread_resumeAll();
-}
-
@nogc @safe nothrow
unittest
{
@@ -1740,21 +1664,11 @@ private extern(D) void* getStackBottom() nothrow @nogc
*/
private extern (D) bool suspend( Thread t ) nothrow @nogc
{
- Duration waittime = dur!"usecs"(10);
- Lagain:
if (!t.isRunning)
{
Thread.remove(t);
return false;
}
- else if (t.m_isInCriticalRegion)
- {
- Thread.criticalRegionLock.unlock_nothrow();
- Thread.sleep(waittime);
- if (waittime < dur!"msecs"(10)) waittime *= 2;
- Thread.criticalRegionLock.lock_nothrow();
- goto Lagain;
- }
version (Windows)
{
@@ -1963,6 +1877,13 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc
}
/**
+ * Runs the necessary operations required before stopping the world.
+ */
+extern (C) void thread_preStopTheWorld() nothrow {
+ Thread.slock.lock_nothrow();
+}
+
+/**
* Suspend all threads but the calling thread for "stop the world" garbage
* collection runs. This function may be called multiple times, and must
* be followed by a matching number of calls to thread_resumeAll before
@@ -1994,13 +1915,11 @@ extern (C) void thread_suspendAll() nothrow
return;
}
- Thread.slock.lock_nothrow();
+ thread_preStopTheWorld();
{
if ( ++suspendDepth > 1 )
return;
- Thread.criticalRegionLock.lock_nothrow();
- scope (exit) Thread.criticalRegionLock.unlock_nothrow();
size_t cnt;
bool suspendedSelf;
Thread t = ThreadBase.sm_tbeg.toThread;
@@ -2466,6 +2385,39 @@ else version (Posix)
__gshared sem_t suspendCount;
+ extern (C) bool thread_preSuspend( void* sp ) nothrow {
+ // NOTE: Since registers are being pushed and popped from the
+ // stack, any other stack data used by this function should
+ // be gone before the stack cleanup code is called below.
+ Thread obj = Thread.getThis();
+ if (obj is null)
+ {
+ return false;
+ }
+
+ if ( !obj.m_lock )
+ {
+ obj.m_curr.tstack = sp;
+ }
+
+ return true;
+ }
+
+ extern (C) bool thread_postSuspend() nothrow {
+ Thread obj = Thread.getThis();
+ if (obj is null)
+ {
+ return false;
+ }
+
+ if ( !obj.m_lock )
+ {
+ obj.m_curr.tstack = obj.m_curr.bstack;
+ }
+
+ return true;
+ }
+
extern (C) void thread_suspendHandler( int sig ) nothrow
in
{
@@ -2475,15 +2427,13 @@ else version (Posix)
{
void op(void* sp) nothrow
{
- // NOTE: Since registers are being pushed and popped from the
- // stack, any other stack data used by this function should
- // be gone before the stack cleanup code is called below.
- Thread obj = Thread.getThis();
- assert(obj !is null);
+ bool supported = thread_preSuspend(getStackTop());
+ assert(supported, "Tried to suspend a detached thread!");
- if ( !obj.m_lock )
+ scope(exit)
{
- obj.m_curr.tstack = getStackTop();
+ supported = thread_postSuspend();
+ assert(supported, "Tried to suspend a detached thread!");
}
sigset_t sigres = void;
@@ -2499,11 +2449,6 @@ else version (Posix)
assert( status == 0 );
sigsuspend( &sigres );
-
- if ( !obj.m_lock )
- {
- obj.m_curr.tstack = obj.m_curr.bstack;
- }
}
callWithStackShell(&op);
}
@@ -2641,11 +2586,7 @@ private
bool ll_dllHasExternalReferences() nothrow
{
- version (CRuntime_DigitalMars)
- enum internalReferences = 1; // only the watchdog thread
- else
- int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1;
-
+ int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1;
int refcnt = dll_getRefCount(ll_dllModule);
return refcnt > internalReferences;
}
@@ -2706,10 +2647,7 @@ private
// if a thread is created from a DLL, the MS runtime (starting with VC2015) increments the DLL reference count
// to avoid the DLL being unloaded while the thread is still running. Mimick this behavior here for all
// runtimes not doing this
- version (CRuntime_DigitalMars)
- enum needRef = true;
- else
- bool needRef = !msvcUsesUCRT;
+ bool needRef = !msvcUsesUCRT;
if (needRef)
{
diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d
index 58dd259..cb13e9a 100644
--- a/libphobos/libdruntime/core/thread/threadbase.d
+++ b/libphobos/libdruntime/core/thread/threadbase.d
@@ -456,7 +456,6 @@ package:
string m_name;
size_t m_sz;
bool m_isDaemon;
- bool m_isInCriticalRegion;
Throwable m_unhandled;
///////////////////////////////////////////////////////////////////////////
@@ -564,25 +563,17 @@ package(core.thread):
return cast(Mutex)_slock.ptr;
}
- @property static Mutex criticalRegionLock() nothrow @nogc
- {
- return cast(Mutex)_criticalRegionLock.ptr;
- }
-
__gshared align(mutexAlign) void[mutexClassInstanceSize] _slock;
- __gshared align(mutexAlign) void[mutexClassInstanceSize] _criticalRegionLock;
static void initLocks() @nogc nothrow
{
import core.lifetime : emplace;
emplace!Mutex(_slock[]);
- emplace!Mutex(_criticalRegionLock[]);
}
static void termLocks() @nogc nothrow
{
(cast(Mutex)_slock.ptr).__dtor();
- (cast(Mutex)_criticalRegionLock.ptr).__dtor();
}
__gshared StackContext* sm_cbeg;
@@ -979,6 +970,13 @@ package __gshared uint suspendDepth = 0;
private alias resume = externDFunc!("core.thread.osthread.resume", void function(ThreadBase) nothrow @nogc);
/**
+ * Run the necessary operation required after the world was resumed.
+ */
+extern (C) void thread_postRestartTheWorld() nothrow {
+ ThreadBase.slock.unlock_nothrow();
+}
+
+/**
* Resume all threads but the calling thread for "stop the world" garbage
* collection runs. This function must be called once for each preceding
* call to thread_suspendAll before the threads are actually resumed.
@@ -1004,7 +1002,7 @@ do
return;
}
- scope(exit) ThreadBase.slock.unlock_nothrow();
+ scope(exit) thread_postRestartTheWorld();
{
if (--suspendDepth > 0)
return;
@@ -1144,75 +1142,6 @@ extern (C) void thread_scanAll(scope ScanAllThreadsFn scan) nothrow
private alias thread_yield = externDFunc!("core.thread.osthread.thread_yield", void function() @nogc nothrow);
-/**
- * Signals that the code following this call is a critical region. Any code in
- * this region must finish running before the calling thread can be suspended
- * by a call to thread_suspendAll.
- *
- * This function is, in particular, meant to help maintain garbage collector
- * invariants when a lock is not used.
- *
- * A critical region is exited with thread_exitCriticalRegion.
- *
- * $(RED Warning):
- * Using critical regions is extremely error-prone. For instance, using locks
- * inside a critical region can easily result in a deadlock when another thread
- * holding the lock already got suspended.
- *
- * The term and concept of a 'critical region' comes from
- * $(LINK2 https://github.com/mono/mono/blob/521f4a198e442573c400835ef19bbb36b60b0ebb/mono/metadata/sgen-gc.h#L925, Mono's SGen garbage collector).
- *
- * In:
- * The calling thread must be attached to the runtime.
- */
-extern (C) void thread_enterCriticalRegion() @nogc
-in
-{
- assert(ThreadBase.getThis());
-}
-do
-{
- synchronized (ThreadBase.criticalRegionLock)
- ThreadBase.getThis().m_isInCriticalRegion = true;
-}
-
-
-/**
- * Signals that the calling thread is no longer in a critical region. Following
- * a call to this function, the thread can once again be suspended.
- *
- * In:
- * The calling thread must be attached to the runtime.
- */
-extern (C) void thread_exitCriticalRegion() @nogc
-in
-{
- assert(ThreadBase.getThis());
-}
-do
-{
- synchronized (ThreadBase.criticalRegionLock)
- ThreadBase.getThis().m_isInCriticalRegion = false;
-}
-
-
-/**
- * Returns true if the current thread is in a critical region; otherwise, false.
- *
- * In:
- * The calling thread must be attached to the runtime.
- */
-extern (C) bool thread_inCriticalRegion() @nogc
-in
-{
- assert(ThreadBase.getThis());
-}
-do
-{
- synchronized (ThreadBase.criticalRegionLock)
- return ThreadBase.getThis().m_isInCriticalRegion;
-}
-
/**
* A callback for thread errors in D during collections. Since an allocation is not possible
@@ -1233,22 +1162,6 @@ package void onThreadError(string msg) nothrow @nogc
throw error;
}
-unittest
-{
- assert(!thread_inCriticalRegion());
-
- {
- thread_enterCriticalRegion();
-
- scope (exit)
- thread_exitCriticalRegion();
-
- assert(thread_inCriticalRegion());
- }
-
- assert(!thread_inCriticalRegion());
-}
-
/**
* Indicates whether an address has been marked by the GC.
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 4fac724..8daeda5 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-48d581a1f509a7a302ea893e28939edb5b130622
+eab6595ade1dab9a757bc0efe2f4e92f39cab0f7
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/sorting.d b/libphobos/src/std/algorithm/sorting.d
index 2d16c65..cb47153 100644
--- a/libphobos/src/std/algorithm/sorting.d
+++ b/libphobos/src/std/algorithm/sorting.d
@@ -2385,7 +2385,11 @@ private template TimSortImpl(alias pred, R)
size_t stackLen = 0;
// Allocate temporary memory if not provided by user
- if (temp.length < minTemp) temp = () @trusted { return uninitializedArray!(T[])(minTemp); }();
+ if (temp.length < minTemp)
+ {
+ static if (hasElaborateAssign!T) temp = new T[](minTemp);
+ else temp = () @trusted { return uninitializedArray!(T[])(minTemp); }();
+ }
for (size_t i = 0; i < range.length; )
{
@@ -3076,6 +3080,20 @@ private template TimSortImpl(alias pred, R)
array.sort!("a < b", SwapStrategy.stable);
}
+// https://issues.dlang.org/show_bug.cgi?id=24773
+@safe unittest
+{
+ static struct S
+ {
+ int i = 42;
+ ~this() { assert(i == 42); }
+ }
+
+ auto array = new S[](400);
+ array.sort!((a, b) => false, SwapStrategy.stable);
+}
+
+
// schwartzSort
/**
Alternative sorting method that should be used when comparing keys involves an
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index a78e1b3..e02c120 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -60,7 +60,7 @@ Limitation: This package does not support localization, but
adheres to the rounding mode of the floating point unit, if
available.
-$(SECTION3 Format Strings)
+$(H3 $(LNAME2 format-strings, Format Strings))
The functions contained in this package use $(I format strings). A
format string describes the layout of another string for reading or
@@ -144,7 +144,7 @@ recommended to assign (lower- and uppercase) letters.
Note: The $(I Parameters) of a $(I CompoundIndicator) are currently
limited to a $(B '-') flag.
-$(SECTION4 Format Indicator)
+$(H4 $(LNAME2 format-indicator, Format Indicator))
The $(I format indicator) can either be a single character or an
expression surrounded by $(B %\() and $(B %\)). It specifies the
@@ -205,7 +205,7 @@ Note: Inside a $(I compound indicator), strings and characters are
escaped automatically. To avoid this behavior, use `"%-$(LPAREN)"`
instead of `"%$(LPAREN)"`.
-$(SECTION4 Flags)
+$(H4 $(LNAME2 flags, Flags))
There are several flags that affect the outcome of the formatting.
@@ -244,7 +244,7 @@ $(BOOKTABLE ,
sections below for more information.))
)
-$(SECTION4 Width$(COMMA) Precision and Separator)
+$(H4 $(LNAME2 width-precision-separator, Width, Precision and Separator))
The $(I width) parameter specifies the minimum width of the result.
@@ -269,7 +269,7 @@ The $(I separator) can also be followed by a $(B '?'). In that case,
an additional argument is used to specify the symbol that should be
used to separate the chunks.
-$(SECTION4 Position)
+$(H4 $(LNAME2 position, Position))
By default, the arguments are processed in the provided order. With
the $(I position) parameter it is possible to address arguments
@@ -282,7 +282,7 @@ It's also possible to use positional arguments for $(I width), $(I
precision) and $(I separator) by adding a number and a $(B
'$(DOLLAR)') after the $(B '*').
-$(SECTION4 Types)
+$(H4 $(LNAME2 types, Types))
This section describes the result of combining types with format
characters. It is organized in 2 subsections: a list of general
diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d
index 2aa45d7..078fa78 100644
--- a/libphobos/src/std/format/write.d
+++ b/libphobos/src/std/format/write.d
@@ -28,7 +28,7 @@ $(TR $(TD $(I delegates)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH))
Enums can be used with all format characters of the base type.
-$(SECTION3 Structs$(COMMA) Unions$(COMMA) Classes$(COMMA) and Interfaces)
+$(H3 $(LNAME2 aggregates, Structs, Unions, Classes, and Interfaces))
Aggregate types can define various `toString` functions. If this
function takes a $(REF_ALTTEXT FormatSpec, FormatSpec, std, format,
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index b6d31a8..f7610c0 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -7005,7 +7005,7 @@ private enum TransformRes
// Note, getting GB1 (break at start of text, unless text is empty) right
// relies on the user starting grapheme walking from beginning of the text, and
// not attempting to walk an empty text.
-private enum TransformRes
+private immutable TransformRes
function(ref GraphemeState, dchar) @safe pure nothrow @nogc [] graphemeTransforms =
[
GraphemeState.Start: (ref state, ch)
@@ -7243,9 +7243,7 @@ if (is(C : dchar))
static assert(c2 == 3); // \u0301 has 2 UTF-8 code units
}
-// TODO: make this @nogc. Probably no big deal since the state machine is
-// already GC-free.
-@safe pure nothrow unittest
+@safe pure nothrow @nogc unittest
{
// grinning face ~ emoji modifier fitzpatrick type-5 ~ grinning face
assert(graphemeStride("\U0001F600\U0001f3FE\U0001F600"d, 0) == 2);