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.109.0

previous version: 2.108.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, dlang.org, 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 dlang.org and running the pending_changelog target:
    make -f posix.mak pending_changelog


2.109.0 comes with 9 major changes and 26 fixed Bugzilla issues. A huge thanks goes to the 40 contributors who made 2.109.0 possible.

List of all upcoming bug fixes and enhancements in D 2.109.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. 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 ");
        __ctfeWrite(__DATE__);
        __ctfeWrite("\n");
        return 0;
    }
    
    enum forceCTFE = greeting();
    

    Compiling this program will generate the following output:

    Hello from CTFE. Today is <current date>
    
  3. 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()
    {
        f();
        f();
        f();
        f();
    }
    

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

  4. 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
    #else
    #define EXTERN_SYSTEM_AFTER
    #define EXTERN_SYSTEM_BEFORE extern "C"
    #endif
    
    int32_t __stdcall hello();
    
    EXTERN_SYSTEM_BEFORE int32_t EXTERN_SYSTEM_AFTER myFriend(x);
    
  5. 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.

  6. 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.

  7. 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;
    
    unittest
    {
        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.

Runtime changes

  1. 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.

  2. 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.


List of all bug fixes and enhancements in D 2.109.0:

DMD Compiler regression fixes

  1. Bugzilla 23657: [REG2.101] Incorrect error escape reference to stack allocated value
  2. Bugzilla 24436: a array be overwritten when other array be written
  3. Bugzilla 24479: [REG2.104] Error on getAttributes on getOverloads of templates
  4. Bugzilla 24505: [REG2.108] ImportC: Function-like macros (newly translated to templates) may collide with regular symbols
  5. Bugzilla 24519: compiler segfault on default argument with slice operator []

DMD Compiler bug fixes

  1. Bugzilla 14128: AliasDeclaration allows expressions, causing false code for ThisExp
  2. Bugzilla 20148: void initializated bool can be both true and false
  3. Bugzilla 21854: @live breaks foreach over integers
  4. Bugzilla 21923: @live does not take destructor code into account.
  5. Bugzilla 24477: Union access of bool shouldn't be allowed in @safe
  6. Bugzilla 24485: Invalid implicit ref return reinterpret cast for structs with copy constructor
  7. Bugzilla 24493: FreeBSD_14 version identifier missing
  8. Bugzilla 24495: ImportC: Struct initialization expression fails to initialize field
  9. Bugzilla 24509: importC cannot handle _stdcall Function Calling Convention with single heading underscore
  10. Bugzilla 24511: __stdcall functions from C are extern(C) in D.

DMD Compiler enhancements

  1. Bugzilla 5573: Compiler (not linker) should generate an error for missing main()
  2. Bugzilla 21718: Preview switches have insufficient descriptions
  3. Bugzilla 24111: [ImportC] fatal error C1034: stdio.h: no include path set
  4. Bugzilla 24450: apply VRP to foreach indices when array is of known length
  5. Bugzilla 24452: Can't disable coverage at runtime

Phobos bug fixes

  1. Bugzilla 15708: std.range.choose assumes hasElaborateCopyConstructor means "has __postblit"
  2. Bugzilla 24478: std.csv array out of bounds when row size exceeds header

Druntime regression fixes

  1. Bugzilla 24498: Multidimensional array not scanned by GC

Druntime bug fixes

  1. Bugzilla 24517: druntime tests fail on FreeBSD 14

dlang.org bug fixes

  1. Bugzilla 24472: __traits(fullyQualifedName) is undocumented in spec

dlang.org enhancements

  1. Bugzilla 24488: contributor guide hard to find from home page

Contributors to this release (40)

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

previous version: 2.108.0