From f99303eb4aafef70075951731b3ad99266fe6225 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 29 Jan 2023 21:06:59 +0100 Subject: d: Merge upstream dmd, druntime 09faa4eacd, phobos 13ef27a56. D front-end changes: - Import dmd v2.102.0-beta.1 - `static assert' now supports multiple message arguments. D runtime changes: - Import druntime v2.102.0-beta.1 - The default `Throwable.TraceInfo' generation now is `@nogc'. - `Object.factory' method has now been deprecated. Phobos changes: - Import phobos v2.102.0-beta.1 - Added float- and double-precision implementations for log function families in std.math. - `std.typecons.Unique' now calls `destroy` on struct types gcc/d/ChangeLog: * Make-lang.in (D_FRONTEND_OBJS): Add d/location.o. * d-lang.cc (d_init_options): Update for new front-end interface. (d_post_options): Call Loc::set after handling options. * dmd/MERGE: Merge upstream dmd 09faa4eacd. * dmd/VERSION: Bump version to v2.102.0-beta.1. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 09faa4eacd. * src/MERGE: Merge upstream phobos 13ef27a56. * testsuite/libphobos.exceptions/refcounted.d: Add test for chained reference counted exceptions. * testsuite/libphobos.shared/finalize.d: Add dg-warning for deprecated factory interfaces. * testsuite/libphobos.gc/issue22843.d: New test. gcc/testsuite/ChangeLog: * gdc.dg/simd2a.d: Update. * gdc.dg/simd2b.d: Update. * gdc.dg/simd2c.d: Update. * gdc.dg/simd2d.d: Update. * gdc.dg/simd2e.d: Update. * gdc.dg/simd2f.d: Update. * gdc.dg/simd2g.d: Update. * gdc.dg/simd2h.d: Update. * gdc.dg/simd2i.d: Update. * gdc.dg/simd2j.d: Update. --- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/demangle.d | 6 +- libphobos/libdruntime/core/exception.d | 2 - .../core/internal/gc/impl/conservative/gc.d | 14 +- .../libdruntime/core/internal/gc/impl/manual/gc.d | 7 +- libphobos/libdruntime/core/runtime.d | 89 ++++- libphobos/libdruntime/core/stdc/config.d | 16 + .../libdruntime/core/sys/darwin/mach/getsect.d | 2 +- libphobos/libdruntime/core/sys/posix/sys/wait.d | 12 +- libphobos/libdruntime/core/sys/windows/dbghelp.d | 4 +- .../libdruntime/core/sys/windows/stacktrace.d | 60 ++-- libphobos/libdruntime/core/thread/osthread.d | 12 +- libphobos/libdruntime/core/time.d | 2 +- libphobos/libdruntime/object.d | 19 +- libphobos/libdruntime/rt/deh.d | 2 + libphobos/libdruntime/rt/dmain2.d | 10 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/iteration.d | 5 +- libphobos/src/std/conv.d | 6 +- libphobos/src/std/math/exponential.d | 399 +++++++++++++++++---- libphobos/src/std/math/operations.d | 2 +- libphobos/src/std/numeric.d | 2 +- libphobos/src/std/parallelism.d | 13 +- libphobos/src/std/random.d | 14 +- libphobos/src/std/regex/package.d | 2 +- libphobos/src/std/typecons.d | 26 +- .../testsuite/libphobos.exceptions/refcounted.d | 34 +- libphobos/testsuite/libphobos.gc/issue22843.d | 12 + libphobos/testsuite/libphobos.shared/finalize.d | 4 +- 29 files changed, 620 insertions(+), 160 deletions(-) create mode 100644 libphobos/testsuite/libphobos.gc/issue22843.d (limited to 'libphobos') diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 5ee6f62..ac3dd12 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -c8ae4adb2eda515b09b326948e3a4aa9f489af45 +09faa4eacd4fb147107e94eeebf56b3a73fdcc05 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 869ade6..fe27331 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -2134,7 +2134,7 @@ 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") + if (__cxa_demangle && 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 @@ -2734,6 +2734,9 @@ unittest s ~= "FiZi"; expected ~= "F"; assert(s.demangle == expected); + + // https://issues.dlang.org/show_bug.cgi?id=23562 + assert(demangle("_Zv") == "_Zv"); } // https://issues.dlang.org/show_bug.cgi?id=22235 @@ -2929,6 +2932,7 @@ CXX_DEMANGLER getCXXDemangler() nothrow @trusted 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 (OpenBSD) import core.sys.openbsd.dlfcn : RTLD_DEFAULT; version (OSX) import core.sys.darwin.dlfcn : RTLD_DEFAULT; version (Solaris) import core.sys.solaris.dlfcn : RTLD_DEFAULT; diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d index 62179fe..d2016b1 100644 --- a/libphobos/libdruntime/core/exception.d +++ b/libphobos/libdruntime/core/exception.d @@ -278,7 +278,6 @@ class FinalizeError : Error this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { super( "Finalization error", file, line, next ); - super.info = SuppressTraceInfo.instance; info = ci; } @@ -393,7 +392,6 @@ class InvalidMemoryOperationError : Error this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { super( "Invalid memory operation", file, line, next ); - this.info = SuppressTraceInfo.instance; } override string toString() const @trusted diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d index e29e426..6d19247 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d @@ -110,13 +110,23 @@ alias GC gc_t; /* ============================ GC =============================== */ // register GC in C constructor (_STI_) -extern(C) pragma(crt_constructor) void _d_register_conservative_gc() +private pragma(crt_constructor) void gc_conservative_ctor() +{ + _d_register_conservative_gc(); +} + +extern(C) void _d_register_conservative_gc() { import core.gc.registry; registerGCFactory("conservative", &initialize); } -extern(C) pragma(crt_constructor) void _d_register_precise_gc() +private pragma(crt_constructor) void gc_precise_ctor() +{ + _d_register_precise_gc(); +} + +extern(C) void _d_register_precise_gc() { import core.gc.registry; registerGCFactory("precise", &initialize_precise); diff --git a/libphobos/libdruntime/core/internal/gc/impl/manual/gc.d b/libphobos/libdruntime/core/internal/gc/impl/manual/gc.d index a65c636..570781e 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/manual/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/manual/gc.d @@ -29,7 +29,12 @@ static import core.memory; extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */ // register GC in C constructor (_STI_) -extern(C) pragma(crt_constructor) void _d_register_manual_gc() +private pragma(crt_constructor) void gc_manual_ctor() +{ + _d_register_manual_gc(); +} + +extern(C) void _d_register_manual_gc() { import core.gc.registry; registerGCFactory("manual", &initialize); diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index 799e525..19bb61b 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -112,7 +112,7 @@ private alias void delegate( Throwable ) ExceptionHandler; extern (C) void _d_print_throwable(Throwable t); - extern (C) void* thread_stackBottom(); + extern (C) void* thread_stackBottom() nothrow @nogc; } @@ -122,7 +122,7 @@ shared static this() // still possible the app could exit without a stack trace. If // this becomes an issue, the handler could be set in C main // before the module ctors are run. - Runtime.traceHandler = &defaultTraceHandler; + Runtime.traceHandler(&defaultTraceHandler, &defaultTraceDeallocator); } @@ -284,10 +284,18 @@ struct Runtime * If the supplied pointer is null then the trace routine should determine * an appropriate calling context from which to begin the trace. * + * If the deallocator is set, then it is called with the traceinfo when the + * exception is finalized. The deallocator is only set in the exception if + * the default handler is used to generate the trace info. + * * Params: * h = The new trace handler. Set to null to disable exception backtracing. + * d = The new trace deallocator. If non-null, this will be called on + * exception destruction with the trace info, only when the trace + * handler is used to generate TraceInfo. */ - extern(C) pragma(mangle, "rt_setTraceHandler") static @property void traceHandler(TraceHandler h); + extern(C) pragma(mangle, "rt_setTraceHandler") static @property void traceHandler(TraceHandler h, + Throwable.TraceDeallocator d = null); /** * Gets the current trace handler. @@ -298,6 +306,14 @@ struct Runtime extern(C) pragma(mangle, "rt_getTraceHandler") static @property TraceHandler traceHandler(); /** + * Gets the current trace deallocator. + * + * Returns: + * The current trace deallocator or null if none has been set. + */ + extern(C) pragma(mangle, "rt_getTraceDeallocator") static @property Throwable.TraceDeallocator traceDeallocator(); + + /** * Overrides the default collect hander with a user-supplied version. This * routine will be called for each resource object that is finalized in a * non-deterministic manner--typically during a garbage collection cycle. @@ -705,6 +721,10 @@ extern (C) UnitTestResult runModuleUnitTests() * This functions returns a trace handler, allowing to inspect the * current stack trace. * + * IMPORTANT NOTE! the returned trace is potentially not GC allocated, and so + * you must call `defaultTraceDeallocator` when you are finished with the + * `TraceInfo` + * * Params: * ptr = (Windows only) The context to get the stack trace from. * When `null` (the default), start from the current frame. @@ -714,14 +734,24 @@ extern (C) UnitTestResult runModuleUnitTests() * or `null`. If called from a finalizer (destructor), always returns `null` * as trace handlers allocate. */ -Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) +Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) // @nogc { + // NOTE: with traces now being allocated using C malloc, no need to worry + // about GC reentrancy. This code left commented out for reference. + // // avoid recursive GC calls in finalizer, trace handlers should be made @nogc instead - import core.memory : GC; + /*import core.memory : GC; if (GC.inFinalizer) - return null; + return null;*/ - static if (__traits(compiles, new LibBacktrace(0))) + static T allocate(T, Args...)(auto ref Args args) @nogc + { + import core.lifetime : emplace; + import core.stdc.stdlib : malloc; + auto result = cast(T)malloc(__traits(classInstanceSize, T)); + return emplace(result, args); + } + static if (__traits(compiles, allocate!LibBacktrace(0))) { version (Posix) static enum FIRSTFRAME = 4; @@ -729,9 +759,9 @@ Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) static enum FIRSTFRAME = 4; else static enum FIRSTFRAME = 0; - return new LibBacktrace(FIRSTFRAME); + return allocate!LibBacktrace(FIRSTFRAME); } - else static if (__traits(compiles, new UnwindBacktrace(0))) + else static if (__traits(compiles, allocate!UnwindBacktrace(0))) { version (Posix) static enum FIRSTFRAME = 5; @@ -739,25 +769,25 @@ Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) static enum FIRSTFRAME = 4; else static enum FIRSTFRAME = 0; - return new UnwindBacktrace(FIRSTFRAME); + return allocate!UnwindBacktrace(FIRSTFRAME); } else version (Windows) { import core.sys.windows.stacktrace; - static if (__traits(compiles, new StackTrace(0, null))) + static if (__traits(compiles, allocate!StackTrace(0, null))) { import core.sys.windows.winnt : CONTEXT; version (Win64) enum FIRSTFRAME = 4; else version (Win32) enum FIRSTFRAME = 0; - return new StackTrace(FIRSTFRAME, cast(CONTEXT*)ptr); + return allocate!StackTrace(FIRSTFRAME, cast(CONTEXT*)ptr); } else return null; } - else static if (__traits(compiles, new DefaultTraceInfo())) - return new DefaultTraceInfo(); + else static if (__traits(compiles, allocate!DefaultTraceInfo())) + return allocate!DefaultTraceInfo(); else return null; } @@ -775,9 +805,32 @@ unittest { printf("%.*s\n", cast(int)line.length, line.ptr); } + defaultTraceDeallocator(trace); } } +/*** + * Deallocate a traceinfo generated by deaultTraceHander. + * + * Call this function on a TraceInfo generated via `defaultTraceHandler` when + * you are done with it. If necessary, this cleans up any manually managed + * resources from the `TraceInfo`, and invalidates it. After this, the object + * is no longer valid. + * + * Params: + * info = The `TraceInfo` to deallocate. This should only be a value that + * was returned by `defaultTraceHandler`. + */ +void defaultTraceDeallocator(Throwable.TraceInfo info) nothrow +{ + if (info is null) + return; + auto obj = cast(Object)info; + destroy(obj); + import core.stdc.stdlib : free; + free(cast(void *)obj); +} + version (DRuntime_Use_Libunwind) { import core.internal.backtrace.handler; @@ -791,7 +844,7 @@ else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInf import core.stdc.stdlib : free; import core.stdc.string : strlen, memchr, memmove; - this() + this() @nogc { // it may not be 1 but it is good enough to get // in CALL instruction address range for backtrace @@ -805,13 +858,13 @@ else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInf elem -= CALL_INSTRUCTION_SIZE; else // backtrace() failed, do it ourselves { - static void** getBasePtr() + static void** getBasePtr() @nogc { version (D_InlineAsm_X86) - asm { naked; mov EAX, EBP; ret; } + asm @nogc { naked; mov EAX, EBP; ret; } else version (D_InlineAsm_X86_64) - asm { naked; mov RAX, RBP; ret; } + asm @nogc { naked; mov RAX, RBP; ret; } else return null; } diff --git a/libphobos/libdruntime/core/stdc/config.d b/libphobos/libdruntime/core/stdc/config.d index c576e99..16bc475 100644 --- a/libphobos/libdruntime/core/stdc/config.d +++ b/libphobos/libdruntime/core/stdc/config.d @@ -286,6 +286,22 @@ private struct _Complex(T) { T re; T im; + + // Helper properties. + pragma(inline, true) + { + static @property epsilon()() { return _Complex(T.epsilon, T.epsilon); } + static @property infinity()() { return _Complex(T.infinity, T.infinity); } + static @property max()() { return _Complex(T.max, T.max); } + static @property min_normal()() { return _Complex(T.min_normal, T.min_normal); } + static @property nan()() { return _Complex(T.nan, T.nan); } + static @property dig()() { return T.dig; } + static @property mant_dig()() { return T.mant_dig; } + static @property max_10_exp()() { return T.max_10_exp; } + static @property max_exp()() { return T.max_exp; } + static @property min_10_exp()() { return T.min_10_exp; } + static @property min_exp()() { return T.min_exp; } + } } enum __c_complex_float : _Complex!float; diff --git a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d index dc42a2d..b6e10a8 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/getsect.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/getsect.d @@ -148,7 +148,7 @@ version (CoreDdoc) * * auto mph = _NSGetMachExecuteHeader(); * int size; - * assert(getsectdata(mph, "__TEXT", "__text", &size)); + * assert(getsectiondata(mph, "__TEXT", "__text", &size)); * assert(size > 0); * } * --- diff --git a/libphobos/libdruntime/core/sys/posix/sys/wait.d b/libphobos/libdruntime/core/sys/posix/sys/wait.d index 145149b..f6b0674 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/wait.d +++ b/libphobos/libdruntime/core/sys/posix/sys/wait.d @@ -386,9 +386,15 @@ else version (NetBSD) else version (OpenBSD) { enum WCONTINUED = 8; - // OpenBSD does not define the following: - //enum WSTOPPED - //enum WNOWAIT + enum WSTOPPED = WUNTRACED; + enum WNOWAIT = 16; + + enum idtype_t + { + P_ALL, + P_PID, + P_PGID + } } else version (DragonFlyBSD) { diff --git a/libphobos/libdruntime/core/sys/windows/dbghelp.d b/libphobos/libdruntime/core/sys/windows/dbghelp.d index de14bce..55fbc56 100644 --- a/libphobos/libdruntime/core/sys/windows/dbghelp.d +++ b/libphobos/libdruntime/core/sys/windows/dbghelp.d @@ -31,7 +31,7 @@ extern(Windows) alias PVOID function(HANDLE hProcess, DWORD64 AddrBase) SymFunctionTableAccess64Func; alias BOOL function(DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, PVOID ContextRecord, ReadProcessMemoryProc64 ReadMemoryRoutine, FunctionTableAccessProc64 FunctoinTableAccess, - GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress) StackWalk64Func; + GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress) @nogc StackWalk64Func; alias BOOL function(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, IMAGEHLP_LINEA64 *line) SymGetLineFromAddr64Func; alias DWORD64 function(HANDLE hProcess, DWORD64 dwAddr) SymGetModuleBase64Func; alias BOOL function(HANDLE hProcess, DWORD64 dwAddr, IMAGEHLP_MODULEA64 *ModuleInfo) SymGetModuleInfo64Func; @@ -66,7 +66,7 @@ struct DbgHelp SymRegisterCallback64Func SymRegisterCallback64; ImagehlpApiVersionFunc ImagehlpApiVersion; - static DbgHelp* get() + static DbgHelp* get() @nogc { if ( sm_hndl != sm_hndl.init ) return &sm_inst; diff --git a/libphobos/libdruntime/core/sys/windows/stacktrace.d b/libphobos/libdruntime/core/sys/windows/stacktrace.d index 6e5c4cd..8df2972 100644 --- a/libphobos/libdruntime/core/sys/windows/stacktrace.d +++ b/libphobos/libdruntime/core/sys/windows/stacktrace.d @@ -24,10 +24,10 @@ import core.sys.windows.windef; debug(PRINTF) import core.stdc.stdio; -extern(Windows) void RtlCaptureContext(CONTEXT* ContextRecord); +extern(Windows) void RtlCaptureContext(CONTEXT* ContextRecord) @nogc; extern(Windows) DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR pBuffer, DWORD nSize); -extern(Windows) alias USHORT function(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) RtlCaptureStackBackTraceFunc; +extern(Windows) alias USHORT function(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) @nogc RtlCaptureStackBackTraceFunc; private __gshared RtlCaptureStackBackTraceFunc RtlCaptureStackBackTrace; private __gshared immutable bool initialized; @@ -42,7 +42,7 @@ public: * skip = The number of stack frames to skip. * context = The context to receive the stack trace from. Can be null. */ - this(size_t skip, CONTEXT* context) + this(size_t skip, CONTEXT* context) @nogc { if (context is null) { @@ -64,7 +64,7 @@ public: skip += INTERNALFRAMES; } if ( initialized ) - m_trace = trace(skip, context); + m_trace = trace(tracebuf[], skip, context); } int opApply( scope int delegate(ref const(char[])) dg ) const @@ -100,18 +100,27 @@ public: } /** - * Receive a stack trace in the form of an address list. + * Receive a stack trace in the form of an address list. One form accepts + * an allocated buffer, the other form automatically allocates the buffer. + * * Params: * skip = How many stack frames should be skipped. * context = The context that should be used. If null the current context is used. + * buffer = The buffer to use for the trace. This should be at least 63 elements. * Returns: * A list of addresses that can be passed to resolve at a later point in time. */ static ulong[] trace(size_t skip = 0, CONTEXT* context = null) { + return trace(new ulong[63], skip, context); + } + + /// ditto + static ulong[] trace(ulong[] buffer, size_t skip = 0, CONTEXT* context = null) @nogc + { synchronized( typeid(StackTrace) ) { - return traceNoSync(skip, context); + return traceNoSync(buffer, skip, context); } } @@ -131,38 +140,43 @@ public: } private: + ulong[128] tracebuf; ulong[] m_trace; - static ulong[] traceNoSync(size_t skip, CONTEXT* context) + static ulong[] traceNoSync(ulong[] buffer, size_t skip, CONTEXT* context) @nogc { auto dbghelp = DbgHelp.get(); if (dbghelp is null) return []; // dbghelp.dll not available - if (RtlCaptureStackBackTrace !is null && context is null) + if (buffer.length >= 63 && RtlCaptureStackBackTrace !is null && + context is null) { - size_t[63] buffer = void; // On windows xp the sum of "frames to skip" and "frames to capture" can't be greater then 63 - auto backtraceLength = RtlCaptureStackBackTrace(cast(ULONG)skip, cast(ULONG)(buffer.length - skip), cast(void**)buffer.ptr, null); + version (Win64) + { + auto bufptr = cast(void**)buffer.ptr; + } + version (Win32) + { + size_t[63] bufstorage = void; // On windows xp the sum of "frames to skip" and "frames to capture" can't be greater then 63 + auto bufptr = cast(void**)bufstorage.ptr; + } + auto backtraceLength = RtlCaptureStackBackTrace(cast(ULONG)skip, cast(ULONG)(63 - skip), bufptr, null); // If we get a backtrace and it does not have the maximum length use it. // Otherwise rely on tracing through StackWalk64 which is slower but works when no frame pointers are available. - if (backtraceLength > 1 && backtraceLength < buffer.length - skip) + if (backtraceLength > 1 && backtraceLength < 63 - skip) { debug(PRINTF) printf("Using result from RtlCaptureStackBackTrace\n"); - version (Win64) + version (Win32) { - return buffer[0..backtraceLength].dup; - } - else version (Win32) - { - auto result = new ulong[backtraceLength]; - foreach (i, ref e; result) + foreach (i, ref e; buffer[0 .. backtraceLength]) { - e = buffer[i]; + e = bufstorage[i]; } - return result; } + return buffer[0..backtraceLength]; } } @@ -210,21 +224,21 @@ private: else version (X86_64) enum imageType = IMAGE_FILE_MACHINE_AMD64; else static assert(0, "unimplemented"); - ulong[] result; size_t frameNum = 0; + size_t nframes = 0; // do ... while so that we don't skip the first stackframe do { if (frameNum >= skip) { - result ~= stackframe.AddrPC.Offset; + buffer[nframes++] = stackframe.AddrPC.Offset; } frameNum++; } while (dbghelp.StackWalk64(imageType, hProcess, hThread, &stackframe, &ctxt, null, null, null, null)); - return result; + return buffer[0 .. nframes]; } static char[][] resolveNoSync(const(ulong)[] addresses) diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index 415430c..7316373 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -1997,12 +1997,17 @@ extern (C) void thread_suspendAll() nothrow Thread.criticalRegionLock.lock_nothrow(); scope (exit) Thread.criticalRegionLock.unlock_nothrow(); size_t cnt; + bool suspendedSelf; Thread t = ThreadBase.sm_tbeg.toThread; while (t) { auto tn = t.next.toThread; if (suspend(t)) + { + if (t is ThreadBase.getThis()) + suspendedSelf = true; ++cnt; + } t = tn; } @@ -2010,9 +2015,12 @@ extern (C) void thread_suspendAll() nothrow {} else version (Posix) { - // subtract own thread + // Subtract own thread if we called suspend() on ourselves. + // For example, suspendedSelf would be false if the current + // thread ran thread_detachThis(). assert(cnt >= 1); - --cnt; + if (suspendedSelf) + --cnt; // wait for semaphore notifications for (; cnt; --cnt) { diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d index ea163a0..8d50875 100644 --- a/libphobos/libdruntime/core/time.d +++ b/libphobos/libdruntime/core/time.d @@ -2822,7 +2822,7 @@ struct TickDuration } - @trusted shared static this() + static pragma(crt_constructor) void time_initializer() { version (Windows) { diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 83351f2..0385b51 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -246,7 +246,7 @@ class Object * } * --- */ - static Object factory(string classname) + deprecated static Object factory(string classname) { auto ci = TypeInfo_Class.find(classname); if (ci) @@ -256,7 +256,7 @@ class Object return null; } - @system unittest + deprecated @system unittest { Object valid_obj = Object.factory("object.Object"); Object invalid_obj = Object.factory("object.__this_class_doesnt_exist__"); @@ -2481,6 +2481,8 @@ class Throwable : Object string toString() const; } + alias TraceDeallocator = void function(TraceInfo) nothrow; + string msg; /// A message describing the error. /** @@ -2502,6 +2504,12 @@ class Throwable : Object TraceInfo info; /** + * If set, this is used to deallocate the TraceInfo on destruction. + */ + TraceDeallocator infoDeallocator; + + + /** * A reference to the _next error in the list. This is used when a new * $(D Throwable) is thrown from inside a $(D catch) block. The originally * caught $(D Exception) will be chained to the new $(D Throwable) via this @@ -2614,6 +2622,13 @@ class Throwable : Object { if (nextInChain && nextInChain._refcount) _d_delThrowable(nextInChain); + // handle owned traceinfo + if (infoDeallocator !is null) + { + infoDeallocator(info); + info = null; // avoid any kind of dangling pointers if we can help + // it. + } } /** diff --git a/libphobos/libdruntime/rt/deh.d b/libphobos/libdruntime/rt/deh.d index 695f2ce..0a44be3 100644 --- a/libphobos/libdruntime/rt/deh.d +++ b/libphobos/libdruntime/rt/deh.d @@ -42,12 +42,14 @@ module rt.deh; extern (C) { Throwable.TraceInfo _d_traceContext(void* ptr = null); + Throwable.TraceDeallocator rt_getTraceDeallocator(); void _d_createTrace(Throwable t, void* context) { if (t !is null && t.info is null && cast(byte*) t !is typeid(t).initializer.ptr) { t.info = _d_traceContext(context); + t.infoDeallocator = rt_getTraceDeallocator(); } } } diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d index 264fdf6..8a10aac 100644 --- a/libphobos/libdruntime/rt/dmain2.d +++ b/libphobos/libdruntime/rt/dmain2.d @@ -182,6 +182,7 @@ extern (C) int rt_term() */ alias Throwable.TraceInfo function(void* ptr) TraceHandler; private __gshared TraceHandler traceHandler = null; +private __gshared Throwable.TraceDeallocator traceDeallocator = null; /** @@ -189,10 +190,12 @@ private __gshared TraceHandler traceHandler = null; * * Params: * h = The new trace handler. Set to null to use the default handler. + * d = The new dealloactor to use. */ -extern (C) void rt_setTraceHandler(TraceHandler h) +extern (C) void rt_setTraceHandler(TraceHandler h, Throwable.TraceDeallocator d = null) { traceHandler = h; + traceDeallocator = d; } /** @@ -203,6 +206,11 @@ extern (C) TraceHandler rt_getTraceHandler() return traceHandler; } +extern (C) Throwable.TraceDeallocator rt_getTraceDeallocator() +{ + return traceDeallocator; +} + /** * This function will be called when an exception is constructed. The * user-supplied trace handler will be called if one has been supplied, diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 09da6a8..be31395 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -792c8b7c1d5957767e138f78d04bf175d4b92f10 +13ef27a56e4c22e122fc4dd54bb46b5955babdb0 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 9a365d5..967d2a6 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -7737,8 +7737,9 @@ if (isInputRange!R && // uniq /** -Lazily iterates unique consecutive elements of the given range (functionality -akin to the $(HTTP wikipedia.org/wiki/_Uniq, _uniq) system +Lazily iterates unique consecutive elements of the given range, which is +assumed to be sorted (functionality akin to the +$(HTTP wikipedia.org/wiki/_Uniq, _uniq) system utility). Equivalence of elements is assessed by using the predicate `pred`, by default `"a == b"`. The predicate is passed to $(REF binaryFun, std,functional), and can either accept a string, or any callable diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index d1b6421..aef2365 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -1891,9 +1891,7 @@ if (!is(S : T) && isAssociativeArray!S && } // test conversions floating => integral { - // AllInts[0 .. $ - 1] should be AllInts - // @@@ BUG IN COMPILER @@@ - foreach (Integral; AllInts[0 .. $ - 1]) + foreach (Integral; AllInts) { foreach (Floating; AllFloats) { @@ -1903,7 +1901,7 @@ if (!is(S : T) && isAssociativeArray!S && } // test conversion integral => floating { - foreach (Integral; AllInts[0 .. $ - 1]) + foreach (Integral; AllInts) { foreach (Floating; AllFloats) { diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d index e32330f..66f4b8a 100644 --- a/libphobos/src/std/math/exponential.d +++ b/libphobos/src/std/math/exponential.d @@ -2910,7 +2910,7 @@ private alias log10P = logP; alias log10Q = logQ; - // Coefficients for log(x) = z + z^^3 P(z^^2)/Q(z^^2) + // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) // where z = 2(x-1)/(x+1) // Theoretical peak relative error = 1.1e-35 static immutable real[6] logR = [ @@ -2931,7 +2931,8 @@ private 1.0 ]; } - else + else static if (floatTraits!T.realFormat == RealFormat.ieeeExtended || + floatTraits!T.realFormat == RealFormat.ieeeExtended53) { // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) // Theoretical peak relative error = 2.32e-20 @@ -2980,7 +2981,7 @@ private alias log10P = log2P; alias log10Q = log2Q; - // Coefficients for log(x) = z + z^^3 P(z^^2)/Q(z^^2) + // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) // where z = 2(x-1)/(x+1) // Theoretical peak relative error = 6.16e-22 static immutable real[4] logR = [ @@ -2996,6 +2997,85 @@ private 1.0000000000000000000000E0L, ]; } + else static if (floatTraits!T.realFormat == RealFormat.ieeeDouble) + { + // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) + static immutable double[6] logP = [ + 7.70838733755885391666E0, + 1.79368678507819816313E1, + 1.44989225341610930846E1, + 4.70579119878881725854E0, + 4.97494994976747001425E-1, + 1.01875663804580931796E-4, + ]; + static immutable double[6] logQ = [ + 2.31251620126765340583E1, + 7.11544750618563894466E1, + 8.29875266912776603211E1, + 4.52279145837532221105E1, + 1.12873587189167450590E1, + 1.00000000000000000000E0, + ]; + + // log2 uses the same coefficients as log. + alias log2P = logP; + alias log2Q = logQ; + + // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) + static immutable double[7] log10P = [ + 1.98892446572874072159E1, + 5.67349287391754285487E1, + 6.06127134467767258030E1, + 2.97877425097986925891E1, + 6.56312093769992875930E0, + 4.98531067254050724270E-1, + 4.58482948458143443514E-5, + ]; + static immutable double[7] log10Q = [ + 5.96677339718622216300E1, + 2.14955586696422947765E2, + 3.07254189979530058263E2, + 2.20664384982121929218E2, + 8.27410449222435217021E1, + 1.50314182634250003249E1, + 1.00000000000000000000E0, + ]; + + // Coefficients for log(x) = z + z^^3 R(z)/S(z) + // where z = 2(x-1)/(x+1) + static immutable double[3] logR = [ + -6.41409952958715622951E1, + 1.63866645699558079767E1, + -7.89580278884799154124E-1, + ]; + static immutable double[4] logS = [ + -7.69691943550460008604E2, + 3.12093766372244180303E2, + -3.56722798256324312549E1, + 1.00000000000000000000E0, + ]; + } + else static if (floatTraits!T.realFormat == RealFormat.ieeeSingle) + { + // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x) + static immutable float[9] logP = [ + 3.3333331174E-1, + -2.4999993993E-1, + 2.0000714765E-1, + -1.6668057665E-1, + 1.4249322787E-1, + -1.2420140846E-1, + 1.1676998740E-1, + -1.1514610310E-1, + 7.0376836292E-2, + ]; + + // log2 and log10 uses the same coefficients as log. + alias log2P = logP; + alias log10P = logP; + } + else + static assert(0, "no coefficients for log()"); } } @@ -3009,6 +3089,7 @@ private * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ +pragma(inline, true) real log(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) @@ -3020,6 +3101,31 @@ real log(real x) @safe pure nothrow @nogc return logImpl(x); } +/// ditto +pragma(inline, true) +double log(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log(cast(real) x) : logImpl(x); } + +/// ditto +pragma(inline, true) +float log(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log(cast(real) x) : logImpl(x); } + +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log` called with argument types `(int)` matches both " + ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") +real log(int x) @safe pure nothrow @nogc { return log(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log` called with argument types `(uint)` matches both " + ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") +real log(uint x) @safe pure nothrow @nogc { return log(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log` called with argument types `(long)` matches both " + ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") +real log(long x) @safe pure nothrow @nogc { return log(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both " + ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") +real log(ulong x) @safe pure nothrow @nogc { return log(cast(real) x); } + /// @safe pure nothrow @nogc unittest { @@ -3034,12 +3140,31 @@ private T logImpl(T)(T x) @safe pure nothrow @nogc import std.math.constants : SQRT1_2; import std.math.algebraic : poly; import std.math.traits : isInfinity, isNaN, signbit; + import std.math : floatTraits, RealFormat; alias coeffs = LogCoeffs!T; + alias F = floatTraits!T; - // C1 + C2 = LN2. - enum T C1 = 6.93145751953125E-1L; - enum T C2 = 1.428606820309417232121458176568075500134E-6L; + static if (F.realFormat == RealFormat.ieeeExtended || + F.realFormat == RealFormat.ieeeExtended53 || + F.realFormat == RealFormat.ieeeQuadruple) + { + // C1 + C2 = LN2. + enum T C1 = 6.93145751953125E-1L; + enum T C2 = 1.428606820309417232121458176568075500134E-6L; + } + else static if (F.realFormat == RealFormat.ieeeDouble) + { + enum T C1 = 0.693359375; + enum T C2 = -2.121944400546905827679e-4; + } + else static if (F.realFormat == RealFormat.ieeeSingle) + { + enum T C1 = 0.693359375; + enum T C2 = -2.12194440e-4; + } + else + static assert(0, "Not implemented for this architecture"); // Special cases. if (isNaN(x)) @@ -3058,30 +3183,36 @@ private T logImpl(T)(T x) @safe pure nothrow @nogc x = frexp(x, exp); - // Logarithm using log(x) = z + z^^3 R(z) / S(z), - // where z = 2(x - 1)/(x + 1) - if ((exp > 2) || (exp < -2)) + static if (F.realFormat == RealFormat.ieeeDouble || + F.realFormat == RealFormat.ieeeExtended || + F.realFormat == RealFormat.ieeeExtended53 || + F.realFormat == RealFormat.ieeeQuadruple) { - if (x < SQRT1_2) - { // 2(2x - 1)/(2x + 1) - exp -= 1; - z = x - 0.5; - y = 0.5 * z + 0.5; - } - else - { // 2(x - 1)/(x + 1) - z = x - 0.5; - z -= 0.5; - y = 0.5 * x + 0.5; - } - x = z / y; - z = x * x; - z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); - z += exp * C2; - z += x; - z += exp * C1; + // Logarithm using log(x) = z + z^^3 R(z) / S(z), + // where z = 2(x - 1)/(x + 1) + if ((exp > 2) || (exp < -2)) + { + if (x < SQRT1_2) + { // 2(2x - 1)/(2x + 1) + exp -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } + else + { // 2(x - 1)/(x + 1) + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); + z += exp * C2; + z += x; + z += exp * C1; - return z; + return z; + } } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) @@ -3095,7 +3226,10 @@ private T logImpl(T)(T x) @safe pure nothrow @nogc x = x - 1.0; } z = x * x; - y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ)); + static if (F.realFormat == RealFormat.ieeeSingle) + y = x * (z * poly(x, coeffs.logP)); + else + y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ)); y += exp * C2; z = y - 0.5 * z; @@ -3117,6 +3251,7 @@ private T logImpl(T)(T x) @safe pure nothrow @nogc * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ +pragma(inline, true) real log10(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) @@ -3128,12 +3263,37 @@ real log10(real x) @safe pure nothrow @nogc return log10Impl(x); } +/// ditto +pragma(inline, true) +double log10(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log10(cast(real) x) : log10Impl(x); } + +/// ditto +pragma(inline, true) +float log10(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log10(cast(real) x) : log10Impl(x); } + +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both " + ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") +real log10(int x) @safe pure nothrow @nogc { return log10(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both " + ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") +real log10(uint x) @safe pure nothrow @nogc { return log10(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both " + ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") +real log10(long x) @safe pure nothrow @nogc { return log10(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both " + ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") +real log10(ulong x) @safe pure nothrow @nogc { return log10(cast(real) x); } + /// @safe pure nothrow @nogc unittest { import std.math.algebraic : fabs; - assert(fabs(log10(1000) - 3) < .000001); + assert(fabs(log10(1000.0L) - 3) < .000001); } private T log10Impl(T)(T x) @safe pure nothrow @nogc @@ -3141,16 +3301,34 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc import std.math.constants : SQRT1_2; import std.math.algebraic : poly; import std.math.traits : isNaN, isInfinity, signbit; + import std.math : floatTraits, RealFormat; alias coeffs = LogCoeffs!T; + alias F = floatTraits!T; - // log10(2) split into two parts. - enum T L102A = 0.3125L; - enum T L102B = -1.14700043360188047862611052755069732318101185E-2L; + static if (F.realFormat == RealFormat.ieeeExtended || + F.realFormat == RealFormat.ieeeExtended53 || + F.realFormat == RealFormat.ieeeQuadruple) + { + // log10(2) split into two parts. + enum T L102A = 0.3125L; + enum T L102B = -1.14700043360188047862611052755069732318101185E-2L; - // log10(e) split into two parts. - enum T L10EA = 0.5L; - enum T L10EB = -6.570551809674817234887108108339491770560299E-2L; + // log10(e) split into two parts. + enum T L10EA = 0.5L; + enum T L10EB = -6.570551809674817234887108108339491770560299E-2L; + } + else static if (F.realFormat == RealFormat.ieeeDouble || + F.realFormat == RealFormat.ieeeSingle) + { + enum T L102A = 3.0078125E-1; + enum T L102B = 2.48745663981195213739E-4; + + enum T L10EA = 4.3359375E-1; + enum T L10EB = 7.00731903251827651129E-4; + } + else + static assert(0, "Not implemented for this architecture"); // Special cases are the same as for log. if (isNaN(x)) @@ -3169,26 +3347,31 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc x = frexp(x, exp); - // Logarithm using log(x) = z + z^^3 R(z) / S(z), - // where z = 2(x - 1)/(x + 1) - if ((exp > 2) || (exp < -2)) - { - if (x < SQRT1_2) - { // 2(2x - 1)/(2x + 1) - exp -= 1; - z = x - 0.5; - y = 0.5 * z + 0.5; - } - else - { // 2(x - 1)/(x + 1) - z = x - 0.5; - z -= 0.5; - y = 0.5 * x + 0.5; + static if (F.realFormat == RealFormat.ieeeExtended || + F.realFormat == RealFormat.ieeeExtended53 || + F.realFormat == RealFormat.ieeeQuadruple) + { + // Logarithm using log(x) = z + z^^3 R(z) / S(z), + // where z = 2(x - 1)/(x + 1) + if ((exp > 2) || (exp < -2)) + { + if (x < SQRT1_2) + { // 2(2x - 1)/(2x + 1) + exp -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } + else + { // 2(x - 1)/(x + 1) + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); + goto Ldone; } - x = z / y; - z = x * x; - y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); - goto Ldone; } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) @@ -3201,7 +3384,10 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc x = x - 1.0; z = x * x; - y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q)); + static if (F.realFormat == RealFormat.ieeeSingle) + y = x * (z * poly(x, coeffs.log10P)); + else + y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q)); y = y - 0.5 * z; // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). @@ -3232,6 +3418,7 @@ Ldone: * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ +pragma(inline, true) real log1p(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) @@ -3245,6 +3432,31 @@ real log1p(real x) @safe pure nothrow @nogc return log1pImpl(x); } +/// ditto +pragma(inline, true) +double log1p(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log1p(cast(real) x) : log1pImpl(x); } + +/// ditto +pragma(inline, true) +float log1p(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log1p(cast(real) x) : log1pImpl(x); } + +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both " + ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") +real log1p(int x) @safe pure nothrow @nogc { return log1p(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both " + ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") +real log1p(uint x) @safe pure nothrow @nogc { return log1p(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both " + ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") +real log1p(long x) @safe pure nothrow @nogc { return log1p(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both " + ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") +real log1p(ulong x) @safe pure nothrow @nogc { return log1p(cast(real) x); } + /// @safe pure unittest { @@ -3289,6 +3501,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) ) * ) */ +pragma(inline, true) real log2(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) @@ -3297,6 +3510,31 @@ real log2(real x) @safe pure nothrow @nogc return log2Impl(x); } +/// ditto +pragma(inline, true) +double log2(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log2(cast(real) x) : log2Impl(x); } + +/// ditto +pragma(inline, true) +float log2(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log2(cast(real) x) : log2Impl(x); } + +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both " + ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") +real log2(int x) @safe pure nothrow @nogc { return log2(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both " + ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") +real log2(uint x) @safe pure nothrow @nogc { return log2(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both " + ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") +real log2(long x) @safe pure nothrow @nogc { return log2(cast(real) x); } +// @@@DEPRECATED_[2.112.0]@@@ +deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both " + ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") +real log2(ulong x) @safe pure nothrow @nogc { return log2(cast(real) x); } + /// @safe unittest { @@ -3318,8 +3556,10 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc import std.math.traits : isNaN, isInfinity, signbit; import std.math.constants : SQRT1_2, LOG2E; import std.math.algebraic : poly; + import std.math : floatTraits, RealFormat; alias coeffs = LogCoeffs!T; + alias F = floatTraits!T; // Special cases are the same as for log. if (isNaN(x)) @@ -3338,26 +3578,32 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc x = frexp(x, exp); - // Logarithm using log(x) = z + z^^3 R(z) / S(z), - // where z = 2(x - 1)/(x + 1) - if ((exp > 2) || (exp < -2)) + static if (F.realFormat == RealFormat.ieeeDouble || + F.realFormat == RealFormat.ieeeExtended || + F.realFormat == RealFormat.ieeeExtended53 || + F.realFormat == RealFormat.ieeeQuadruple) { - if (x < SQRT1_2) - { // 2(2x - 1)/(2x + 1) - exp -= 1; - z = x - 0.5; - y = 0.5 * z + 0.5; - } - else - { // 2(x - 1)/(x + 1) - z = x - 0.5; - z -= 0.5; - y = 0.5 * x + 0.5; + // Logarithm using log(x) = z + z^^3 R(z) / S(z), + // where z = 2(x - 1)/(x + 1) + if ((exp > 2) || (exp < -2)) + { + if (x < SQRT1_2) + { // 2(2x - 1)/(2x + 1) + exp -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } + else + { // 2(x - 1)/(x + 1) + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); + goto Ldone; } - x = z / y; - z = x * x; - y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); - goto Ldone; } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) @@ -3370,7 +3616,10 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc x = x - 1.0; z = x * x; - y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q)); + static if (F.realFormat == RealFormat.ieeeSingle) + y = x * (z * poly(x, coeffs.log2P)); + else + y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q)); y = y - 0.5 * z; // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). diff --git a/libphobos/src/std/math/operations.d b/libphobos/src/std/math/operations.d index cb3c805..f2e1800 100644 --- a/libphobos/src/std/math/operations.d +++ b/libphobos/src/std/math/operations.d @@ -1793,7 +1793,7 @@ if (isFloatingPoint!T) } import std.math.exponential : log2; - enum log2_max_exp = cast(int) log2(T.max_exp); + enum log2_max_exp = cast(int) log2(T(T.max_exp)); ret.mantissa = ival & ((1L << (T.mant_dig - 1)) - 1); ret.exponent = (ival >> (T.mant_dig - 1)) & ((1L << (log2_max_exp + 1)) - 1); diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d index df7ac39..648b70e 100644 --- a/libphobos/src/std/numeric.d +++ b/libphobos/src/std/numeric.d @@ -436,7 +436,7 @@ public: static @property size_t dig() { auto shiftcnt = precision - ((flags&Flags.storeNormalized) == 0); - return shiftcnt == 64 ? 19 : cast(size_t) log10(1uL << shiftcnt); + return shiftcnt == 64 ? 19 : cast(size_t) log10(real(1uL << shiftcnt)); } /// Returns: smallest increment to the value 1 diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d index 2c97638..9b231f3 100644 --- a/libphobos/src/std/parallelism.d +++ b/libphobos/src/std/parallelism.d @@ -1508,7 +1508,7 @@ public: if (this.size == 0) { - return rangeLen; + return max(rangeLen, 1); } immutable size_t eightSize = 4 * (this.size + 1); @@ -3644,6 +3644,15 @@ ParallelForeach!R parallel(R)(R range, size_t workUnitSize) assert(arrIndex.sum == 10.iota.sum); } +// https://issues.dlang.org/show_bug.cgi?id=22745 +@system unittest +{ + auto pool = new TaskPool(0); + int[] empty; + foreach (i; pool.parallel(empty)) {} + pool.finish(); +} + // Thrown when a parallel foreach loop is broken from. class ParallelForeachError : Error { @@ -4339,7 +4348,7 @@ version (StdUnittest) foreach (i, elem; logs) { - assert(isClose(elem, cast(double) log(i + 1))); + assert(isClose(elem, log(double(i + 1)))); } assert(poolInstance.amap!"a * a"([1,2,3,4,5]) == [1,4,9,16,25]); diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index 9b3c5ed..93be764 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -2516,7 +2516,7 @@ if (!is(T == enum) && (isIntegral!T || isSomeChar!T)) assert(rnd.uniform!ulong == 4838462006927449017); enum Fruit { apple, mango, pear } - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(rnd.uniform!Fruit == Fruit.mango); } @@ -2798,7 +2798,7 @@ auto ref choice(Range)(ref Range range) auto rnd = MinstdRand0(42); auto elem = [1, 2, 3, 4, 5].choice(rnd); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(elem == 3); } @@ -2913,7 +2913,7 @@ if (isRandomAccessRange!Range) auto rnd = MinstdRand0(42); auto arr = [1, 2, 3, 4, 5].randomShuffle(rnd); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(arr == [3, 5, 2, 4, 1]); } @@ -3003,15 +3003,15 @@ if (isRandomAccessRange!Range) auto arr = [1, 2, 3, 4, 5, 6]; arr = arr.dup.partialShuffle(1, rnd); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(arr == [2, 1, 3, 4, 5, 6]); // 1<->2 arr = arr.dup.partialShuffle(2, rnd); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(arr == [1, 4, 3, 2, 5, 6]); // 1<->2, 2<->4 arr = arr.dup.partialShuffle(3, rnd); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(arr == [5, 4, 6, 2, 1, 3]); // 1<->5, 2<->4, 3<->6 } @@ -3428,7 +3428,7 @@ if (isRandomAccessRange!Range) import std.range : iota; auto rnd = MinstdRand0(42); - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 assert(10.iota.randomCover(rnd).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); } diff --git a/libphobos/src/std/regex/package.d b/libphobos/src/std/regex/package.d index 1562d79..d6a01e2 100644 --- a/libphobos/src/std/regex/package.d +++ b/libphobos/src/std/regex/package.d @@ -212,7 +212,7 @@ They met on 24/01/1970. names work like aliases in addition to direct numbers. ) $(REG_TITLE Assertions, Match position rather than character ) - $(REG_ROW ^, Matches at the begining of input or line (in multiline mode).) + $(REG_ROW ^, Matches at the beginning of input or line (in multiline mode).) $(REG_ROW $, Matches at the end of input or line (in multiline mode). ) $(REG_ROW \b, Matches at word boundary. ) $(REG_ROW \B, Matches when $(U not) at word boundary. ) diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index e83b6171..25cf9e0 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -225,7 +225,10 @@ public: { if (_p !is null) { - destroy(_p); + static if (is(T == class) || is(T == interface)) + destroy(_p); + else + destroy(*_p); _p = null; } } @@ -259,7 +262,7 @@ private: /// @safe unittest { - static struct S + struct S { int i; this(int i){this.i = i;} @@ -284,6 +287,7 @@ private: Unique!S u1; assert(u1.isEmpty); u1 = produce(); + assert(u1.i == 5); increment(u1); assert(u1.i == 6); //consume(u1); // Error: u1 is not copyable @@ -292,6 +296,24 @@ private: assert(u1.isEmpty); } +@safe unittest +{ + int i; + struct S + { + ~this() + { + // check context pointer still exists - dtor also called before GC frees struct + if (this.tupleof[0]) + i++; + } + } + { + Unique!S u = new S; + } + assert(i == 1); +} + @system unittest { // test conversion to base ref diff --git a/libphobos/testsuite/libphobos.exceptions/refcounted.d b/libphobos/testsuite/libphobos.exceptions/refcounted.d index 2b7e79b..e4ed8e8 100644 --- a/libphobos/testsuite/libphobos.exceptions/refcounted.d +++ b/libphobos/testsuite/libphobos.exceptions/refcounted.d @@ -2,9 +2,9 @@ class E : Exception { static int instances; - this(string msg = "") + this(string msg = "", Throwable nextInChain = null) { - super(msg); + super(msg, nextInChain); instances++; } @@ -93,4 +93,34 @@ void main() } assert(E.instances == 0); + + try + { + throw new E("first"); + } + catch (E first) + { + assert(first.refcount == 2); + assert(E.instances == 1); + + try + { + throw new E("second", first); + } + catch (E second) + { + assert(first.next is null); + assert(second.next is first); + + assert(first.refcount == 3); + assert(second.refcount == 2); + + assert(E.instances == 2); + } + + assert(first.refcount == 2); + assert(E.instances == 1); + } + + assert(E.instances == 0); } diff --git a/libphobos/testsuite/libphobos.gc/issue22843.d b/libphobos/testsuite/libphobos.gc/issue22843.d new file mode 100644 index 0000000..bf6e830 --- /dev/null +++ b/libphobos/testsuite/libphobos.gc/issue22843.d @@ -0,0 +1,12 @@ +import core.memory; +void main() +{ + auto collections = GC.profileStats().numCollections; + // loop until we trigger a collection + for (;;) + { + cast(void)GC.malloc(100_000, GC.BlkAttr.NO_SCAN); + if (GC.profileStats().numCollections == collections+1) + break; + } +} diff --git a/libphobos/testsuite/libphobos.shared/finalize.d b/libphobos/testsuite/libphobos.shared/finalize.d index f31b818..fcec87b 100644 --- a/libphobos/testsuite/libphobos.shared/finalize.d +++ b/libphobos/testsuite/libphobos.shared/finalize.d @@ -7,9 +7,9 @@ import core.sys.posix.dlfcn; void runTest() { Object obj; - obj = Object.factory("lib.MyFinalizer"); + obj = Object.factory("lib.MyFinalizer"); // { dg-warning "is deprecated" } assert(obj.toString() == "lib.MyFinalizer"); - obj = Object.factory("lib.MyFinalizerBig"); + obj = Object.factory("lib.MyFinalizerBig"); // { dg-warning "is deprecated" } assert(obj.toString() == "lib.MyFinalizerBig"); } -- cgit v1.1