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.1 – next version: 2.097.1

Download D 2.097.0
released Jun 03, 2021

2.097.0 comes with 29 major changes and 144 fixed Bugzilla issues. A huge thanks goes to the 54 contributors who made 2.097.0 possible.

List of all 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.

    Example:

    module pkg.foo;
    
    package(pkg.foo):           // 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 */ }
        else
        { break; }
    }
    

Library changes

  1. Centering formatted output.

    A new flag '=' has been added to the format specifier, which allows to center the output:

    assert(format!"|%=8d|"(1234) == "|  1234  |");
    

    In case the output cannot be centered exactly it is moved slightly to the left if '-' flag is present too and to the right else:

    assert(format!"|%=-8d|"(123) == "|  123   |");
    assert(format!"|%=8d|"(123) == "|   123  |");
    
  2. 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.

  3. Formatting integers with %e, %f, %g and %a is now possible.

    The formatting posibilities of integers have been expanded to the specifiers that are typical for floating point numbers: Integers can now be formatted using %e, %f, %g and %a. The result is similar to the result expected for the corresponding floating point value.

    assert(format!"%.3e"(ulong.max) == "1.845e+19");
    assert(format!"%.3,3f"(ulong.max) == "18,446,744,073,709,551,615.000");
    assert(format!"%.3g"(ulong.max) == "1.84e+19");
    assert(format!"%.3a"(ulong.max) == "0x1.000p+64");
    
  4. 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 ==.

  5. Deprecate std.format : enforceValidFormatSpec

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

  6. 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;
    
    sink.put(format!("%("~fmt~"%)")(only(value)));
    
  7. 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 std.format.read.

  8. FieldnameTuple now returns an empty tuple for interfaces

    Previously FieldNameTuple returned AliasSeq!"" for interfaces as done for non-aggregate types like int, char*, ... . This behaviour was surprising because an instance of that interface may have members that just are not known at compile time.

    FieldNameTuple will now return an empty AliasSeq!() for interfaces.

  9. Fields (formerly FieldTypeTuple) now returns an empty tuple for interfaces

    Previously Fields returned AliasSeq!(Interface) for interfaces as done for non-aggregate types like int, char*, ... . This behaviour was surprising because an instance of an interface may have members that just are not known at compile time.

    Fields will now return an empty AliasSeq!() for interfaces.

  10. Floating point numbers can be formatted at compile time

    Example:

    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   |");
    
  11. Formatting floating point numbers don't allocate with the GC anymore.

    The implementation of formatting floating point numbers has been reworked. We made sure that working examples never allocate with the GC, however, we are still using exceptions which are GC managed. Therefore, code that uses formatting correctly will never allocate, but in the case of exceptions, the GC will be used to allocate the exception. We are working on DIP 1008 to solve this issue.

  12. Some reals will be downcast to double when used with std.format.

    In the internals of std.format we replaced a call to snprintf of libc with routines written in D for formatting floating point values. These functions only work for floats, doubles, 64-bit-reals and 80-bit-reals (x87-reals) yet.

    All other reals are handled by downcasting them to doubles before being formatted. This might result in a loss of precision in the output. Further, numbers larger than double.max will be formatted like double.max and numbers large than zero but smaller than the smallest positive double will be formatted like the smallest positive double. Likewise for negative values.

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

  14. Documentation of std.format has been completely reworked.

    In the last years, the documentation of std.format was outdated little by little and therefore needed a complete rework. The whole package was reviewed and all documentations, including examples, improved and extended.

    Some highlights:

    • The grammar of the format string was updated.
    • A detailed description of format specifiers was provided.
    • Several examples on how to use the functions and the format strings were added.

  15. 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
    • std.format.read: 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.

  16. Module std.math has been split into smaller modules

    The module std.math has been split into submodules:

    • std.math.constants: Mathematical constants, like PI.
    • std.math.algebraic: Basic algebraic functions, like abs and sqrt.
    • std.math.trigonometry: Trigonometric functions, like sin and cos.
    • std.math.rounding: Functions concerned about rounding, like ceil and floor.
    • std.math.exponential: Exponential and logarithmic functions, like pow, exp and log.
    • std.math.remainder: Function calculating the remainder, like fmod.
    • std.math.operations: Floating-point operations, like isClose, nextUp and fmin.
    • std.math.traits: Floating-point introspection, like isNaN and isSubnormal.
    • std.math.hardware: Hardware control: IeeeFlags and FloatingPointControl.

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

  17. 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);
    assert(r3.equal!equal([
        [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.

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

  19. std.exception.enforceEx has been removed.

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

  20. New module: std.sumtype

    The sumtype package from code.dlang.org 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(
            t.match!(
                (Fahrenheit f) => f.degrees,
                (Celsius c) => c.degrees * 9.0/5 + 32,
                (Kelvin k) => k.degrees * 9.0/5 - 459.4
            )
        );
    }
    
    assert(toFahrenheit(t1).degrees.isClose(98.6));
    assert(toFahrenheit(t2).degrees.isClose(212));
    assert(toFahrenheit(t3).degrees.isClose(32));
    
    // Use ref to modify the value in place.
    void freeze(ref Temperature t)
    {
        t.match!(
            (ref Fahrenheit f) => f.degrees = 32,
            (ref Celsius c) => c.degrees = 0,
            (ref Kelvin k) => k.degrees = 273
        );
    }
    
    freeze(t1);
    assert(toFahrenheit(t1).degrees.isClose(32));
    
    // Use a catch-all handler to give a default result.
    bool isFahrenheit(Temperature t)
    {
        return t.match!(
            (Fahrenheit f) => true,
            _ => false
        );
    }
    
    assert(isFahrenheit(t1));
    assert(!isFahrenheit(t2));
    assert(!isFahrenheit(t3));
    
  21. 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 21752: Template constraint breaks nested eponymeous template
  2. Bugzilla 21802: opAssign and opOpAssign treat lazy void parameters inconsistently
  3. Bugzilla 21880: [REG 2.095] scope variable assigned to non-scope parameter calling function
  4. Bugzilla 21898: Qualifier ignored in alias definition if parentheses are not present
  5. Bugzilla 21914: naked assembler functions get wrong offset to parameters
  6. Bugzilla 21936: [REG 2.080.1] Segfault when compiled with -dip1000

DMD Compiler bug fixes

  1. Bugzilla 2450: Error using operators from named template mixin
  2. Bugzilla 13815: Inconsistent goto jump behavior between compile-time and runtime
  3. Bugzilla 14114: Allow volatileLoad/Store to access null location
  4. Bugzilla 14145: opDispatch not considered when function body doesn't compile
  5. Bugzilla 14740: __traits(allMembers) returns erroneous 'this' member for types declared in functions.
  6. Bugzilla 14954: extern opaque struct instance doesn't compile
  7. Bugzilla 15478: cases of missed CTFE evaluation when defining arrays dimensions
  8. Bugzilla 16472: Spurious "is used as a type" when aliasing enum template as default parameter
  9. Bugzilla 17146: Internal error: tk.c 266 with -O -inline
  10. Bugzilla 18251: deprecate + transition=complex shouldn't look at functions with non-matching if constraints
  11. Bugzilla 19387: [dip1000] __fieldPostblit should be scope or deduce scope qualifier
  12. Bugzilla 19443: core.simd generates MOVLPS instead of MOVHLPS
  13. Bugzilla 19783: Fail to emplace struct with betterC
  14. Bugzilla 20460: [OSX] DMD writes the same address everywhere in DWARF debug infos
  15. Bugzilla 20581: DIP1000 wrongly flags hidden ref temporary
  16. Bugzilla 20599: cpp_long as enum type doesn't work
  17. Bugzilla 20704: -preview=rvaluerefparam does not work with init as default parameter
  18. Bugzilla 20855: stack overflow when compiling large file
  19. Bugzilla 21403: dmd/backend/cgcs.d:375 assert failed
  20. Bugzilla 21651: Unimported package doesn't error out when used as part of fully qualified type
  21. Bugzilla 21661: Can't use fully-qualified name of the current module inside an expression
  22. Bugzilla 21665: Void initialization should not be allowed for instances of struct with invariant
  23. Bugzilla 21668: Cannot declare ref parameter of opaque type
  24. Bugzilla 21672: [REG][ICE][SIMD] accessing SIMD type as a short causes compiler ice
  25. Bugzilla 21680: inconsistent error on typeof({ return field; }())
  26. Bugzilla 21684: Assert fail for Win32 with a struct larger than 64k in size
  27. Bugzilla 21699: Duplicate error for index out of bounds at compile time
  28. Bugzilla 21726: Wrong comparison in package(...) visibilities
  29. Bugzilla 21739: debug case can access variable from other case
  30. Bugzilla 21742: dot template expressions don't have the void type like any template
  31. Bugzilla 21743: getOverloads fails to propagate 'this' expression for template member
  32. Bugzilla 21753: Struct literal with function literal member not allowed as template value argument
  33. Bugzilla 21765: Assignment-as-condition error with checkaction=context
  34. Bugzilla 21779: assert not omitted for -release -checkaction=context
  35. Bugzilla 21785: Cannot declare variable of opaque enum with base type
  36. Bugzilla 21791: Stack overflow for forward-referenced enum initializer
  37. Bugzilla 21792: Enum using itself as base type crashes dmd
  38. Bugzilla 21793: Cannot initialize shared member with -preview=nosharedaccess
  39. Bugzilla 21797: Stack overflow for forward-referenced enum min / max
  40. Bugzilla 21812: __traits(allMembers) on types with value tuples return ghost members
  41. Bugzilla 21816: testing XMM for nan does not work
  42. Bugzilla 21822: Optimizer flowlv() does not account for OPmemcmp and OPstrcmp
  43. Bugzilla 21825: DIP1034: Do not spuriously warn "calling XXX without side effects discards return value of type 'noreturn'"
  44. Bugzilla 21826: MSCOFF output for Win32 should not use EBP for anything other than the frame pointer
  45. Bugzilla 21827: Null pointer exception in elToPair() in backend/cgelem.d
  46. Bugzilla 21828: Enum forward-references just assume int base type
  47. Bugzilla 21830: Wrong deprecation message when non-deprecated template in static condition
  48. Bugzilla 21831: Wrong deprecation message in template parameters before evaluating constraints
  49. Bugzilla 21832: Wrong deprecation message when importing non-deprecated template in static condition
  50. Bugzilla 21833: Optimizer incorrectly rewrites integer comparison to unsigned short comparison
  51. Bugzilla 21849: UTF8: -verrors=context doesn't respect multibyte characters
  52. Bugzilla 21861: ctfe fails when a nested enum or function has a UDA
  53. Bugzilla 21870: Property/method not invoked and requires () when used in static array length
  54. Bugzilla 21874: The test suite fails with most recent GDB versions
  55. Bugzilla 21876: Zero-length static arrays "cannot be read at compile time"
  56. Bugzilla 21878: "ref" lost when indexing array in CTFE
  57. Bugzilla 21882: [ICE][dip1021] src/dmd/escape.d(1850): Assertion failure
  58. Bugzilla 21883: poor error message when swapping order of base class and interface
  59. Bugzilla 21918: segfault in getParameterStorageClasses on auto function with error
  60. Bugzilla 21927: ICE (illegal instruction) with static foreach over empty member template
  61. Bugzilla 21940: Compiler flags -check=on/off not recognized

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 regression fixes

  1. Bugzilla 21716: std.regex performance regression (additional GC allocation)
  2. Bugzilla 21725: Specifying null as bitfields variable name now fails

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 21456: std.format does not accept enum member with string base type as template parameter
  16. Bugzilla 21512: RedBlackTree!Tid treats any values as duplicated except for Tid.init
  17. Bugzilla 21575: Child processes spawned by std.process.spawnProcess accidentally inherit signal masks in parent process
  18. Bugzilla 21592: two stack traces if high surrogate is printed
  19. Bugzilla 21601: std.math : pow(float/double, -2) produces sometimes wrong result
  20. Bugzilla 21627: macOS: std.stdio.File.sync does not guarantee to be written to disk
  21. Bugzilla 21641: std.format: %g produces in rare circumstances inconsistent result
  22. Bugzilla 21679: Assertion failure in Base64.encoder for empty input range of ranges
  23. Bugzilla 21700: Long deprecated Stopwatch std.datetime is still not removed
  24. Bugzilla 21702: avoid quadratic template expansion in constraints of multiple search term versions of std.algorithm.searching.startsWith & endsWith
  25. Bugzilla 21704: Nullable fails to destroy static array elements
  26. Bugzilla 21705: Nullable!T.opEquals fails for T with non-const opEquals overload
  27. Bugzilla 21707: std.base64: Faulty input creates range error instead of Base64Exception
  28. Bugzilla 21708: SumType.opEquals gives confusing error message
  29. Bugzilla 21721: casting std.BigInts to built-in floating point types doesn't work without -preview=dip1000
  30. Bugzilla 21722: toString(sink, string format) does not work with non-"%s" strings
  31. Bugzilla 21724: std.algorithm.mutation.copy fails on overlapping arrays if the source array's pointer is less than the destination array's pointer
  32. Bugzilla 21728: rawRead calls fread with NULL if invoked on closed readEnd of Pipe (segfault)
  33. Bugzilla 21729: rawRead derefences null pointer if invoked on closed File (segfault)
  34. Bugzilla 21730: null ptr dereferenced in ChunksImpl.opApply (SIGSEGV)
  35. Bugzilla 21738: std.format.spec: singleSpec should throw on "%%"
  36. Bugzilla 21758: std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
  37. Bugzilla 21777: std.format: several issues when formatting integers with precision
  38. Bugzilla 21814: std.format: grouping with width 0 causes floating point exception
  39. Bugzilla 21817: std.format: %u on integer does not print unsigned value
  40. Bugzilla 21820: std.format: formatting zero should never lead to empty string
  41. Bugzilla 21834: std.numeric.gcd can't handle negative values
  42. Bugzilla 21836: std.format: grouping may cause RangeError
  43. Bugzilla 21838: std.format: Grouping garbles up %a output
  44. Bugzilla 21840: std.format: grouping ignores space flag with %e
  45. Bugzilla 21841: std.format: grouping produces strange result with zero precision and %e
  46. Bugzilla 21842: std.format: "%-+05,g" adds extra comma
  47. Bugzilla 21846: std.format: provided format string for toString does not work with grouping
  48. Bugzilla 21853: std.format: formatting real.max in CTFE fails
  49. Bugzilla 21863: FieldNameTuple returns emptry string for interfaces
  50. Bugzilla 21875: std.format: wrong number of format specifiers in nested format string of associative arrays should be detected
  51. Bugzilla 21900: std.format: round to even does not work for hex integers with letters

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 18627: std.complex is a lot slower than builtin complex types at number crunching
  5. Bugzilla 20756: ImplicitConversionTargets ignores interface inheritance
  6. Bugzilla 21759: std.experimental.checkedint.Checked is not compatible with "%d" and "%x" integer format specifiers
  7. Bugzilla 21760: std.conv.to does not know how to convert a string to a std.experimental.checkedint.Checked!T
  8. Bugzilla 21761: make std.experimental.checkedint.Checked!T.toHash callable when Checked!T is shared
  9. Bugzilla 21808: std.format: It should be possible to change the order of key and value of AAs.
  10. Bugzilla 21847: std.format: %e, %g and %a should be supported for integers too
  11. Bugzilla 21858: std.format: centering output

Druntime regression fixes

  1. Bugzilla 21097: [REG2.083] Stack exhaustion upon large struct .destroy
  2. Bugzilla 21363: [REG2.094] Implementation of core.bitop.ror(x,0) is using UB

Druntime bug fixes

  1. Bugzilla 21764: checkaction=context doesn't work for empty tuples
  2. Bugzilla 21857: TypeInfo_Array.compare can give wrong result when either array exceeds 2GB

Druntime enhancements

  1. Bugzilla 21789: Codecov should use default umask for file permissions

dlang.org enhancements

  1. Bugzilla 21161: [Variadic Templates] uses outdated example from D1 / Tango
  2. Bugzilla 21869: Invalid hyperlink to doxygen

Contributors to this release (54)

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

previous version: 2.096.1 – next version: 2.097.1