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

previous version: 2.093.1

Download D 2.094.0
released Sep 22, 2020

2.094.0 comes with 21 major changes and 119 fixed Bugzilla issues. A huge thanks goes to the 49 contributors who made 2.094.0 possible.

List of all bug fixes and enhancements in D 2.094.0.

Compiler changes

  1. Add __traits(child, parent, member)

    Takes two arguments. The first must be a symbol or expression and the second must be a symbol, such as an alias to a member of parent. The result is member interpreted with its this context set to parent. This is the inverse of __traits(parent, member).

    struct A
        int i;
        int foo(int j) {
            return i * j;
    alias Ai = A.i;
    void main()
        A a;
        __traits(child, a, Ai) = 3;
        assert(a.i == 3);
        assert(__traits(child, a, == 6);
  2. Improve type determination for array literals

    There were some cases where DMD wasn't able to determine the common type for array literal elements. Mismatched enums and literals containing only mutable and immutable elements should now be correctly inferred.

  3. Template usage diagnostics via -vtemplates has been improved.

    Every template having at least one instantiation is now printed using standard compiler diagnostics formatting for easy navigation to the point of its declaration.

    All messages of this kind are sorted by descending unique instantiation count.

    If the flag argument list-instances is passed (such as -vtemplates=list-instances), each location where a template was instantiated is printed along with the reason for the instantiation (implicit or explicit).

    For instance, a D source file named main.d containing

    void foo(int I)() { }
    void goo1(int I)() { }
    void goo2(int I)() { goo1!(I); }
    void test()

    compiled with -vtemplates=list-instances will output

    main.d(1): vtemplate: 3 (2 unique) instantiation(s) of template `foo(int I)()` found, they are:
    main.d(7): vtemplate: explicit instance `foo!1`
    main.d(8): vtemplate: explicit instance `foo!1`
    main.d(9): vtemplate: explicit instance `foo!2`
    main.d(2): vtemplate: 2 (1 unique) instantiation(s) of template `goo1(int I)()` found, they are:
    main.d(11): vtemplate: explicit instance `goo1!1`
    main.d(3): vtemplate: implicit instance `goo1!1`
    main.d(3): vtemplate: 1 (1 unique) instantiation(s) of template `goo2(int I)()` found, they are:
    main.d(13): vtemplate: explicit instance `goo2!1`
  4. C++ header generation omits Ignored ... comments by default

    The C++ header generated used to write comments when it encountered non-extern(C++) declarations, e.g.

    // test.d
    void foo() {}
    // test.h
    // ignoring function because of linkage

    This caused a lot of bloat in the generated header file and is now customizable via the `-HC= switch which accepts either verbose (write comments) and silent (omit comments). The default was changed to silent.

    Note: The header generator is still considerer experimental, so please submit any bugs encountered to the bug tracker.

  5. Exception-throwing code can now be used in debug blocks

    When writing debug code, one isn't interested statically ensuring that a function block doesn't throw, but a pleasant debugging experience as e.g. writing to the console or logfiles typically can't be nothrow. DMD already allowed to escape pure and @nogc within debug statement. With this release, exception-throwing code can be called from debug statements too:

    import std.stdio;
    void main() nothrow
        debug writeln("Your throwing log statement.");
  6. Always inline pragma(inline, true) functions regardless of -inline compiler switch.

    Marking a function with pragma(inline, true) will now cause it to be always inlined when called, and a compile error will result if it cannot be inlined.

    If the pragma(inline, true) is embedded in the function body rather than outside it, it may not always take effect. (It depends on whether the function body is analyzed before it is called or not.)

    If a function marked with pragma(inline, true) cannot be inlined it will now issue a warning if and only if the -wi command line switch is given. Previously, it would issue an error.

  7. The deprecation period for implicit override has ended

    Implicit overrides of base classes methods were deprecated in 2.075.0 (released 2017-07-19) when issue 17349 was fixed by PR 6731.

    The deprecation period has now ended and the following code will always error from now:

    class Base
        void myFunction();
        void myOtherFunction(void* ptr);
    class Child : Base
        // Error: Implicitly overriding `Base.myFunction`
        void myFunction() const;
        // Error: Implicitly overriding `Base.myOtherFunction(void*)`
        void myOtherFunction(const void* ptr);
  8. Strict implicit conversion rules for Vector types

    Previously, the compiler allowed any __vector type to be implicitly convertible with any other __vector type.

    int4 x = 2;
    float8 y = x;
    short8 z = y / 3;

    In this release, __vector types now, like static arrays, can only be implicitly converted to either qualified types of itself, or void.

    const int4 a = 5;
    int4 b = a;         // OK, both are int4
    void16 c = a;       // OK, cast to void of same size.
    float4 d = b;       // Error, cannot implicitly convert int4 to float4.

    Explicit conversions between __vector types can be done, but only between vectors of the same size.

    long2 a = 8;
    short8 b = cast(short8)a;   // OK
    short16 c = cast(short16)b; // Error, cannot cast because of different sizes.

    Users of the __simd and __simd_sto intrinsics will have to either add explicit casts from void16 to the appropriate type at each use, or operate strictly with void16 vectors until a value is required to be peeked.

    float4 fun1(float4 a, float4 b)
        a = cast(float4)__simd(XMM.ADDPD, a, b);
        a = cast(float4)__simd(XMM.ADDSS, a, b);
        return a;
    float4 fun2(void16 a, void16 b)
        a = __simd(XMM.ADDPD, a, b);
        a = __simd(XMM.ADDSS, a, b);
        return cast(float4)a;
  9. Parameters marked as in will now be properly displayed

    In earlier releases, using in on parameters would be lowered too early, leading to confusing display: error messages would show the parameter as const (or scope const if -preview=in was used), and so would header generations or stack traces. The header generation was problematic, as a header generated with -preview=in would be different from one generated without. From this release, in will now display correctly in every message. As this requires an update to the mangling, some older debuggers or tools might not be able to properly demangle functions that uses in parameters.

  10. DDoc Markdown support has been enabled by default

    Ddoc's Markdown has now been enabled by default. The full list of supported Markdown features (headings, emphasized text, links, and more) is described in the Ddoc documentation page.

    For the more cautious, a list of all instances of Markdown features can be logged with -transition=vmarkdown. If you encounter issues with this transition, you can temporarily disable the processing of the Markdown features with -revert=markdown and report an issue.

    A huge thanks goes to David Gileadi for championing this issue!

  11. Added support for input parameters (in parameter, -preview=in)

    D has supported the in, ref, and out storage classes on parameters since its inception. out and ref are commonly used, however in was usually left behind, as, while it was originally intended as an alias to const scope, it was made an alias to const when support for scope was introduced (DIP1000).

    DMD v2.092.0 rectified this by adding -preview=in to mean const scope, as it was originally intended, instead of const without the switch.

    However, this didn't really capture the intended meaning of in: the be applied on input parameters. Input parameters are parameters that a function intend to only examine, without modifying it, nor keeping a reference to them around. This is covered by const scope. However, some input parameters can be pretty large, or copying them can have side effects (postblit, copy constructor), hence those should be passed by reference to avoid runtime overhead. Which prompts a new issue: D doesn't support passing rvalues by references. Hence, when designing an API accepting an input parameter, a common practice was to have both an in-accepting overload, and an in ref-accepting one. While this works well for a single parameter, it also suffers from combinatorial explosion.

    This release reworks the meaning of in to properly support all those use cases. in parameters will now be passed by reference when optimal, and will accept rvalue. When using the switch, in ref parameters will also trigger an error.

    Note that the rules for passing by reference are as follow:

    • If the type has an elaborate copy or destruction (postblit, copy constructor, destructor),
    the type is always passed by reference.
    • If the type is not copy-able, it will always be passed by reference.
    • Reference types (dynamic arrays, function pointers, delegates, associative arrays, classes) do not get passed by ref. This allows for covariance on delegates.
    • Otherwise, if the type's size requires it, it will be passed by reference. Currently, types which are over twice the machine word size will be passed by reference, however this is controlled by the backend and can be changed based on the platform's ABI.

  12. Usage of vector types and operations on an unsupported -mcpu= will now error

    Previously, the compiler accepted the following code as being supported by all -mcpu= types on both OSX 32-bit and all 64-bit targets.

    __vector(long[4]) x;    // AVX type
    x += 1;                 // AVX2 operation

    In this release, all __vector types and operations now check the current CPU being targeted for, and will issue an error if there is insufficient support.

    This also allows for conditional compilation using __traits(compiles) to probe which operations are supported at compile-time.

    static if (__traits(compiles, long4))
        // Compiled in if `-mcpu=avx` or higher
    static if (__traits(compiles, { int4 x; x += 1; }))
        // Compiled in if `-mcpu=baseline` or higher
    static if (__traits(compiles, { int4 x; x *= 1; }))
        // Compiled in if `-mcpu=avx` or higher
    static if (__traits(compiles, { int8 x; x += 1; }))
        // Compiled in if `-mcpu=avx2` or higher

    The following tables describe what minimum -mcpu= level is required.

    Minimum Required -mcpu= for 128-bit Vector Types

    Minimum Required -mcpu= for 128-bit Vector Operators

    Minimum Required -mcpu= for 256-bit Vector Types

    Minimum Required -mcpu= for 256-bit Vector Operators

Runtime changes

  1. Equality of arrays of structs is consistent again, as before v2.078

    Since v2.078, some array equality comparisons (e.g., if both arrays are dynamic arrays) have been wrongly using a .tupleof comparison for structs without custom opEquals, basically enforcing -preview=fieldwise for these array comparisons.

    union U
        string s;
    void main()
        static immutable from = "from", from2 = "from2";
        U[] a = [{ s : from }];
        U[1] b = [{ s : from2[0..4] }];
        assert(a[0] != b[0]);
        assert(a != b);
        assert(a != b[]); // worked before v2.078, been failing since, now working again
  2. core.memory.GC.allocatedInCurrentThread() was added, which makes -profile=gc faster

    The new function core.memory.GC.allocatedInCurrentThread() returns the same as core.memory.GC.stats().allocatedInCurrentThread, but is faster, because it avoids calculating other statistics. It is used for -profile=gc and makes it faster, too.

Installer changes

  1. Installation script now supports get-path <compiler>

    get-path <compiler> has been added as a new action to the install script. This action allows printing information about a compiler binary. The behavior of get-path can be changed with the following additional options:

    • --install install compiler if not found locally
    • --dmd returns the path of a specific compiler executable (DMD-alike interface)
    • --dub returns the path of the DUB executable


    curl | bash -s get-path --install

    ~/dlang/ get-path ldc-1.23.0 --install

    ~/dlang/ get-path --dmd ldc --install

    ~/dlang/ get-path --dub ldc --install

    ~/dlang/ get-path --dub dub-1.22.0 --install

    ~/dlang/ get-path --dub ldc,dub-1.22.0 --install

    If a compiler installation isn't found and --install has not been passed, an error will be issued.

  2. DMD binary releases are now built with LDC

    Binary releases for Linux, OSX, and FreeBSD are now built with LDC. This follows the switch to LDC as host compiler for Windows releases with 2.091.0.

    Building DMD with LDC should provide a significant speedup of the compiler (20-30%).

    This change comes with the following limitations:

    • no more FreeBSD 32-bit binary releases (no 32-bit LDC host compiler)
    • additional binary tools copied over from previous dmd releases are no longer included (see c0de0295e6b1f9a802bb04a97cca9f06c5b0dccd (optlink still included)) They are still available via or from older dmd releases.

Dub changes

  1. Added architecture x86_omf for windows-dmd

    On windows dmd the x86_omf architecture can now be used as platform specification using --arch=x86_omf. This is currently equivalent to the previously existing --arch=x86 argument.

  2. dub remove --non-interactive will now remove all packages by default

    When calling a command with a package name and no version specification, the latest version is usually assumed. While this behavior makes sense for dub fetch or dub run, it can come as a surprise when cleaning up local packages through dub remove, and so previous version would simply error out when more than one version was available. From this version, dub remove -n $PKGNAME will just remove all cached versions of the package named $PKGNAME, without asking you to use $PKGNAME@*.

  3. Running dub upgrade on a package-less folder is now a no-op

    Prior to this change, accidentally running dub upgrade in a folder where no dub.json / dub.sdl was present would leave you with a dub.selections.json and, in some instances, an empty .dub folder. This has been fixed and running dub upgrade where one shouldn't will now only generate a friendly error message.

  4. Support dependencies as git url with exact commit

    Git repositories can be directly used by dub as dependencies.


        "name": "git-dependency",
        "dependencies": {
            "gitcompatibledubpackage": {
                "repository": "git+",
                "version": "ccb31bf6a655437176ec02e04c2305a8c7c90d67"
  5. All commands now support package[@<version-spec>], --version is deprecated

    dub commands had some disparity in their version handling. Most commands accepting a package name (e.g. dub fetch or dub run) supported either package[@version-spec], or supported only package and accepted an option --version=<version-spec>. The latter form has now been deprecated and all commands now accept package[@<version-spec>]. Note that the absence of @<package-spec> still means "latest version" (except for remove).

List of all bug fixes and enhancements in D 2.094.0:

DMD Compiler regressions

  1. Bugzilla 18412: [REG2.077.0] immutable array in library becomes null when referenced in static constructor
  2. Bugzilla 19476: explicit mixin template function call results in recursive call instead
  3. Bugzilla 20296: Segfault when using variadic D functions with extern(C++) linkage
  4. Bugzilla 20620: dmd version has -dirty suffix
  5. Bugzilla 20958: incomplete semantic analysis when generating code for function
  6. Bugzilla 20981: Runtime segfault for inlined __simd_sto
  7. Bugzilla 21088: std.meta.staticMap no longer works for typeid
  8. Bugzilla 21091: [ICE] Segmentation fault: Module::importAll(Scope*) (this=0x0, prevsc=0x0) at dmd/dmodule.d:1124
  9. Bugzilla 21163: Scope lambda argument in struct initializer causes parsing error
  10. Bugzilla 21196: [REG 2.092] Deprecation for language feature triggered inside of deprecated block
  11. Bugzilla 21258: Tuple parameters with defaults use the first tuple element for all defaults since 2.094.0-beta.1

DMD Compiler bugs

  1. Bugzilla 2617: asm silently accepts ambiguous-sized operations
  2. Bugzilla 5570: 64 bit C ABI not followed for passing structs and complex numbers as function parameters
  3. Bugzilla 5922: inline assembler - referencing immutable variable values fails
  4. Bugzilla 6166: Named return value optimization not dealt with in inline assembler
  5. Bugzilla 6459: Inline assembler does not work well for 64 bit registers R8..R15
  6. Bugzilla 7387: call instruction does not understand $
  7. Bugzilla 10966: Optimizer generates wrong code with try-catch
  8. Bugzilla 12490: No "Error: , has no effect" Error for comma expression LHS
  9. Bugzilla 12730: lea instruction accepts subtraction of scaling register but actually adds
  10. Bugzilla 12832: asm movdqu accepts wrong operand size
  11. Bugzilla 13215: Error message with static this array assignment
  12. Bugzilla 13957: 64 bit C ABI not followed for passing structs with floating+integer types
  13. Bugzilla 14203: Return of floating point values from extern(C++) member functions does not match dmc
  14. Bugzilla 14458: very slow ubyte[] assignment (dmd doesn't use memset)
  15. Bugzilla 14872: [2.068.2] Label address in asm [x86-64]
  16. Bugzilla 15103: Improve declaration / initialization syntax error message
  17. Bugzilla 15257: __traits(compiles, …) with malformed inline asm silently ends compilation
  18. Bugzilla 15745: Inline Assembly stomped on by Profiling
  19. Bugzilla 16044: __traits(allMembers) returns empty tuple for subpackages
  20. Bugzilla 16092: AVX registers YMM0-YMM7 are inaccessible to 32-bit asm
  21. Bugzilla 16268: Wrong loop optimization in code with integer overflow
  22. Bugzilla 16317: Wrong binop evaluation/load order when optimizing
  23. Bugzilla 16857: inline assembler reverses operands of VPEXTRW instruction
  24. Bugzilla 16963: Forward reference label name resolution in asm statement
  25. Bugzilla 17617: No RIP relative addressing available in x64 inline assembly (iasm)
  26. Bugzilla 17720: Wrong code using vector extensions with different types
  27. Bugzilla 17965: Usage of the FPU while function result already in right XMM registers
  28. Bugzilla 18373: The inline assembler parser allows strange constructs
  29. Bugzilla 18748: bt instruction with immediate offset uses 64-bit variant for 32-bit data
  30. Bugzilla 18749: bt instruction using 64-bit register for 32-bit offset
  31. Bugzilla 19210: Poor error message for return function parameter that is not ref
  32. Bugzilla 19384: [Codegen] Address of stack temporary is returned
  33. Bugzilla 19590: __traits allMembers should put fully qualified names for imports
  34. Bugzilla 19729: Constructor overloads coming from mixin are not resolved
  35. Bugzilla 19846: zero size function parameter such as byte[0] causes code to not be executed
  36. Bugzilla 20017: JSON (-X) compilerInfo.architectures generation depends on params.isXXX for CPU detection
  37. Bugzilla 20162: Sign Extension for ?: optimization done wrong
  38. Bugzilla 20363: painting XMM registers as integers leads to codegen bugs
  39. Bugzilla 20422: confusing error "new can only create structs, dynamic arrays or class objects, not int[]'s"
  40. Bugzilla 20761: __traits(isSame) for alias tuples is broken and underspecified
  41. Bugzilla 20831: __traits(getAttributes) failes to compile when used on a parameter with no name
  42. Bugzilla 20911: Documentation for test/unit is non-existant
  43. Bugzilla 20934: preview=dtorfields segfaults for disabled/extern constructors
  44. Bugzilla 20938: Cannot create const arrays mixing immutable and mutable structs with indirections
  45. Bugzilla 20963: wrong code for cast(double)anUlong
  46. Bugzilla 20995: Range violation with -preview=dip1021
  47. Bugzilla 21001: Private alias becomes public if used before declaration
  48. Bugzilla 21019: Azure pipelines Windows_VisualD win32-ldc fails with Heisenbug
  49. Bugzilla 21037: AVX code sometimes fails to set VEX prefix
  50. Bugzilla 21038: wchar and dchar string alignment should be 2 and 4, respectively
  51. Bugzilla 21040: SIMD: illegal instruction using 32-byte operations on AVX
  52. Bugzilla 21050: __traits(getOverloads) for templates returns incorrect symbol for the first overload
  53. Bugzilla 21053: Test Suite run.d is built with compiler under test, must be build with bootstrap dmd
  54. Bugzilla 21058: __traits(getOverloads) forgets "this" with third argument or if first overload is a template
  55. Bugzilla 21082: Testsuite fails on OSX (runnable/ with asserts on)
  56. Bugzilla 21089: With vm.overcommit_memory=0, DMD can't link if it uses more than half the total (ram+swap) memory in the system.
  57. Bugzilla 21092: [ICE] Segmentation fault in ExpressionPrettyPrintVisitor::visit(CommaExp*) at dmd/hdrgen.d:2293
  58. Bugzilla 21117: When compiler segfaults running autotester, cannot tell which file it was testing
  59. Bugzilla 21120: Inconsistent mangling of __init symbol
  60. Bugzilla 21153: DWARF: DMD emits the mangled name for DW_AT_name
  61. Bugzilla 21154: DWARF: shared types are not represented
  62. Bugzilla 21164: segfault on incomplete static if
  63. Bugzilla 21181: Inline Assmbler compiles long ptr as a byte operation for 32 bit compiles
  64. Bugzilla 21198: Inout copy constructor on union field does not prevent copy-initialization of union
  65. Bugzilla 21208: [ICE] dtoh with enums
  66. Bugzilla 21213: preview=dtorfields with strict attributes in base class constructor
  67. Bugzilla 21217: C++ header generator shouldn't emit private enums
  68. Bugzilla 21219: Invalid C++ header generated for extern(C++, [class|struct])
  69. Bugzilla 21225: preview=dtorfields inserts unnecessary dtor call in nothrow ctors

DMD Compiler enhancements

  1. Bugzilla 1995: invalid paths feed to -J option should be warned
  2. Bugzilla 12223: __traits(getMember,...) needed for aliases
  3. Bugzilla 14120: iasm is missing pause instruction
  4. Bugzilla 14697: Add support for pclmulqdq instruction to dmd's inline assembler
  5. Bugzilla 14936: Dividing by a power of 2 slow on 32bit
  6. Bugzilla 19277: storage class used in alias statement has no effect
  7. Bugzilla 19663: On x86_64 the fabs intrinsic should use SSE
  8. Bugzilla 19705: Static foreach slow for numeric ranges
  9. Bugzilla 20931: code which was executed at ctfe should be accounted for in coverage
  10. Bugzilla 20990: Optimizer should move cold branches to the end of the function
  11. Bugzilla 21060: ICE in semantic, at d/dmd/dstruct.c:1224
  12. Bugzilla 21159: DWARF: DW_AT_pure should be emitted for pure functions

Phobos regressions

  1. Bugzilla 21129: [REG2.090] std.range.only broken for reference conversions of local copies of parameters

Phobos bugs

  1. Bugzilla 7033: File.rawWrite is slow on Windows
  2. Bugzilla 12521: std.getopt does not conform to documentation
  3. Bugzilla 20370: On POSIX, std.file.copy only copies the file times at second precision
  4. Bugzilla 20765: Can't run processes with relative paths when specifying a working directory
  5. Bugzilla 20929: std.experimental.allocator.expandArray's range-based overload fails to instantiate for char and wchar arrays.
  6. Bugzilla 20949: std.range.popFront is unsafe in release mode
  7. Bugzilla 20984: Heisenbug: FreeBSD64 Phobos random test suite failure in std/process
  8. Bugzilla 21021: std.variant confused by alias this when struct larger than maxDataSize
  9. Bugzilla 21148: Semaphoreci: core.exception.AssertError@std/file.d(1929): unittest failure
  10. Bugzilla 21182: asm code is missing int ptr and so defaults to byte op
  11. Bugzilla 21183: schwartzSort does not strip const
  12. Bugzilla 21191: min should be stable: when in doubt, return the first argument
  13. Bugzilla 21199: Nullable.apply should take string expression like rest of Phobos
  14. Bugzilla 21210: std.traits : isAssignable false positive on disabled copy struct

Phobos enhancements

  1. Bugzilla 20889: Support construction of std.bigint.BigInt from a sign and a byte-array magnitude
  2. Bugzilla 21113: std.file.thisExePath on NetBSD depends upon the /proc filesystem
  3. Bugzilla 21131: Appender with string does not process UTF input ranges properly
  4. Bugzilla 21201: let std.uuid.parseUUID accept input ranges whose elements are char or wchar, not just dchar

Druntime bugs

  1. Bugzilla 19554: [2.084.0] Confusing message - Warning: struct Foo has method toHash
  2. Bugzilla 20910: Default unittest runner reports wrong unittest count
  3. Bugzilla 21029: Remove __ArrayEq which the compiler no longer uses as of DMD PR #11212
  4. Bugzilla 21055: core.stdc.stdarg is not @nogc
  5. Bugzilla 21116: onArrayCastError is horribly unsafe

Druntime enhancements

  1. Bugzilla 21026: add core.bitop.byteswap(ushort)
  2. Bugzilla 21070: -profile=gc makes the program much slower bugs

  1. Bugzilla 13569: Inconsistent integer divide by zero behavior and spec

Contributors to this release (49)

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

previous version: 2.093.1