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

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

2.097.0 comes with 21 major changes and 102 fixed Bugzilla issues. A huge thanks goes to the 45 contributors who made 2.097.0 possible.

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

Compiler changes

  1. Deprecation period for ambiguous ternary expressions has ended

    In D, the ternary operator (?:) has a higher precedence than the assignment operator (=), hence:

    true ? stt = "AA" : stt = "BB"

    actually means:

    (true ? (stt = "AA") : stt) = "BB",

    This is in line with C, and many other languages (except C++), but comes at a surprise to many, which is why this specific combination of ternary and assignment was deprecated in v2.082.0 (2018-09-01).

    The deprecation instructs the user to use parenthesis to make the intent explicit, so the above snippet should read as:

    true ? (stt = "AA") : (stt = "BB")

    This deprecation period has now ended and the compiler will now issue an error for ambiguous code.

  2. Usage of the body keyword has been deprecated

    Using body to indicate the body of a function or method in the presence of contracts is now deprecated. Any leftover usage of body can be replaced with do. This replacement, introduced by DIP1003, has been available since DMD v2.075.0 (July 2017).

  3. Deprecate a case of using fully-qualified names to bypass imports

    Since v2.084 it is no longer possible to bypass private imports by using fully-qualified names, this was deprecated in v2.071 but when fully-qualified names are used as a type (vs an expression) the code is accepted without any warning.

    Starting with this release the compiler will now properly deprecate the previous omitted case.

    The issue is best described in the following example:

    import std.algorithm;
    // deprecated in v2.071, error since v2.084
    auto a = std.range.Take!(int[]); // Error: undefined identifier `range` in package `std`...
    // now it's deprecated, will be error from v2.106
    std.range.Take!(int[]) s;
  4. Explicit package visibility attribute is now always applied to new scopes

    If a less restrictive package attribute appeared within the scope of another package attribute, the more restrictive parent would override any explicit child visibility.


    package(           // analogous to "private" or plain "package"
    package(pkg) int bar();     // package(pkg) was being ignored

    Starting from this version, the package visibility attribute is now always applied as long as it is valid. In the given example, this allows any module in the package pkg to import and use the symbol bar.

  5. pragma(mangle) can now be applied to aggregates

    The syntax is pragma(mangle, str_or_decl [, str] ) declaration; where str_or_decl is either: a string expression to substitute the name of declaration; or a class, struct, or union declaration or template instance to use instead of declarations for mangling. If the optional second argument is present, use that as a name instead but keep the namespaces and template parameters of str_or_decl (if any).

    This enables binding with functions that take classes by value or reference and to classes that are D keywords.

    To bind C++'s std::function by value:

    extern(C++, "std")
        template std_function(F)
            pragma(mangle, "function")
            class std_function
                // member variables and functions
    template ScopeClass(C , string name)
        enum ns = __traits(getCppNamespaces,C);
        extern(C++, class) extern(C++,(ns))
            pragma(mangle, C, name)
            struct ScopeClass
                char[__traits(classInstanceSize, C)] buffer;
                // member variables and functions
    alias FuncType = void function(int);
    alias RawFuncType = typeof(*FuncType.init);
    // Mangles as `void funk(std::function<void(int)> a)`
    extern(C++) void funk( ScopeClass!(std_function!(RawFuncType)),"function") a );
  6. Complex and imaginary types are now deprecated

    D previously supported complex and imaginary versions of all floating point types as part of the language.

    float a = 2;
    ifloat b = 4i;
    cfloat c = a + b;
    assert(c == 2 + 4i);

    However these types are too specialized to be a part of the core language, and the same functionalities can be implemented as part of a library type. As such, older versions of DMD provided the -transition=complex switch to warn when those builtin types were used. This transition phase has finished, and those deprecations are now turned on by default.

    Users should use std.complex.Complex instead.

    import std.complex;
    float a = 2;
    float b = 4;
    auto c = complex(a, b);
    assert(c == complex(2, 4));

    The -transition=complex switch that previously turn on deprecation warnings no longer has an effect and has also been deprecated.

  7. while (auto n = expression) is now supported

    Up until this release, while (auto n = expression) was not supported, although the if counterpart: if (auto n = expression) compiled succesfully. Starting with the current compiler version, while (auto n = expression) is accepted, having the exact same semantics as:

    while (true)
        if (auto n = expression)
        { /* loop body */ }
        { break; }

Library changes

  1. AllImplicitConversionTargets replaces ImplicitConversionTargets

    The function ImplicitConversionTargets in module std.traits has a design flaw: The list of conversion targets contains some, but not all unsafe conversion targets. To overcome this, a new function AllImplicitConversionTargets has been added and ImplicitConversionTargets has been deprecated.

  2. Implementation of pow(f, -2) and f ^^ -2 changed

    We noticed that the implementation of pow(f, -2) and f ^^ -2 with f being a floating point value, was buggy for some values of f. Unfortunately the fix implies small changes for other values for f (with exponent -2) too: The least significant bits of the result might differ from the current implementation. (This is due to the peculiarities of floating point numbers and cannot be avoided with reasonable means.)

    To avoid problems, make sure, that your algorithms do not rely on the least significant bits of floating point calculations, for example by using isClose instead of ==.

  3. Deprecate std.format : enforceValidFormatSpec

    enforceValidFormatSpec from std.format has been accidentally made public and will be removed from public view in 2.107.0.

  4. Deprecate std.format : formatElement

    formatElement from std.format has been accidentally made public and will be removed from public view in 2.107.0.

    Please use instead of formatElement(sink, value, fmt):

    import std.range : only;
  5. Deprecate std.format : unformatElement

    unformatElement from std.format has been accidentally made public and will be removed from public view in 2.107.0.

    Please use instead for strings and characters parseElement from std.conv and for all else unformatValue from

  6. Floating point numbers can be formatted at compile time


    import std.format : format;
    import std.math : sqrt;
    enum pi = format!"%s"(3.1415926f);
    static assert(pi == "3.14159");
    enum golden_ratio = format!"|%+-20.10E|"((1 + sqrt(5.0)) / 2);
    static assert(golden_ratio == "|+1.6180339887E+00   |");

    Note: compile time formatting reals is only supported for 64-bit reals and 80-bit reals.

  7. std.typecons.Nullable: Remove deprecated alias get this.

    Nullable no longer implicitly converts to its member. This feature was problematic because a simple use of a value could invisibly cause an assertion due to type conversion. To restore the previous behavior, replace uses of a Nullable value n with n.get.

  8. Module std.format has been split into smaller modules

    The module std.format has been split into submodules:

    • std.format.spec: Symbols concerning the format string, mainly the struct FormatSpec and the template singleSpec
    • Symbols concerning reading input, mainly the template formattedRead and the template unformatValue
    • std.format.write: Symbols concerning writing output, mainly the template formattedWrite and the template formatValue

    All public symbols are still accessible using std.format as usual.

  9. splitWhen added to std.algorithm.iteration

    std.algortihm.iteration.splitWhen is a variant of the existing std.algortihm.iteration.chunkBy function that does not require its predicate to be an equivalence relation, allowing it to be used in ways that chunkBy cannot. For example:

    // Grouping by maximum adjacent difference:
    import std.math : abs;
    import std.algorithm;
    auto r3 = [1, 3, 2, 5, 4, 9, 10].splitWhen!((a, b) => abs(a-b) >= 3);
        [1, 3, 2],
        [5, 4],
        [9, 10]

    This would have an undefined result with chunkBy, because it requires that if pred(a,b) and pred(b,c) return true, pred(a,c) must also return true.

  10. The old benchmarking functionality in std.datetime has been removed.

    It had been deprecated in 2.077.0 in favor of std.datetime.stopwatch, which uses core.time.MonoTime and core.time.Duration.

  11. std.exception.enforceEx has been removed.

    It had been deprecated in 2.079 in favor of std.exception.enforce.

  12. New module: std.sumtype

    The sumtype package from has been added to the standard library as std.sumtype.

    It provides SumType, a generic discriminated union implementation that uses design-by-introspection to generate safe and efficient code, and is intended to serve as a replacement for the legacy std.variant.Algebraic.

    Features of SumType include:

    • Pattern matching.
    • Support for self-referential types.
    • Full compatibility with pure, @safe, @nogc, nothrow, and scope.
    • No dependency on runtime type information (TypeInfo).
    • Compatibility with BetterC.

    Example usage:

    import std.sumtype;
    import std.math : isClose;
    struct Fahrenheit { double degrees; }
    struct Celsius { double degrees; }
    struct Kelvin { double degrees; }
    alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin);
    // Construct from any of the member types.
    Temperature t1 = Fahrenheit(98.6);
    Temperature t2 = Celsius(100);
    Temperature t3 = Kelvin(273);
    // Use pattern matching to access the value.
    Fahrenheit toFahrenheit(Temperature t)
        return Fahrenheit(
                (Fahrenheit f) => f.degrees,
                (Celsius c) => c.degrees * 9.0/5 + 32,
                (Kelvin k) => k.degrees * 9.0/5 - 459.4
    // Use ref to modify the value in place.
    void freeze(ref Temperature t)
            (ref Fahrenheit f) => f.degrees = 32,
            (ref Celsius c) => c.degrees = 0,
            (ref Kelvin k) => k.degrees = 273
    // Use a catch-all handler to give a default result.
    bool isFahrenheit(Temperature t)
        return t.match!(
            (Fahrenheit f) => true,
            _ => false
  13. std.range.Transposed: Remove deprecated member save

    Transposed never worked as forward range.

Dub changes

  1. Added support for low memory compilation option to the dub settings file.

    To enable, set defaultLowMemory to true. For dmd and ldc, the -lowmem command-line option is added when compiling.

        "defaultLowMemory": true

List of all bug fixes and enhancements in D 2.097.0:

DMD Compiler regression fixes

  1. Bugzilla 21229: [REG 2.080.2] Constructor flow analysis doesn't understand unions
  2. Bugzilla 21687: Confusing error message for CTFE pointer in static initializer
  3. Bugzilla 21752: Template constraint breaks nested eponymeous template
  4. Bugzilla 21798: checkaction=context creates temporary of type void
  5. Bugzilla 21802: opAssign and opOpAssign treat lazy void parameters inconsistently
  6. Bugzilla 21806: Overload selection ignores slice

DMD Compiler bug fixes

  1. Bugzilla 14114: Allow volatileLoad/Store to access null location
  2. Bugzilla 14145: opDispatch not considered when function body doesn't compile
  3. Bugzilla 14740: __traits(allMembers) returns erroneous 'this' member for types declared in functions.
  4. Bugzilla 14954: extern opaque struct instance doesn't compile
  5. Bugzilla 16472: Spurious "is used as a type" when aliasing enum template as default parameter
  6. Bugzilla 17146: Internal error: tk.c 266 with -O -inline
  7. Bugzilla 18251: deprecate + transition=complex shouldn't look at functions with non-matching if constraints
  8. Bugzilla 19192: [wrong-code] [crashes] Covariant method interface <- abstract class <- class hierarchies
  9. Bugzilla 19387: [dip1000] __fieldPostblit should be scope or deduce scope qualifier
  10. Bugzilla 19443: core.simd generates MOVLPS instead of MOVHLPS
  11. Bugzilla 20581: DIP1000 wrongly flags hidden ref temporary
  12. Bugzilla 20599: cpp_long as enum type doesn't work
  13. Bugzilla 20704: -preview=rvaluerefparam does not work with init as default parameter
  14. Bugzilla 20705: -preview=rvaluerefparam does not work with template deduction
  15. Bugzilla 21403: dmd/backend/cgcs.d:375 assert failed
  16. Bugzilla 21651: Unimported package doesn't error out when used as part of fully qualified type
  17. Bugzilla 21661: Can't use fully-qualified name of the current module inside an expression
  18. Bugzilla 21665: Void initialization should not be allowed for instances of struct with invariant
  19. Bugzilla 21668: Cannot declare ref parameter of opaque type
  20. Bugzilla 21672: [REG][ICE][SIMD] accessing SIMD type as a short causes compiler ice
  21. Bugzilla 21680: inconsistent error on typeof({ return field; }())
  22. Bugzilla 21684: Assert fail for Win32 with a struct larger than 64k in size
  23. Bugzilla 21699: Duplicate error for index out of bounds at compile time
  24. Bugzilla 21726: Wrong comparison in package(...) visibilities
  25. Bugzilla 21739: debug case can access variable from other case
  26. Bugzilla 21742: dot template expressions don't have the void type like any template
  27. Bugzilla 21743: getOverloads fails to propagate 'this' expression for template member
  28. Bugzilla 21753: Struct literal with function literal member not allowed as template value argument
  29. Bugzilla 21765: Assignment-as-condition error with checkaction=context
  30. Bugzilla 21779: assert not omitted for -release -checkaction=context
  31. Bugzilla 21785: Cannot declare variable of opaque enum with base type
  32. Bugzilla 21791: Stack overflow for forward-referenced enum initializer
  33. Bugzilla 21792: Enum using itself as base type crashes dmd
  34. Bugzilla 21793: Cannot initialize shared member with -preview=nosharedaccess
  35. Bugzilla 21797: Stack overflow for forward-referenced enum min / max
  36. Bugzilla 21799: CTFE doesn't call base class destructor for extern(D) classes
  37. Bugzilla 21812: __traits(allMembers) on types with value tuples return ghost members
  38. Bugzilla 21816: testing XMM for nan does not work
  39. Bugzilla 21822: Optimizer flowlv() does not account for OPmemcmp and OPstrcmp
  40. Bugzilla 21825: DIP1034: Do not spuriously warn "calling XXX without side effects discards return value of type 'noreturn'"
  41. Bugzilla 21826: MSCOFF output for Win32 should not use EBP for anything other than the frame pointer
  42. Bugzilla 21827: Null pointer exception in elToPair() in backend/cgelem.d
  43. Bugzilla 21828: Enum forward-references just assume int base type
  44. Bugzilla 21830: Wrong deprecation message when non-deprecated template in static condition
  45. Bugzilla 21831: Wrong deprecation message in template parameters before evaluating constraints
  46. Bugzilla 21832: Wrong deprecation message when importing non-deprecated template in static condition

DMD Compiler enhancements

  1. Bugzilla 16140: while(auto x = y) does not behave like if(auto x = y)
  2. Bugzilla 20068: Union initialization in constructors should be @safe
  3. Bugzilla 21203: Accept pragma(mangle) on aggregate types
  4. Bugzilla 21585: add __traits(totype, string) to convert mangled type string to an existing type
  5. Bugzilla 21630: assert(0) and assert(false) should not be marked for coverage
  6. Bugzilla 21835: Operation on float should use XMM register, not x87

Phobos bug fixes

  1. Bugzilla 8424: Compile time conversions of double/floats to strings
  2. Bugzilla 9297: Formatting of floating point values in std.format truncates reals to double
  3. Bugzilla 15227: std.format undocumented grammar
  4. Bugzilla 15348: std.stdio.writef format specifier error message
  5. Bugzilla 15386: std.format.formatValue usage hangs
  6. Bugzilla 15888: std.format should not produce deprecated hexstrings
  7. Bugzilla 16432: JSON incorrectly parses to string
  8. Bugzilla 17381: Checked format string is permissive after floating point argument
  9. Bugzilla 18780: Inconsistent behavior with Variant holding int converting to unsigned types
  10. Bugzilla 20320: format("%f") leeds to wrong output
  11. Bugzilla 20371: std.format limited to 500 characters for floats
  12. Bugzilla 20502: Converting std.typecons.RefCounted!T to a string gives T's storage location instead of T's fields when T is a struct without an explicit toString
  13. Bugzilla 20534: std.format: %r on boolean gives wrong result
  14. Bugzilla 20536: std.format: %a on reals is inconsistent with %a on float/double
  15. Bugzilla 21592: two stack traces if high surrogate is printed
  16. Bugzilla 21601: std.math : pow(float/double, -2) produces sometimes wrong result
  17. Bugzilla 21627: macOS: std.stdio.File.sync does not guarantee to be written to disk
  18. Bugzilla 21641: std.format: %g produces in rare circumstances inconsistent result
  19. Bugzilla 21679: Assertion failure in Base64.encoder for empty input range of ranges
  20. Bugzilla 21700: Long deprecated Stopwatch std.datetime is still not removed
  21. Bugzilla 21704: Nullable fails to destroy static array elements
  22. Bugzilla 21705: Nullable!T.opEquals fails for T with non-const opEquals overload
  23. Bugzilla 21707: std.base64: Faulty input creates range error instead of Base64Exception
  24. Bugzilla 21708: SumType.opEquals gives confusing error message
  25. Bugzilla 21722: toString(sink, string format) does not work with non-"%s" strings
  26. Bugzilla 21738: std.format.spec: singleSpec should throw on "%%"
  27. Bugzilla 21777: std.format: several issues when formatting integers with precision
  28. Bugzilla 21814: std.format: grouping with width 0 causes floating point exception
  29. Bugzilla 21817: std.format: %u on integer does not print unsigned value
  30. Bugzilla 21820: std.format: formatting zero should never lead to empty string
  31. Bugzilla 21834: std.numeric.gcd can't handle negative values

Phobos enhancements

  1. Bugzilla 13595: Extend std.algorithm.groupBy to support non-equivalence relations
  2. Bugzilla 16200: Faster pow implementation for integral exponents
  3. Bugzilla 18024: checkedint.Abort and checkedint.Warn should be @safe
  4. Bugzilla 21759: std.experimental.checkedint.Checked is not compatible with "%d" and "%x" integer format specifiers
  5. Bugzilla 21760: does not know how to convert a string to a std.experimental.checkedint.Checked!T
  6. Bugzilla 21761: make std.experimental.checkedint.Checked!T.toHash callable when Checked!T is shared

Druntime regression fixes

  1. Bugzilla 21709: std.conv.emplace not usable in betterC - 2.096
  2. Bugzilla 21712: [REG 2.096.0] sometimes coverage *.lst files are corrupted

Druntime bug fixes

  1. Bugzilla 21371: core.stdcpp.allocator: _Adjust_manually_vector_aligned checks for sentinel unconditionally (Windows only)
  2. Bugzilla 21701: casWeak is not implemented
  3. Bugzilla 21764: checkaction=context doesn't work for empty tuples

Druntime enhancements

  1. Bugzilla 21784: joining a detached thread results in segfault.
  2. Bugzilla 21789: Codecov should use default umask for file permissions

Contributors to this release (45)

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

previous version: 2.096.0