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

previous version: 2.085.1 – next version: 2.086.1

Download D 2.086.0
released May 04, 2019

2.086.0 comes with 17 major changes and 69 fixed Bugzilla issues. A huge thanks goes to the 51 contributors who made 2.086.0 possible.

List of all bug fixes and enhancements in D 2.086.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:
    2. struct A
      {
          this(ref return scope A rhs) {}
      }
      
      void main()
      {
          A a;
          A b = a; // copy constructor gets called
      }
      
    3. When a parameter is passed by value to a function:
    4. struct A
      {
          this(ref return scope A another) {}
      }
      
      void fun(A a) {}
      
      void main()
      {
          A a;
          fun(a);    // copy constructor gets called
      }
      
    5. When a parameter is returned by value from a function and Named Returned Value Optiomization (NRVO) cannot be performed:
    6. 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

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

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

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

  8. 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. Support of custom dub init type

    Command dub init now supports custom dub packages for argument -t.

    > dub init -n myPackage --format sdl -t custom-dub-init-dubpackage -- --foo=bar
    

    Dub init will be invoked like before. The package custom-dub-init-dubpackage contains a sub package init-exec which will be invoked afterwards to create a custom package skeleton. Additional arguments could be passed e.g. -- --foo=bar.

  2. DUB will no longer use OPTLINK as default on Windows

    DMD's OPTLINK has many limitations. Apart from long-standing issues in the underlying DigitalMars runtime, the maximum number of symbols is limited as well, which is why most big DUB libraries can't be compiled with OPTLINK for years. This has been a cause of grief and pain for many users and impacted the newcomer experience severly.

    With this release, dub will no longer use OPTLINK as default on Windows, but use -m32mscoff (MSCOFF) on 32-bit Windows systems and -m64 (MSCOFF) on 64-bit Windows.

    Users can still manually instruct dub to use OPTLINK with the --arch=x86 switch of dub:

    > dub --arch=x86
    

  3. dub run will now automatically fetch a package if it's not found locally

    Starting with this release, dub run <mypackage> makes sure that the package is available locally. This means that now a dub fetch <mypackage> is no longer required and all a user of a library needs to run your dub package is dub run:

    > dub run gitcompatibledubpackage
    gitcompatibledubpackage wasn't found locally, but it's available online:
    ‐--
    Description: Example of a DUB package also usable as git submodule. For DUB test suite.
    Version: 1.0.4
    ‐--
    Do you want to fetch gitcompatibledubpackage? [Y/n]:
    

    An optional --yes (-y) flag is provided to confirm fetching non-interactively:

    > dub run --yes gitcompatibledubpackage
    gitcompatibledubpackage wasn't found locally, but it's available online:
    ‐--
    Description: Example of a DUB package also usable as git submodule. For DUB test suite.
    Version: 1.0.4
    ‐--
    Fetching gitcompatibledubpackage 1.0.4...
    Building package gitcompatibledubpackage in /home/seb/.dub/packages/gitcompatibledubpackage-1.0.4/gitcompatibledubpackage/
    Performing "debug" build using dmd for x86_64.
    gitcompatibledubpackage 1.0.4: building configuration "exe"...
    Linking...
    Running ../../.dub/packages/gitcompatibledubpackage-1.0.4/gitcompatibledubpackage/gitcompatibledubpackage
    Hello DUB
    

    An optional --non-interactive (-n) flag is provided to skip searching online packages:

    > dub run --non-interactive gitcompatibledubpackage
    Failed to find a package named 'gitcompatibledubpackage'.
    

    If one wants to run a specific version of a package, it can be passed to dub run too:

    > dub run [email protected]
    Fetching gitcompatibledubpackage 1.0.3...
    Building package gitcompatibledubpackage in /home/seb/.dub/packages/gitcompatibledubpackage-1.0.3/gitcompatibledubpackage/
    Performing "debug" build using dmd for x86_64.
    gitcompatibledubpackage 1.0.3: building configuration "exe"...
    Linking...
    Running ../../.dub/packages/gitcompatibledubpackage-1.0.3/gitcompatibledubpackage/gitcompatibledubpackage
    Hello DUB
    

  4. Remove dub list-installed command

    dub list-installed command was deprecated and renamed to list at in 2013.

  5. DUB uses single API requests to upgrade/resolve dependencies.

    dub now uses single API request to upgrade/resolve dependencies. For more details, see pull #1366.


List of all bug fixes and enhancements in D 2.086.0:

DMD Compiler regressions

  1. Bugzilla 17684: [REG 2.062] static alias this bug or incomplete implementation?
  2. Bugzilla 18810: root/ctfloat depends upon backend
  3. Bugzilla 19519: cannot determine length of static array at compile time
  4. Bugzilla 19691: ICE on null default value for struct parameter in constructor
  5. Bugzilla 19722: botched implementation of semantic3Errors causes compiler assert fail
  6. Bugzilla 19774: wrong code caused by opIndex
  7. Bugzilla 19778: ICE when accessing empty array at compile time
  8. Bugzilla 19782: alias this appends null instead of inner/aliased element to array
  9. Bugzilla 19804: fails to compile with fixes size array T[1]... argument
  10. Bugzilla 19822: 2.086 regression wrt. union initializers
  11. Bugzilla 19833: The member as template cannot be acquired by getMember
  12. Bugzilla 19840: Ice in e2ir.d visit(CastExp) assert(false, "This case should have been rewritten to __ArrayCast in the semantic phase");

DMD Compiler bugs

  1. Bugzilla 5050: No way to declare delegates with ref return
  2. Bugzilla 10806: Interface covariance for more than one interface at once also broken
  3. Bugzilla 11934: Allow ref in foreach over range iff front returns by ref
  4. Bugzilla 15875: case of undetected circular reference in function parameter
  5. Bugzilla 17285: Segfault when types are used in array literals
  6. Bugzilla 17289: With Xcode 8.3 linker, warnings of "pointer not aligned"
  7. Bugzilla 17290: DMD crash due to circular reference in function return type
  8. Bugzilla 17651: Segfault when parsing Ddoc ESCAPES macro
  9. Bugzilla 18573: cast(void) leads to floating point return value not being popped from FPU stack
  10. Bugzilla 19051: Undefined functions Set/GetWindowLongPtr in mingw libs
  11. Bugzilla 19099: Struct with field that has postblit or destructor makes struct assignable
  12. Bugzilla 19442: multiple argument string mixin dont support char literals
  13. Bugzilla 19463: DIP1008 - _d_newclass is called instead of _d_newThrowable
  14. Bugzilla 19540: ICE when using typeof(new class {}) as default value for template parameter
  15. Bugzilla 19563: extern(C++) Incorrect ABI passing small struct
  16. Bugzilla 19569: overload resolution not right?
  17. Bugzilla 19658: C++ enum mangling is wrong on Windows for other integer types
  18. Bugzilla 19679: variable escapes unnoticed when referenced in function called from function whose address is taken
  19. Bugzilla 19688: [ICE] Default function argument concatenation crashes DMD
  20. Bugzilla 19717: case of segfault due to undetected forward reference
  21. Bugzilla 19719: Debugging string mixins using -mixin doesn't work
  22. Bugzilla 19731: auto struct methods whose address is taken don't test invariants
  23. Bugzilla 19734: isDataseg returns true for non-static declarations
  24. Bugzilla 19735: Error: variable extern symbols cannot have initializers
  25. Bugzilla 19744: Confusing error message when annotating a non-member function with return
  26. Bugzilla 19747: No debug line info for code in scope(exit)
  27. Bugzilla 19775: multiple argument string mixin doesn't expand tuples
  28. Bugzilla 19797: File.seek() terminates ungracefully on incorrect origin for -m32mscoff and -m64

DMD Compiler enhancements

  1. Bugzilla 8065: No way to write function/delegate literals returning ref T
  2. Bugzilla 12330: array.reserve at compile time too
  3. Bugzilla 15361: Incomprehensible error message: function declaration without return type.
  4. Bugzilla 15371: __traits(getMember) should bypass the protection
  5. Bugzilla 16271: Should be able to express that a lambda returns by reference
  6. Bugzilla 16657: alias this interacts with generated opCmp and opEquals
  7. Bugzilla 18825: No syntax for function literal returning a reference
  8. Bugzilla 19441: alias this causes partial assignment
  9. Bugzilla 19809: override block affects passing lambda as argument

Phobos regressions

  1. Bugzilla 19777: [REG2.086a] SortedRange.opSlice is wrongly @trusted

Phobos bugs

  1. Bugzilla 18728: std.math.fdim does not handle nan correctly
  2. Bugzilla 19042: Chunking a padRight'ed range leads to range violations
  3. Bugzilla 19151: std.utf.toUTF16z() can not be used for LPWSTR
  4. Bugzilla 19681: std.range.padRight.popFront does not correctly adjust length
  5. Bugzilla 19689: large types cannot be moved
  6. Bugzilla 19751: std.stdio.File should not retry fclose after error
  7. Bugzilla 19799: templated string formatting fails with const Nullable!string
  8. Bugzilla 19806: phobos/std/uri.d: ietf link outdated

Phobos enhancements

  1. Bugzilla 15853: std.random save methods must be const
  2. Bugzilla 18806: minIndex should be able to take an input range but does not
  3. Bugzilla 19412: std.algorithm.cmp with default ordering can use memcmp for all size 1 unsigned types (instead of just char)
  4. Bugzilla 19686: sgn is too greedy

Druntime regressions

  1. Bugzilla 18530: [Reg 2.079] src/rt/tracegc.d(43): Deprecation: The delete keyword has been deprecated
  2. Bugzilla 19796: druntime PR#1982 broke array ops on double[] due to wrong assumption of integral element type

Druntime bugs

  1. Bugzilla 19810: destroy does not work for C++ classes without destructor
  2. Bugzilla 19830: core.memory.__delete destructs arrays of structs in the wrong order

dlang.org bugs

  1. Bugzilla 11161: Document the default struct equality comparison and operator overloading
  2. Bugzilla 19621: The specification is self-contradictory on immutability

Installer regressions

  1. Bugzilla 18522: [REG 2.079-b2] MinGW import libraries interfere with platform SDK

Contributors to this release (51)

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

previous version: 2.085.1 – next version: 2.086.1