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

previous version: 2.095.0

Download D nightlies
To be released


This changelog has been automatically generated from all commits in master since the last release.

  • The full-text messages are assembled from the changelog/ directories of the respective repositories: dmd, druntime, phobos, tools, dlang.org, installer, and dub.
  • See the DLang-Bot documentation for details on referencing Bugzilla. The DAutoTest PR preview doesn't include the Bugzilla changelog.
  • The pending changelog can be generated locally by setting up dlang.org and running the pending_changelog target:
    make -f posix.mak pending_changelog


2.096.0 comes with 19 major changes and 92 fixed Bugzilla issues. A huge thanks goes to the 55 contributors who made 2.096.0 possible.

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

Compiler changes

  1. 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()
    {
        foo!(1)();
        foo!(1)();
        foo!(2)();
    
        goo1!(1)();
    
        goo2!(1)();
    }
    

    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`
    
  2. Deprecate bypassing of symbol visibility when doing overload resolution

    If an aggregate declaration contains a private method and a public method in the same overload set it is possible to call the private method from a different module.

    Example:

    ==============================
    module foo;
    
    struct Foo
    {
      import std : writeln;
    
      private int _x;
    
      private ref int x() return
      {
        writeln("ref int");
        return _x;
      }
    
      int x() const
      {
        writeln("int");
        return _x;
      }
    }
    ============================
    
    ---
    

    module main;

    void main() { import std : writeln; import foo : Foo;

    auto f = Foo(); f.x = 3; // ok to call private method writeln(f); } ===========================

    Starting from this version a deprecation message will be issued in such situations.
  3. Deprecation triggered inside of templates now show instantiation trace

    A common issue when dealing with deprecations is to have it trigger in library code, for example having a deprecated alias this, or a hook (opApply, range primitives...) being called by a function deeply nested inside Phobos.

    In such cases, finding out where the instantiation comes from can be quite tedious. From this release, if a deprecation is triggered inside a template, the compiler will show the template instantiation trace, just like it already does on error. The same limit apply (6 frames, recursive templates are compressed), and -v can be used to lift it.

  4. Improvements for the C++ header generation

    The following features/bugfixes/improvements were implemented for the experimental C++ header generator:

    • Enums are no longer emitted in macros and enum class is used when the C++ standard set from -extern-std= is c++11 or later.
    • Forward referenced declarations are now properly indented.
    • Default functions parameters are properly emitted
    • Tuple members/parameters/variables are emitted as individual variables using the compiler internal names instead of causing an assertion failure.
    • Interfaces are now emitted as base classes.
    • Aggregate members will be emitted with proper protection levels
    • Protected enums in aggregates are emitted again
    • Private member methods are no longer emitted
    • No auto-generated default constructor for unions
    • No longer ignores declarations nested inside an extern block, e.g. extern(D) extern(C++) void foo() {}
    • Opaque enums no longer cause segfaults & are properly exported for C++ 11
    • C++11 constructs are avoided when compiling with -extern-std=c++98.
    • Using typeof(null) type no longer causes an assertion failure.
    • The base type of floating point literals is propagated into the header
    • NaN, Infinity are emitted using NAN/INFINITY from math.h.
    • Final classes are marked as final
    • immutable is emitted as const instead of mutable
    • Identifier chains in templates are printed completely
    • Proper vtable layout is ensured by emitting hidden placeholders for virtual functions that are not extern(C|C++).
    • Fixed missing const for class members/methods
    • Templated class declarations are now emitted
    • Manifest constants that are not extern(C|C++) are no longer emitted.

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

  5. Diagnostics for conflicting function definitions within a module

    Previously, multiple definitions of identical functions within a module were not recognized, although they have the same mangling. This was problematic because a binary cannot contain multiple definitions of a symbol, which caused undefined behavior depending on the compiler backend.

    DMD will now raise an error message if there are conflicting implementations within a single module:

    void foo() {}
    void foo() {} // error
    

    Multiple declarations are still allowed as long as there is at most one definition:

    void bar(int);
    void bar(int) { }
    void bar(int);
    

    DMD will issue a deprecation for mangling schemes that don't support overloading (extern(C|Windows|System)):

    extern(C):
    void foo(int) { }
    void foo(double) { } // deprecation
    

    This deprecation will become an error in 2.105.

  6. extern(Pascal) has been removed

    This unused linkage was deprecated in https://dlang.org/changelog/2.084.0.html#deprecated_extern_pascal and has now been removed.

  7. The compiler now accepts -extern-std=c++20

    The compiler now accepts c++20 as a supported standard for -extern-std=. Currently this only changes the value of __traits(getTargetInfo, "cppStd"), though new types may be added in the future.

  8. C++ compability standard now c++11 by default

    The default setting for -extern-std= has been updated to c++11.

    Declarations with extern(C++) linkage are no longer guaranteed to link with code compiled by a C++98 compiler. Additionally, C++ headers generated by -HC will use constructs only available from C++11 onwards.

    If compatibility with older C++ compilers is required, you must now pass -extern-std=c++98 on the command-line.

  9. Add -preview=inclusiveincontracts: in contracts must be an explicit superset of the parent in contracts.

    As per Liskov, in contracts can only loosen the conditions placed on the method they appear on. Currently this is enforced by automatically "oring" together the in contract with the in contract on the parent method, creating a combined contract that is necessarily looser than the parent.

    However, this leads to odd behavior like this code passing:

    class A
    {
        void foo(int i) in (i > 0) { }
    }
    class B : A
    {
        void foo(int i) in (i < 0) { }
    }
    unittest { (new B).foo(5); }
    

    That is because the in contract of B.foo is implicitly super.in() || i < 0, ie. i > 0 || i < 0

    With -preview=inclusiveincontracts, this code will now fail with an AssertError. To reach the previous behavior, you would have to write out in (i > 0 || i < 0); that is, you explicitly include the parent's in contract in the child's.

  10. Add support for Objective-C protocols

    It's now possible to declare [Objective-C protocols][objc_protocol]. In D, this is declared using the interface keyword.

    To match the behavior of protocols in Objective-C, some additional changes have been made:

    • It's possible to declare optional methods in an interface. This is done
    with the @optional User Defined Attribute, available in the core.attributes module. An optional method is a method that does not have to be implemented in the class that implements the interface. To safely call an optional method, a runtime check should be performed to make sure the receiver implements the method.

    • It's possible to have static methods in an interface. This method is
    required to be implemented in the class that implements the interface (unless it's declared optional). Unlike in extern (D) interfaces, static methods in extern (Objective-C) cannot have a body.

    Example:

    import core.attribute : optional, selector;
    import std.stdio : writeln;
    
    struct objc_selector;
    alias SEL = objc_selector*;
    
    extern (C) SEL sel_registerName(in char* str);
    
    extern (Objective-C)
    extern class NSObject
    {
        static NSObject alloc() @selector("alloc");
        NSObject init() @selector("init");
    }
    
    extern (Objective-C)
    interface Foo
    {
        bool respondsToSelector(SEL sel) @selector("respondsToSelector:");
        void foo() @selector("foo");
    
        // this is an optional method
        @optional void bar() @selector("bar");
    }
    
    extern (Objective-C)
    class Bar : NSObject, Foo
    {
        override static Bar alloc() @selector("alloc");
        override Bar init() @selector("init");
    
        bool respondsToSelector(SEL sel) @selector("respondsToSelector:");
    
        void foo() @selector("foo")
        {
            writeln("foo");
        }
    }
    
    void main()
    {
        Foo f = Bar.alloc.init;
    
        // check, at runtime, if the instance `f` implements the method `bar`
        if (f.respondsToSelector(sel_registerName("bar")))
            f.bar();
        else
            f.foo();
    }
    

    [objc_protocol][https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html]

  11. Allow any compile-time argument in pragma(inline)

    Previously only true or false literals were allowed (the spec stated that integers worked, but they did not).

    Now the pragma can receive any compile-time expression convertible to bool, this expression will be evaluated only when the target function is actually used.

    For example, in the following code all three functions should be inlined:

    pragma(inline, canInline("func1"))
    void func1() {}
    
    void func2()
    {
        pragma(inline, canInline(__traits(identifier, __traits(parent, {}))));
    }
    
    pragma(inline, canInline("func3") || true)
    void func3() {}
    
    int canInline(string fname)
    {
        switch (fname)
        {
            case "func1":
            case "func2":
                return 1;
            default:
                return 0;
        }
    }
    
    void main()
    {
        func1();
        func2();
        func3();
    }
    
  12. Add __traits(getCppNamespaces, symbol) to retrieve the C++ namespaces a symbol resides in.

    This new trait returns a tuple of strings representing the namespace(s) the symbol resides in. This enables determining what namespaces a given symbol resides in for use in reflection, and can be used directly with an extern(C++) declaration as demonstrated below.

    extern(C++, "ns")
    struct Foo {}
    static assert(__traits(getCppNamespaces, Foo)[0] == "ns");
    struct Bar {}
    static assert(!__traits(getCppNamespaces, Foo).length);
    extern(C++, __traits(getCppNamespaces, Foo)) struct Baz {}
    static assert(__traits(getCppNamespaces, Foo) ==  __traits(getCppNamespaces, Baz));
    

Runtime changes

  1. Variables suspendSignalNumber and resumeSignalNumber are now private

    These variables, which are in core.thread.osthread, were accidentally exposed. They shouldn't be accessed directly and have been made private. In order to set GC signals, one should call thread_setGCSignals instead.

Library changes

  1. Return the number of characters consumed by std.conv.parse

    By setting the flag doCount to Yes.doCount, the function returns a named tuple. The tuple contains the fields data and count. The field data is of type Target and it contains the result of the original function. The field count is of type size_t and it contains the number of characters consumed. The function is keeping its original behaviour otherwise. Example:

    import std.typecons : Flag, Yes, No;
    
    string s1 = "123";
    auto a1 = parse!(int, string, Yes.doCount)(s1);
    assert(a1.data == 123 && a1.count == 3);
    
  2. Deprecate std.stdio.getdelim and std.stdio.getline

    The publicly available extern(C) bindings for getdelim and getline in std.stdio have been deprecated. Any code that still needs it can import the symbol from core.sys.posix.stdio in druntime instead.

  3. Add integer conversions in JSONValue.get

    JSONValue.get now allows to convert a stored uinteger or integer into any signed or unsigned integer. The conversion is performed with std.conv.to, and throws a ConvException in case of an integer overflow;

    auto json = parseJSON(`{"a": 123}`);
    writeln(json["a"].get!ubyte);
    

Dub changes

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

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

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

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

  2. The $DUB_BUILD_PATH variable was added

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

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

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

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

    Before this would have failed:

    "preBuildCommands": ["$DC -run foo.d"]
    

    unless DC was defined as environment variable outside DUB.

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

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


List of all bug fixes and enhancements in D 2.096.0:

DMD Compiler regressions

  1. Bugzilla 20661: opEquals not recognized for AA key (take two)
  2. Bugzilla 21177: printf check does not recognize GNU extensions
  3. Bugzilla 21319: DMD crashes on immutable circular reference
  4. Bugzilla 21505: Function alias reported as conflicting function
  5. Bugzilla 21513: [Reg 2.094.1] Slice assignment segmentation fault
  6. Bugzilla 21547: Oder of constructor declaration affects struct initializer
  7. Bugzilla 21590: assignment inside assert accepted if -checkaction=context is given
  8. Bugzilla 21678: "_d_arraysetlengthT is not callable using argument types" on chained array length assignment
  9. Bugzilla 21696: DMD 2.095.1 Compilation Crash

DMD Compiler bugs

  1. Bugzilla 5713: Broken final switch on ints
  2. Bugzilla 10619: Wrong local variable passed as alias arguments to templates
  3. Bugzilla 11717: CTFE: non-constant value with array and vector ops.
  4. Bugzilla 13667: ICE: stack overflow using self-referencing cast inside recursive alias this method
  5. Bugzilla 14831: Each function local symbols should have unique mangled name
  6. Bugzilla 15225: cannot overload directly aliased function literals
  7. Bugzilla 16635: Alias this for implicit conversion to "ref const(typeof(this))" causes dmd to segfault
  8. Bugzilla 17105: [ICE] SIMD Internal error with optimizations: backend\cod3.c 6807
  9. Bugzilla 18867: backend/cgcod.c crash on assignment to vector element
  10. Bugzilla 19788: compiler crash on slicing a enum typed as vector
  11. Bugzilla 20041: CTFE incorrect result with __vector
  12. Bugzilla 20111: asm VCVTPS2PH is not encoded correctly
  13. Bugzilla 20235: C++ ABI doesn't destruct struct arguments in the callee
  14. Bugzilla 20565: Local template declarations in different scopes produce uncaught name collisions
  15. Bugzilla 20695: Copy constructor disable default struct constructor
  16. Bugzilla 20821: Aliased template method confuses overload resolution
  17. Bugzilla 20868: DIP1000: scope delegate triggers error in unsafe code and it shouldn't
  18. Bugzilla 21214: simd: wrong diagnostic with unsupported vectors
  19. Bugzilla 21352: enum members should not be given UDAs of its parent enum declaration
  20. Bugzilla 21469: ICE core.simd when implementing _mm_set1_epi16
  21. Bugzilla 21471: Backend assertion triggered with -checkation=context and -inline
  22. Bugzilla 21472: -checkaction=context doesn't work with tupleof
  23. Bugzilla 21474: ICE with core.simd and -O (Illegal Instruction)
  24. Bugzilla 21481: functions in overloaded template are lost when the template overloads an alias
  25. Bugzilla 21489: Duplicated template instantiation using mixin inside alias declaration
  26. Bugzilla 21490: Optimizer can add SSE integer multiply for machines less than SSE4.1 which do not have it
  27. Bugzilla 21501: [REG 2.089.1] undefined identifier in package when using mixin and cyclic imports
  28. Bugzilla 21508: private class p in file p.d visible outside the file (module)
  29. Bugzilla 21515: extern(C) and extern(C++) returns creal in wrong order
  30. Bugzilla 21518: delegates not checked for attribute match in const arrays
  31. Bugzilla 21522: function gets lost when aliasing an overloaded function template
  32. Bugzilla 21526: x87 not rounding to precision on assignment on some platforms
  33. Bugzilla 21530: dtoh: Identifiers need to be sanitized wrt. reserved C++ keywords
  34. Bugzilla 21534: dtoh: Default params for default ctor missing template args
  35. Bugzilla 21543: dmd infinite loop on alias this and std.typecons.Nullable
  36. Bugzilla 21553: incorrect call to expressionSemantic() in statementsem.d
  37. Bugzilla 21569: Unable to rebuild DMD build using win32.mak - v2.095.0
  38. Bugzilla 21586: Struct dtor is called twice if struct is created inside ternary operator
  39. Bugzilla 21591: Mangling problem wrt. backrefs and function types
  40. Bugzilla 21598: checkaction=context reruns pure functions with debug blocks on failure
  41. Bugzilla 21614: compiled imports: core.exception.AssertError@src/dmd/semantic3.d(812): Assertion failure
  42. Bugzilla 21640: @live not working with templates
  43. Bugzilla 21647: pragma(msg) should be able to print a void type
  44. Bugzilla 21659: [OSX] core.stdc.config.__c_ulonglong is forward referenced while looking for sizeof
  45. Bugzilla 21662: Extern linkage variables cannot be of types with disabled default construction
  46. Bugzilla 21668: Cannot declare ref parameter of opaque type
  47. Bugzilla 21682: checkaction=context fails for expressions using static operator overloads

DMD Compiler enhancements

  1. Bugzilla 7176: Lambda => syntax for function and methods too
  2. Bugzilla 10445: add .min, .max, etc. properties for vector types
  3. Bugzilla 19632: [SIMD] Error: invalid foreach aggregate
  4. Bugzilla 20788: Difference between colored and non colored output
  5. Bugzilla 21527: Unnecessary store to memory in SIMD code
  6. Bugzilla 21567: build.d install fails, can't find dmd.conf
  7. Bugzilla 21593: Only update file time if file to be written already exists

Phobos regressions

  1. Bugzilla 21663: std.concurrency.receiveOnly doesn't work with tuples

Phobos bugs

  1. Bugzilla 13663: Comparison of Tuples with floating point fields
  2. Bugzilla 15136: If we want toStringz to be fully correct, it needs to stop checking for '\0'
  3. Bugzilla 17269: formattedWrite of struct with Nullable string fails
  4. Bugzilla 20508: std.math.pow(-infinity, y) does not return NaN for imaginary or complex results
  5. Bugzilla 20539: std.conv.to: internal overload conflict for enums with base types that have a catch-all opEquals overload (?)
  6. Bugzilla 20848: Bug in formatValueImpl
  7. Bugzilla 21103: isDynamicArray instantiates unecessary templates
  8. Bugzilla 21444: bad string concat in static assert message
  9. Bugzilla 21555: std.container.array: insertBack is wrong and should be tested for Array!bool
  10. Bugzilla 21556: std.container.array: insertAfter is wrong and should be tested
  11. Bugzilla 21609: LinearCongruentialEngine fails for m = 0
  12. Bugzilla 21634: std.bitmanip: bitfields may generate invalid variable
  13. Bugzilla 21635: std.bitmanip: bitfields should produce better error messages with wrong parameters
  14. Bugzilla 21636: std.bitmanip: bitfields size of bitfield should be checked against size of used type

Phobos enhancements

  1. Bugzilla 20552: Deprecated Nullable.get warning with Appenders
  2. Bugzilla 21523: Microsoft Windows std.stdio.File.lock(), tryLock(), unlock(): do not allocate memory for error messages when they are not needed
  3. Bugzilla 21559: Speed up walkLength for narrow strings
  4. Bugzilla 21629: std.csv report one record on empty input
  5. Bugzilla 21638: std.typecons.RefCounted!(T, RefCountedAutoInitialize.no) should still work when T.this() is annotated with @disable

Druntime regressions

  1. Bugzilla 21309: Missing core.thread.threadbase documentation
  2. Bugzilla 21642: [REG 2.084] hashOf will fail to compile for some structs/unions that recursively contain shared enums

Druntime bugs

  1. Bugzilla 8046: simd.d needs some documentation
  2. Bugzilla 21544: -checkaction=context formats enum members as their base type
  3. Bugzilla 21578: core.atomic.atomicFetchSub for pointers incorrectly calls wrong function from core.internal.atomic
  4. Bugzilla 21666: wrong printf format specifier for real with -checkaction=context on Win64

Druntime enhancements

  1. Bugzilla 14790: coverage merge should detect changed source code

dlang.org bugs

  1. Bugzilla 21292: Chrome by default now blocks downloading .dmg or .exe files via HTTP
  2. Bugzilla 21493: Documentation broken hyperlink std.stdio

Contributors to this release (55)

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

previous version: 2.095.0