diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-06 23:11:02 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-11 00:51:15 +0100 |
commit | c82395e03592e5858c34f0b824f494eb94b37404 (patch) | |
tree | 8fddc3a6b179866de8e4950888cef1c6b4e834a5 /libphobos | |
parent | a7ae0c31245a7db7abf2e80d0016510afe9c8ad0 (diff) | |
download | gcc-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/MERGE | 2 | ||||
-rw-r--r-- | libphobos/libdruntime/core/builtins.d | 43 | ||||
-rw-r--r-- | libphobos/libdruntime/core/stdc/fenv.d | 8 | ||||
-rw-r--r-- | libphobos/libdruntime/core/sys/posix/signal.d | 5 | ||||
-rw-r--r-- | libphobos/libdruntime/core/sys/windows/winsock2.d | 64 | ||||
-rw-r--r-- | libphobos/libdruntime/core/thread/osthread.d | 158 | ||||
-rw-r--r-- | libphobos/libdruntime/core/thread/threadbase.d | 103 | ||||
-rw-r--r-- | libphobos/src/MERGE | 2 | ||||
-rw-r--r-- | libphobos/src/std/algorithm/sorting.d | 20 | ||||
-rw-r--r-- | libphobos/src/std/format/package.d | 12 | ||||
-rw-r--r-- | libphobos/src/std/format/write.d | 2 | ||||
-rw-r--r-- | libphobos/src/std/uni/package.d | 6 |
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); |