Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Change Log: 2.110.0

previous version: 2.109.0

Download D nightlies
To be released

This changelog has been automatically generated from all commits in master since the last release.

  • The full-text messages are assembled from the changelog/ directories of the respective repositories: dmd, druntime, phobos, tools,, installer, and dub.
  • See the DLang-Bot documentation for details on referencing Bugzilla. The DAutoTest PR preview doesn't include the Bugzilla changelog.
  • The pending changelog can be generated locally by setting up and running the pending_changelog target:
    make -f posix.mak pending_changelog

2.110.0 comes with 15 major changes and 8 fixed Bugzilla issues. A huge thanks goes to the 14 contributors who made 2.110.0 possible.

List of all upcoming bug fixes and enhancements in D 2.110.0.

Compiler changes

  1. [next edition] Aliasing a member of a type instance is now an error

    Such an alias actually aliases a member of the instance's type, not the instance member itself. That could be confusing, and is now an error. Instead, alias a member of the type:

    struct Foo
        int v;
        void test(Foo that) const
            alias a = this.v; // OK
            alias b = that.v; // Error, use `typeof(that).v` instead
            assert(&a is &b); // passes
            assert(&b !is &that.v);
    struct Bar
        Foo f;
        alias v = f.v; // Error, use `typeof(f).v`
  2. Add Bitfield Introspection Capability


    • property .bitoffsetof to get the starting bit number of a bitfield

    • property .bitwidth to get the number of bits in a bitfield

    • __traits(isBitfield, symbol) returns true if a field symbol is a bitfield

  3. Added __ctfeWrite to write messages from CTFE

    The special function __ctfeWrite can now be used to write messages during CTFE, similar to pragma(msg, ...). It is Implementation Defined how the message is presented to the user; the recommended way is by printing the message to stderr, standard error stream. The function is available in object.d and accepts any value implicitly convertible to const(char)[].

    For example:

    int greeting()
        __ctfeWrite("Hello from CTFE. Today is ");
        return 0;
    enum forceCTFE = greeting();

    Compiling this program will generate the following output:

    Hello from CTFE. Today is <current date>
  4. Deprecation warnings are now also limited by -verrors

    By default, the compiler stops after 20 error messages, unless a different amount is specified by passing e.g. -verrors=50 or -verrors=0 for no limit. This error limit now also applies to deprecation messages, so the command line isn't flooded with hundreds of them when compiling a big project that hasn't fixed all deprecations yet.

    deprecated void f()
    void main()

    > dmd -verrors=3 app.d
    app.d(7): Deprecation: function app.f is deprecated
    app.d(8): Deprecation: function app.f is deprecated
    app.d(9): Deprecation: function app.f is deprecated
    1 deprecation warning omitted, use -verrors=0 to show all

  5. dtoh generates signatures for extern(Windows) and extern(System) functions.

    When using the -HC switch, in addition to extern(C) and extern(C++) functions, extern(Windows) and extern(System) functions are output in the .h file as well.

    Example D module:

    extern(Windows) int hello()
        return 0;
    extern(System) int myFriend()
        return 0;

    Output with -HC switch:

    // (full header omitted)
    #ifndef _WIN32
    #define EXTERN_SYSTEM_AFTER __stdcall
    #define EXTERN_SYSTEM_BEFORE extern "C"
    int32_t __stdcall hello();
  6. foreach on a dynamic array can have an index type smaller than size_t

    The array length is known at compile-time for the following cases:

    • The array is a literal
    • The array is a slice expression whose upper bound is known at compile-time

    For an array a, the index type can be any integer type I where a.length <= I.max.

    Other cases are not implemented yet.

  7. foreach_reverse on a delegate is now an error

    The compiler did not try to implement reverse traversal of the results returned by the delegate when foreach_reverse was used. That could result in code that was confusing to read, so it was deprecated (for many years). Using foreach_reverse with a delegate is now an error.

  8. Expansion of identifier tables to allow new characters to match C23 have been added along with CLI configurability

    You can currently choose between c99, c11, UAX31 (C23's) and all (the least restrictive set) for both D and ImportC.

    This can be done with -identifiers=<table> and for ImportC -identifiers-importc=<table>.

    The default table for D is currently set to all, while ImportC is set to c11. Previously both D and ImportC used the c99 tables.

    D's table will be swapped over at a later date to UAX31, this should be done in 2.117. If you find yourself at this time using c99 specific characters and not willing to change them, you may switch back to all. Although it should be unlikely that you will need to.

  9. ImportC has improved Unicode support

    Universal Character Names are now supported, allowing you to use the \uXXXX and \UXXXXXXXX syntax where X is a hex digit as part of an identifier.

    DigitalMars sppn does not support anything newer than C99. It is known to be limited and using any Unicode character not in those ranges will result in an error.

  10. Missing symbol errors are made less cryptic

    It is not uncommon to forget to link a library, list a .d file on the command line, or include a main function. Example:

    module app;
        import assertions;
        assertEquals('D', 'D');
    module assertions;
    void assertEquals(char a, char b)
        assert(a == b);

    When compiling this as follows:

    > dmd -unittest app.d

    The compiler would not see any error, but at link time there are missing symbols. Formerly, this would result in a cryptic linker error with mangled symbol names:

    /usr/bin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../lib/Scrt1.o: in function `_start':
    (.text+0x1b): undefined reference to `main'
    /usr/bin/ld: app.o: in function `_D3app16__unittest_L5_C1FZv':
    app.d:(.text._D3app16__unittest_L5_C1FZv[_D3app16__unittest_L5_C1FZv]+0xc): undefined reference to `_D10assertions12assertEqualsFaaZv'
    collect2: error: ld returned 1 exit status

    Experienced users might know how to demangle the symbol to make it more readable:

    > echo _D10assertions12assertEqualsFaaZv | ddemangle
    void assertions.assertEquals(char, char)

    But this is inconvenient to do manually every time. Now, when the compiler invokes the linker program, it will read its output, scan for undefined symbol errors, and demangle the names:

    Error: undefined reference to main
    Error: undefined reference to void assertions.assertEquals(char, char)
           referenced from void app.__unittest_L5_C1()
           perhaps define a void main() {} function or use the -main switch
           perhaps .d files need to be added on the command line, or use -i to compile imports
    Error: linker exited with status 1

    Which makes it easier to fix the command:

    > dmd -unittest -main -i app.d

    Currently supported linkers are ld, bfd, gold, mold, and Microsoft LINK. Please file an issue if your linker's errors aren't detected.

  11. Windows OMF support has been removed

    After two years of making PE-COFF support the default on Windows, OMF support has now been removed.

    This includes the switch (-m32omf).

Runtime changes

  1. Add module core.sys.linux.sys.mount.

    The new module core.sys.linux.sys.mount provides definitions corresponding to those in the header <sys/mount.h> on Linux.

  2. Remove all collectNoStack functions and API from druntime.

    The function collectNoStack in the D garbage collector performed a collection, without using any roots from thread stacks or thread-local-storage. The danger of running this mechanism is that any blocks of memory which only have a reference from a thread might be collected, while the thread is still running and possibly using the memory.

    The only time this function was called was at GC termination. At GC termination, the GC is about to be destroyed, and so we want to run as many destructors as possible. However, if some thread is using GC-allocated memory, cleaning up that memory isn't going to help matters. Either it will crash after the GC cleans the memory, or it will crash after the GC is destroyed.

    The original purpose of this function (from D1) was to ensure simple uses of the GC were cleaned up in small test programs, as this mechanism was only used on single-threaded programs (and of course, at program exit). Also note at the time, D1 was 32-bit, and false pointers where much more common. Avoiding scanning stacks would aid in avoiding seemingly random behavior in cleanup. However, as shown below, there are more deterministic ways to ensure data is always cleaned up.

    Today, the dangers are much greater that such a function is even callable -- any call to such a function would immediately start use-after-free memory corruption in any thread that is still running. Therefore, we are removing the functionality entirely, and simply doing a standard GC cleanup (scanning stacks and all). One less footgun is the benefit for having less guaranteed GC clean up at program exit.

    In addition, the GC today is a bit smarter about where the valid stack is, so there is even less of a chance of leaving blocks unfinalized.

    As always, the GC is not guaranteed to clean up any block at the end of runtime. Any change in behavior with code that had blocks clean up before, but no longer are cleaned up is still within specification. And if you want the behavior that absolutely cleans all blocks, you can use the --DRT-gcopt=cleanup:finalize druntime configuration option, which will clean up all blocks without even scanning.

  3. Mark Thread.sleep as @trusted

    The static method core.thread.Thread.sleep is now marked as @trusted and can be called directly from @safe code.

Library changes

  1. Add std.process.Config.preExecDelegate

    std.process.Config.preExecDelegate is just like std.process.Config.preExecFunction, but can capture an environment, for example:

    import core.sys.linux.sys.prctl : PR_SET_PDEATHSIG, prctl;
    import std.process : Config, execute;
    void runProgram(int pdeathsig)
            config: Config(
                preExecDelegate: () @trusted =>
                    prctl(PR_SET_PDEATHSIG, pdeathsig, 0, 0, 0) != -1,

    preExecFunction is retained for backwards compatibility. If both preExecFunction and preExecDelegate are given, both are called.

List of all bug fixes and enhancements in D 2.110.0:

DMD Compiler bug fixes

  1. Bugzilla 24534: Having a label on a declaration makes it possible to skip it with goto
  2. Bugzilla 24558: C asserts segfault on Glibc

DMD Compiler enhancements

  1. Bugzilla 20243: inout not substituted for in associative array key type
  2. Bugzilla 24135: Eponymous template member overloads not shown as call candidates

Phobos bug fixes

  1. Bugzilla 24564: std.file.DirEntry throws Exception instead of FileException bug fixes

  1. Bugzilla 24543: The @__future attribute is (almost) undocumented
  2. Bugzilla 24548: [spec] Boolean condition conversion is not documented
  3. Bugzilla 24565: out contract variable is implicitly const

Contributors to this release (14)

A huge thanks goes to all the awesome people who made this release possible.

previous version: 2.109.0