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

previous version: 2.087.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.088.0 comes with 17 major changes and 35 fixed Bugzilla issues. A huge thanks goes to the 47 contributors who made 2.088.0 possible.

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

Compiler changes

  1. D1 operator overloads have been deprecated.

    The following D1 operator overloads have been deprecated in favor of opUnary:

    • opNeg Replace with opUnary(string op)() if (op == "-")
    • opCom Replace with opUnary(string op)() if (op == "~")
    • opPostInc Replace with opUnary(string op)() if (op == "++")
    • opPostDec Replace with opUnary(string op)() if (op == "--")
    • opStar Replace with opUnary(string op)() if (op == "*")

    The following D1 operator overloads have been deprecated in favor of opBinary:

    • opAdd Replace with opBinary(string op)(...) if (op == "+")
    • opSub Replace with opBinary(string op)(...) if (op == "-")
    • opMul Replace with opBinary(string op)(...) if (op == "*")
    • opDiv Replace with opBinary(string op)(...) if (op == "/")
    • opMod Replace with opBinary(string op)(...) if (op == "%")
    • opAnd Replace with opBinary(string op)(...) if (op == "&")
    • opXor Replace with opBinary(string op)(...) if (op == "^")
    • opOr Replace with opBinary(string op)(...) if (op == "|")
    • opShl Replace with opBinary(string op)(...) if (op == "<<")
    • opShr Replace with opBinary(string op)(...) if (op == ">>")
    • opUShr Replace with opBinary(string op)(...) if (op == ">>>")
    • opCat Replace with opBinary(string op)(...) if (op == "~")
    • opIn Replace with opBinary(string op)(...) if (op == "in")

    The following D1 operator overloads have been deprecated in favor of opBinaryRight:

    • opAdd_r Replace with opBinaryRight(string op)(...) if (op == "+")
    • opSub_r Replace with opBinaryRight(string op)(...) if (op == "-")
    • opMul_r Replace with opBinaryRight(string op)(...) if (op == "*")
    • opDiv_r Replace with opBinaryRight(string op)(...) if (op == "/")
    • opMod_r Replace with opBinaryRight(string op)(...) if (op == "%")
    • opAnd_r Replace with opBinaryRight(string op)(...) if (op == "&")
    • opXor_r Replace with opBinaryRight(string op)(...) if (op == "^")
    • opOr_r Replace with opBinaryRight(string op)(...) if (op == "|")
    • opShl_r Replace with opBinaryRight(string op)(...) if (op == "<<")
    • opShr_r Replace with opBinaryRight(string op)(...) if (op == ">>")
    • opUShr_r Replace with opBinaryRight(string op)(...) if (op == ">>>")
    • opCat_r Replace with opBinaryRight(string op)(...) if (op == "~")
    • opIn_r Replace with opBinaryRight(string op)(...) if (op == "in")

    The following D1 operator overloads have been deprecated in favor of opOpAssign:

    • opAddAssign Replace with opOpAssign(string op)(...) if (op == "+")
    • opSubAssign Replace with opOpAssign(string op)(...) if (op == "-")
    • opMulAssign Replace with opOpAssign(string op)(...) if (op == "*")
    • opDivAssign Replace with opOpAssign(string op)(...) if (op == "/")
    • opModAssign Replace with opOpAssign(string op)(...) if (op == "%")
    • opAndAssign Replace with opOpAssign(string op)(...) if (op == "&")
    • opOrAssign Replace with opOpAssign(string op)(...) if (op == "|")
    • opXorAssign Replace with opOpAssign(string op)(...) if (op == "^")
    • opShlAssign Replace with opOpAssign(string op)(...) if (op == "<<")
    • opShrAssign Replace with opOpAssign(string op)(...) if (op == ">>")
    • opUShrAssign Replace with opOpAssign(string op)(...) if (op == ">>>")
    • opCatAssign Replace with opOpAssign(string op)(...) if (op == "~")

    Starting with this release, any D code that triggers a lowering to the D1 operator overloads will emit a deprecation warning.

    Example of deprecation warning:

    struct S
    {
        int opAdd(int i) { ... }
    }
    
    void main()
    {
        S s;
        int i;
        i = s + 1;  // Deprecation: `opAdd` is deprecated.  Use `opBinary` instead.
    }
    

    Example of corrective action:

    struct S
    {
        int opBinary(string op)(int i) if (op == "+") { ... }
    }
    
    void main()
    {
        S s;
        int i;
        i = s + 1;  // OK
    }
    
  2. Deprecate allowing a constructor declaration in a static block

    The language specification states that a static constructor is defined using the construction static this(). Defining a constructor inside a static block does not have any effect on the constructor. The following code does not affect the constructor in any way:

    static:
        this() {}
    
    static
    {
        this() {}
    }
    

    The compiler does not issue any warning/error on the above code samples and generates a normal constructor which is not ran before the main function. This leads to situations in which the compiler is not able to correctly indicate the problem:

    class A
    {
        static
        {
            this() {}
        }
    
        this() {}
    }
    
    void main()
    {
        new A();
    }
    

    This code will result in an error message indicating that there is a multiple definition of the constructor this() which is a misleading message.

    Beginning with this release, whenever a constructor is encountered in a static context an error message is emitted stating that the static keyword does not have any effect on the constructor. The solution is to declare the constructor outside the static block either as a normal constructor or a static one (static this()).

  3. Double initialization of immutable fields inside constructor is now obsolete

    Inside a constructor scope, assigning to aggregate declaration (class/struct) members is done by considering the first assignment as initialization and subsequent assignments as modifications of the initially constructed object. For const/immutable fields the initialization is accepted in the constructor, but subsequent modifications are not. Example:

    class A
    {
        int a;
        immutable int b;
        this(int a, int b)
        {
            this.a = a;
            this.b = b;
    
            this.a = 7; // OK, a is mutable
            this.b = 9; // Error: immutable field b initialized multiple times
        }
    }
    

    However, Bugzilla 18719 shows that this rule does not apply when inside a constructor scope there is a call to a different constructor:

    class A
    {
        immutable int a;
        this()
        {
            this(42);
            this.a = 5;  // second initialization of immutable field
        }
    
        this(int a)
        {
            this.a = a;
        }
    }
    

    The above code wrongfully compiled succesfully before this patch, accepting the double initialization of the immutable field a. Starting with this release, this.a = 5 will emit an error stating that a is initialized multiple times.

  4. add __traits(getLocation, symbol)

    Takes one argument which is a symbol. Returns a tuple(string, int, int) whose entries correspond to the filename, line number and column number where the argument was declared.

    To disambiguate between overloads, pass the result of getOverloads with the desired index, to getLocation:

    module m;
    int foo();
    int foo(int);
    enum loc = __traits(getLocation, __traits(getOverloads, m, "foo")[0]);
    
  5. Postblit and destructors are no longer called on members of anonymous unions.

    Due to a bug in dmd, members of anonymous unions inside struct declarations had their postblits/destructors called when an object of the containing struct type was copied/destroyed. With this release, the postblit/destructor is no longer called in such situations.

    Fixes: https://issues.dlang.org/show_bug.cgi?id=19122

Runtime changes

  1. core.atomic : msync has been removed

    It had been deprecated in 2.061 in favor of MemoryOrder.

  2. Non-POSIX CLOCK enum members have been removed from core.sys.posix.time

    Namely CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE (linux), CLOCK_MONOTONIC_PRECISE, CLOCK_MONOTONIC_FAST (FreeBSD, DragonflyBSD), and CLOCK_MONOTONIC_COARSE (CRuntime_Glibc). Those were deprecated in 2.067. They are available on their respective platform modules.

  3. core.sys.posix.dlfcn : dladdr, dlvsym, Dl_info have been removed

    They are linux extensions, not POSIX, and thus can be found in core.sys.linux.dlfcn. They had been deprecated since 2.063.

  4. core.exception: Remove onHiddenFuncError / HiddenFuncError

    Those have been deprecated since 2.068, and are related to a language feature that is long gone.

  5. core.exception : setAssertHandler has been removed

    It had been deprecated in 2.064 in favor of assertHandler.

  6. core.thread : Fiber.call(bool) has been removed

    This had been deprecated since 2.068 in favor of Fiber.call(Rethrow.[Yes|No]).

  7. Module core.sys.linux.sys.netinet.tcp has been removed

    This module had been deprecated since 2.077.0. core.sys.linux.netinet.tcp should be imported instead.

  8. core.runtime : Runtime.initialize, Runtime.terminate functions taking ExceptionHandler have been removed

    They were deprecated since 2.065 in favor of rt_init C functions, which allow to initialize the runtime from C code.

Library changes

  1. ErrnoException.errno is now nothrow pure @nogc @safe

    Before, it was just @system. As it turns out, all it does is return the value of an integer field, so it can have all these attributes.

  2. Nullable alias get this has been deprecated

    Nullable's feature of implicitly converting to its contained value has been marked deprecated.

    All sites where a Nullable!T is implicitly converted to T, potentially throwing an error at runtime, will now produce a deprecation warning or error with -de.

    To fix this, explicitly use .get to access the contained value of the Nullable.

    alias get this is the only implicit conversion in D that may throw an error. Since it is an implicit conversion, it can easily be used accidentally and lead to unexpected runtime errors. By explicitly invoking get, the developer acknowledges that the operation has a chance of error. Conversely, by not implicitly converting Nullable!T to T, the compiler gives the developer a chance to spot forgotten isNull checks.

    This feature will be removed after release 2.096.

  3. Added the std.file.getAvailableDiskSpace functionality.

    std.file.getAvailableDiskSpace receives as a parameter the path of a file or directory in the file system, and returns the available disk space on the mounted filesystem. If the given path is nonexistent, an exception is thrown.

    import std.file;
    ulong size = getAvailableDiskSpace(".");
    assert(size > 0);
    
    import std.file;
    assertThrown(getAvailableDiskSpace("NonExistentFile"));
    
  4. Allow std.json to overlook trailing comma

    The JSON grammar does not allow trailing commas, however they are accepted by many JSON parsers. std.json now ignores trailing commas as well. Use JSONOptions.strictParsing to disable this behavior.

    import std.json;
    import std.exception : assertThrown, assertNotThrown;
    
    // before
    assertThrown(parseJSON(`{ "a" : { } , }`));
    
    // after
    assertNotThrown(parseJSON(`{ "a" : { } , }`));
    

List of all bug fixes and enhancements in D 2.088.0:

DMD Compiler regressions

  1. Bugzilla 20057: compiler hang on conflicting local and imported template

DMD Compiler bugs

  1. Bugzilla 1142: .stringof performs semantic analysis
  2. Bugzilla 7443: Better diagnostic on wrongly written static constructor
  3. Bugzilla 9884: Refused initialization of const array in the module static this()
  4. Bugzilla 15795: bogus "conflicts with" error depending on order of declaration
  5. Bugzilla 15818: Multiple function declarations without definition cause ambiguity overloading error
  6. Bugzilla 18719: Doubly-called constructor against member when using forwarding constructors
  7. Bugzilla 19122: Postblits and destructors called on members of anonymous unions
  8. Bugzilla 19315: #line inside token string affect outside code
  9. Bugzilla 19534: Wrong error message "only one index allowed to index int"
  10. Bugzilla 19646: Initialization of globals not checked for @safe
  11. Bugzilla 19919: Incorrect initialization of union when first member isn't marked = void
  12. Bugzilla 19925: static opDispatch not considered in WithStatement
  13. Bugzilla 19931: Missing error message when defining postblit, rvalue constructor and copy constructor
  14. Bugzilla 20001: Error: a struct is not a valid initializer for a _error_
  15. Bugzilla 20047: call of static nested function ignores purity
  16. Bugzilla 20050: pure function should be able to return function pointer to impure static nested function

DMD Compiler enhancements

  1. Bugzilla 1252: Inline assembler could support BasicType properties
  2. Bugzilla 18665: Deprecate Undocumented Operator Overloads
  3. Bugzilla 19917: unions should require that all members are = void initialised
  4. Bugzilla 19969: Unhelpful error when attempting (incorrectly) to append to a string
  5. Bugzilla 20000: Casting to interfaces disallowed in @safe code
  6. Bugzilla 20037: Imports in module info should be deduplicated
  7. Bugzilla 20059: mismatched function return type inference should give location of inferred type

Phobos bugs

  1. Bugzilla 19823: std.algorithm.iteration.filter's popFront doesn't always pop the first element like it's supposed to
  2. Bugzilla 19980: File.byLine skips first line in some cases when used inside map!()
  3. Bugzilla 19986: Can't assign large const T to std.Variant.VariantN
  4. Bugzilla 19987: std.variantN wastes space

Phobos enhancements

  1. Bugzilla 16487: Add function to obtain the available disk space
  2. Bugzilla 19834: File exception for [std.file.copy] on windows shows the target file rather than the source file
  3. Bugzilla 19979: std.regex should return null instead of zero-length slice for non-matched captures
  4. Bugzilla 19983: Add fast path using slice assignment to std.internal.cstring.tempCString
  5. Bugzilla 19994: Can't nest self-referential Algebraic types

Druntime enhancements

  1. Bugzilla 19976: Simplify std.internal.convert.toUbyte CTFE path for float and double

dlang.org bugs

  1. Bugzilla 19944: Some examples on std.file docs page raise FileException

Contributors to this release (47)

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

previous version: 2.087.0