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

previous version: 2.086.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.087.0 comes with 15 major changes and 84 fixed Bugzilla issues. A huge thanks goes to the 72 contributors who made 2.087.0 possible.

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

Compiler changes

  1. Turn deprecation into error for privately imported symbols inside aggregate declarations

    With this release DMD will issue an error when a symbol that is privately imported in the scope of an aggregate declaration is used as a member of the aggregate outside of the module where the aggregate is defined. Example:

    // a.d
    class Foobar
    {
        int a;
        this(int a)
        {
            this.a = a;
        }
        static int smeth()
        {
            return 1;
        }
    }
    void fun() {}
    
    // b.d
    struct AST
    {
        import a;
    }
    
    // c.d
    void main()
    {
        import b;
        AST.Foobar t;        // triggered a deprecation, but will now trigger an error
        AST.Foobar.smeth();  // error
        AST.fun();           // error
    }
    
  2. Generated opEquals takes precedence over aliased this member opEquals

    Before this patch, if a struct had an aliased this member that defined an opEquals method, the aliased this opEquals would have been preferred instead of the struct one:

    struct A
    {
        int a, b;
        bool opEquals(ref A rhs) const
        {
            return a == rhs.a && b == rhs.b;
        }
    }
    
    struct B
    {
        int n;
        A a;
        alias a this;
    }
    
    void main()
    {
        B a, b;
        assert(a == b);    // rewritten to a.a.opEquals(b.a)
    }
    

    Although the compiler generates an opEquals for struct B that does member-wise equality comparison (==), the aliased this one is wrongfully preferred.

    This patch corrects this issue by always choosing the defined opEquals (even if it is generated by the compiler) instead of the alias this one. If the behavior prior to this patch is desired, an explicit opEquals needs to be provided.

    References: [1] https://issues.dlang.org/show_bug.cgi?id=16657 [2] https://github.com/dlang/dmd/pull/9289 [3] https://github.com/dlang/dlang.org/pull/2593

  3. Copy Constructor

    With this release, the D language compiler implements the full functionality of the copy constructor described extensively in this DIP [1].

    Copy constructors are used to initialize a struct instance from another struct of the same type.

    A constructor declaration is a copy constructor declaration if and only if it is a constructor declaration that takes only one non-default parameter by reference that is of the same type as typeof(this), followed by any number of default parameters:

    struct A
    {
        this(ref return scope A rhs) {}                        // copy constructor
        this(ref return scope const A rhs, int b = 7) {}       // copy constructor with default parameter
    }
    

    The copy constructor is type checked as a normal constructor.

    If a copy constructor is defined, implicit calls to it will be inserted in the following situations:

    1. When a variable is explicitly initialized:
    struct A
    {
        this(ref return scope A rhs) {}
    }
    
    void main()
    {
        A a;
        A b = a; // copy constructor gets called
    }
    

  4. When a parameter is passed by value to a function:
  5. struct A
    {
        this(ref return scope A another) {}
    }
    
    void fun(A a) {}
    
    void main()
    {
        A a;
        fun(a);    // copy constructor gets called
    }
    

  6. When a parameter is returned by value from a function and Named Returned Value Optiomization (NRVO) cannot be performed:
  7. struct A
    {
        this(ref return scope A another) {}
    }
    
    A fun()
    {
        A a;
        return a;       // NRVO, no copy constructor call
    }
    
    A a;
    A gun()
    {
        return a;       // cannot perform NRVO, rewrite to: return (A __tmp; __tmp.copyCtor(a));
    }
    
    void main()
    {
        A a = fun();
        A b = gun();
    }
    

    When a copy constructor is defined for a struct, all implicit blitting is disabled for that struct:

    struct A
    {
        int[] a;
        this(ref return scope A rhs) {}
    }
    
    void fun(immutable A) {}
    
    void main()
    {
        immutable A a;
        fun(a);          // error: copy constructor cannot be called with types (immutable) immutable
    }
    

    The copy constructor can be overloaded with different qualifiers applied to the parameter (copying from a qualified source) or to the copy constructor itself (copying to a qualified destination):

    struct A
    {
        this(ref return scope A another) {}                        // 1 - mutable source, mutable destination
        this(ref return scope immutable A another) {}              // 2 - immutable source, mutable destination
        this(ref return scope A another) immutable {}              // 3 - mutable source, immutable destination
        this(ref return scope immutable A another) immutable {}    // 4 - immutable source, immutable destination
    }
    
    void main()
    {
        A a;
        immutable A ia;
    
        A a2 = a;      // calls 1
        A a3 = ia;     // calls 2
        immutable A a4 = a;     // calls 3
        immutable A a5 = ia;    // calls 4
    }
    

    The inout qualifier may be applied to the copy constructor parameter in order to specify that mutable, const, or immutable types are treated the same:

    struct A
    {
        this(ref return scope inout A rhs) immutable {}
    }
    
    void main()
    {
        A r1;
        const(A) r2;
        immutable(A) r3;
    
        // All call the same copy constructor because `inout` acts like a wildcard
        immutable(A) a = r1;
        immutable(A) b = r2;
        immutable(A) c = r3;
    }
    

    A copy constructor is generated implicitly by the compiler for a struct S if all of the following conditions are met:

    1. S does not explicitly declare any copy constructors;
    2. S defines at least one direct member that has a copy constructor, and that member is not overlapped (by means of union) with any other member.

    If the restrictions above are met, the following copy constructor is generated:

    this(ref return scope inout(S) src) inout
    {
        foreach (i, ref inout field; src.tupleof)
            this.tupleof[i] = field;
    }
    

    If the generated copy constructor fails to type check, it will receive the @disable attribute.

    f an union S has fields that define a copy constructor, whenever an object of type S is initialized by copy, an error will be issued. The same rule applies to overlapped fields (anonymous unions).

    A struct that defines a copy constructor is not a POD.

    [1] https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1018.md

  8. HexString literals are now obsolete

    HexString literals are obsolete.

    Prior to this release, usage of hex string literals would emit a deprecation warning. Starting with this release they will emit an error.

    Use std.conv.hexString instead.

  9. Turn deprecation into error for selectively imported symbols in imported modules.

    With this release DMD will issue an error when a symbol that is privately and selectively imported in module A is accessed in module B that imports module A non-selectively. Example:

    // a.d
    import fun : foo;
    
    // b.d
    import a;
    
    void main()
    {
        foo();     // deprecation up until now; error from now on
    }
    

    To make the above code compile, the import in a.d needs to be made public.

  10. Function literals can now return by reference

    Prior to this release, there was no way to declare a function that would return a reference by using an anonymous function.
    (It was possible to return a pointer but it's not worth mentioning.)

    Here this function returns by value:

    alias fn = () => a += 2;
    

    In order to return by reference, we needed to define a named function to assign from:

    ref int func()        // a static or non-nested function to mimic a `function` literal
    {                     // or a non-static nested function to mimic a `delegate` literal
        return a += 2;
    }
    alias fn = func;
    

    Now it's possible to use the ref keyword to indicate a return by reference:

    function ref () { return x; }    // `=>` shorthand is there too
    delegate ref () { return x; }
    ref () { return x; }
    

    For example:

    int x = 1;
    alias add2 = ref () => x += 2;
    add2() += 7;    // add2 as a lvalue
    assert(x == 10);
    
  11. New command-line option -lowmem to reduce compiler memory requirements

    It enables the garbage collector for the compiler, trading compile times for (in some cases, significantly) less memory requirements.

    E.g., compiling DMD's test tool d_do_test (dmd -c [-lowmem] test/tools/d_do_test.d) requires about 75% less memory (~1,630 MB -> 410) at the cost of a runtime increase by ~30% (~4.8 secs -> 6.3).

  12. Enable private member access for traits

    The following traits can now access non-public members:

    • getMember
    • getOverloads

    This fixes a long-standing issue in D where the allMembers trait would correctly return non-public members but those non-public members would be inaccessible to other traits.

    See BugZilla issue 15371

Runtime changes

  1. New module core.sync.event

    This module provides a cross-platform interface for lightweight signaling of other threads. It can be used to start execution of multiple waiting threads simultaneously.

Library changes

  1. Fixed comparison bug in std.algorithm.comparison.levenshteinDistance

    Previously the algorithm was allocating the amount of memory which was equal to the size of the biggest range, that is Ο(max(s.length, t.length)). This is now fixed to be Ο(min(s.length, t.length)). For more details see std.algorithm.comparison.levenshteinDistance.

  2. std.experimental.all has been moved to std

    std.experimental.all allowed the convenient use of all Phobos modules with one import (import std.experimental.all;). With this release, this convenience module has been stabilized and moved to std. From now on, the convenience module can be accessed with import std;:

    import std;
    void main()
    {
        5f.iota.map!exp2.sum; // 31
    }
    

    Scripts and experimental code often use long and frequently changing lists of imports from the standard library.

    With this release it is possible to use import std; for importing the entire standard library at once. This can be used for fast prototyping or REPLs:

    import std;
    void main()
    {
        6.iota
          .filter!(a => a % 2) // 1 3 5
          .map!(a => a * 2) // 2 6 10
          .tee!writeln // peek into the processed stream
          .substitute(6, -6) // 2 -6 10
          .mean // (2 - 6 + 10) / 3
          .reverseArgs!writefln("Sum: %.2f"); // 2
    }
    

    As before, symbol conflicts will only arise if a symbol with collisions is used. In this case, static imports or renamed imports can be used to uniquely select a specific symbol.

    The baseline cost for import std; is less than half a second (varying from system to system) and work is in progress to reduce this overhead even further.

Installer changes

  1. The bundled LLD Linker has been upgraded to 8.0.0

    The bundled LLD Linker on Windows binaries has been upgraded to 8.0.0.

Dub changes

  1. Builds dynamicLibrary targets as dynamic libraries instead of static libraries.

    Dub will no longer build dynamicLibrary targetType's as staticLibrary.

    Except for x86_omf. This has been disabled due to numerous issues that will lead this to not doing what is expected of it.

    No compiler or linker flags have been added at this time, you will need to specify the relevant flag to get the compiler to link dynamically against Phobos.

  2. The $DUB_BUILD_PATH variable was added

    The $DUB_BUILD_PATH variable is now defined inside the postBuildCommands section. It contains the absolute path in which the package was built, and can be used to copy by-products of the build process to their intended locations.

    For example, if an executable exports symbols, you will want to make the resulting import library and symbols export file available somewhere. That can be done with a dub.json section like this:

        "postBuildCommands-windows": [
            "copy /y $DUB_BUILD_PATH\\$DUB_TARGET_NAME.lib $PACKAGE_DIR\\lib"
            "copy /y $DUB_BUILD_PATH\\$DUB_TARGET_NAME.exp $PACKAGE_DIR\\lib"
        ],
    
  3. Command environment variable substitution changed

    Now users can use the documented predefined variables inside custom command directives without the need for a wrapper shell script.

    Before this would have failed: ```json "preBuildCommands": ["$DC -run foo.d"] ``` unless DC was defined as environment variable outside DUB.

    It was before possible to run a script that used the $DC environment variable or on POSIX escape the $ with $$DC to make the shell substitute the variable. These workarounds are no longer needed now.

    API change: none of the different command directives are no longer substituted with the process environment variables. You now access the raw commands as provided by the user in the recipe. dub describe has been adjusted and now also processes the predefined environment variables as well as the process environment variables.


List of all bug fixes and enhancements in D 2.087.0:

DMD Compiler regressions

  1. Bugzilla 19584: Illegal optimization: Shift-or -> imul
  2. Bugzilla 19631: Segfault on simple nested templated struct
  3. Bugzilla 19661: DMD 2.084.0 SIGSEGV in std.traits.isFunction
  4. Bugzilla 19758: (0x01 & 0xFF) == 0 by dmd 2.085.0(-m64) on Windows
  5. Bugzilla 19871: Copy constructor rejects valid code if default construction is disabled
  6. Bugzilla 19887: Segfault with void tuple default parameter
  7. Bugzilla 19901: importing export symbols causes link errors
  8. Bugzilla 19936: Deprecated alias get this falsely triggers on appending to array

DMD Compiler bugs

  1. Bugzilla 711: combining mixins and overriding causes inifite loops
  2. Bugzilla 1170: Cannot forward reference a type defined in a MixinStatement
  3. Bugzilla 4923: immutable module variables are modifiable in non-shared module constructors
  4. Bugzilla 6541: using synchronized on a templated method crashes the compiler
  5. Bugzilla 9029: Built-in types treated specially for alias parameters
  6. Bugzilla 10739: Struct defined by template mixin leads to order-sensitivity of declarations
  7. Bugzilla 12950: Lexer interprets UFCS on hex integer as hex float literal
  8. Bugzilla 13471: CTFE glitch when executing std.digest.crc.crc32Of() and checking the result with enforce(). (keyword: uninitialized variable)
  9. Bugzilla 13819: ICE: backend\cg87.c with -O: "a % 2 != 0" for a double
  10. Bugzilla 13848: overlapping initialization for r
  11. Bugzilla 17141: Type Inference Incorrectly Converts Characters to Integers
  12. Bugzilla 17258: Pass by name doesn't work reliably and can sometimes lead to memory corruption
  13. Bugzilla 17793: [ICE] Internal error: ddmd/backend/cod1.c 3976 using simd.double4
  14. Bugzilla 18772: [ICE] Internal error: dmd\backend\cgcod.c 607 no optimizations
  15. Bugzilla 18784: Segfault due to dmd codegen interfacing with C++
  16. Bugzilla 18794: Compiling with -O causes runtime segfault
  17. Bugzilla 18958: extern(C++) wchar, dchar mangling not correct
  18. Bugzilla 19002: __FUNCTION__ and __PRETTY_FUNCTION__ cannot be used as C string literals
  19. Bugzilla 19234: betterC TypeInfo error when using slice copy on Structs
  20. Bugzilla 19386: Destructor not called when constructed inside if condition, leading to memory leak
  21. Bugzilla 19557: extern(C++, ns) and extern(C++, class) interact weird
  22. Bugzilla 19713: dmd crashes generating code for C++ template function
  23. Bugzilla 19754: cast() sometimes yields lvalue, sometimes yields rvalue
  24. Bugzilla 19813: Generated bt instruction seg faults, high 32 bits of register is garbage
  25. Bugzilla 19814: Nested code blocks in Ddoc break formatting
  26. Bugzilla 19825: Memory corruption involving lazy variadic, stdio and json
  27. Bugzilla 19829: __traits(isSame) returns true for some non-local delegate lambdas even when they are different
  28. Bugzilla 19831: throw/catch in scope(exit) crashes with illegal instruction
  29. Bugzilla 19857: Name mangling mismatch when compiling with -dip1000
  30. Bugzilla 19870: Generated Copy Constructor disables default construction
  31. Bugzilla 19881: Escaping reference to local through return scope with -dip1000 and @safe
  32. Bugzilla 19888: default parameters in templates with tuple parameters+defaults are thrown away
  33. Bugzilla 19890: ICE: Segmentation fault with negative array size
  34. Bugzilla 19891: Confusing error message for auto ref parameters with default values
  35. Bugzilla 19893: extern(C++, "ns") should count as module scope for version declarations
  36. Bugzilla 19895: Floating point exception casting zero length array
  37. Bugzilla 19897: dinterpret.d:6439: Internal Compiler Error: null field
  38. Bugzilla 19898: ICE: in sizemask at dmd/mtype.d(2563): Assertion failure
  39. Bugzilla 19905: Floating point .init should be bitwise identical to .nan
  40. Bugzilla 19911: ICE: Segmentation fault with struct object and variadic function
  41. Bugzilla 19912: [module] No implicit import of object module when an object declaration exists.
  42. Bugzilla 19913: ICE: Segmentation fault with mixin and enum
  43. Bugzilla 19914: ICE: Segmentation fault with mixin and templated class
  44. Bugzilla 19915: ICE: Segmentation fault with alias and templated class
  45. Bugzilla 19920: __trait(parent, ...) broken with extern(C++,"ns") nested in scopes
  46. Bugzilla 19922: ICE: Segmentation fault with typeid()
  47. Bugzilla 19923: ICE: typesem.d(3809): Assertion failure with .classinfo
  48. Bugzilla 19941: [ICE] Segmentation fault in ImplicitConvTo::visit(AddrExp*) at dmd/dcast.d(980)
  49. Bugzilla 19942: [ICE] Segmentation fault in resolvePropertiesX at dmd/expressionsem.d:1112
  50. Bugzilla 19954: ICE: Casting AliasSeq to array and passing to a function
  51. Bugzilla 19955: [ICE] Segmentation fault in StatementSemanticVisitor::visit(SwitchStatement*) at dmd/statementsem.d:2558
  52. Bugzilla 19971: wrong string literals in "cannot pass argument" errors
  53. Bugzilla 19995: parameter attributes are accepted in parameter-less functions

DMD Compiler enhancements

  1. Bugzilla 10665: The documentation produced by ddoc should clearly list all public imports of a module
  2. Bugzilla 16002: Add __traits(isModule) and __traits(isPackage)
  3. Bugzilla 16020: Allow AliasDeclarationY to express function types
  4. Bugzilla 19856: [aApplycd2]: foreach (int) doesn't work on BigEndian targets

Phobos regressions

  1. Bugzilla 17358: [REG 2.074.0] std.stdio.File.lockingTextWriter.put no longer accepts chains of characters
  2. Bugzilla 19740: Incorrect result of BigInt * BigInt

Phobos bugs

  1. Bugzilla 11061: std.variant.Variant equality comparison always returns false for static array literals.
  2. Bugzilla 19226: std.typecons.Nullable(T, T nullValue) doesn't fully handle non-self-equal nullValue
  3. Bugzilla 19781: etc.c.zlib should be @nogc
  4. Bugzilla 19836: Excessive probability of UUID collisions in std.uuid.randomUUID
  5. Bugzilla 19837: std.random.isUniformRNG(Rng, ElementType) should not require Rng.front to be annotated @property
  6. Bugzilla 19850: double nested joiner .back falsely thinks the range is empty
  7. Bugzilla 19883: Cyclic constructor call for BigInt(dstring)
  8. Bugzilla 19899: std.bitmanip.bitsSet should accept const arguments
  9. Bugzilla 19939: std.format %13,3.2f does not count width correctly

Phobos enhancements

  1. Bugzilla 6657: dotProduct overload for small fixed size arrays
  2. Bugzilla 13965: More handy schwartzSort
  3. Bugzilla 19513: Use sched_getaffinity(2) to get the number of CPU cores if available
  4. Bugzilla 19892: Add CTFE support for std.bitmanip: nativeToBigEndian, bigEndianToNative, littleEndianToNative, nativeToLittleEndian

Druntime regressions

  1. Bugzilla 19701: undefined reference to `_D6object__T6hashOf

Druntime bugs

  1. Bugzilla 17248: Multiple wrong function definitions in core.sys.windows.winldap (causing runtime issues)
  2. Bugzilla 19847: no GC memory above 4GB reported with --DRT-gcopt=profile:1
  3. Bugzilla 19861: core.cpuid reports the wrong number of threads

Contributors to this release (72)

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

previous version: 2.086.0