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

previous version: 2.094.2 – next version: 2.095.1

Download D 2.095.0
released Jan 01, 2021

2.095.0 comes with 27 major changes and 78 fixed Bugzilla issues. A huge thanks goes to the 61 contributors who made 2.095.0 possible.

List of all bug fixes and enhancements in D 2.095.0.

Compiler changes

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


    module foo;
    struct Foo
      import std : writeln;
      private int _x;
      private ref int x() return
        writeln("ref int");
        return _x;
      int x() const
        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.
  2. 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.

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

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

    void foo(int) { }
    void foo(double) { } // deprecation

    This deprecation will become an error in 2.105.

  5. extern(Pascal) has been removed

    This unused linkage was deprecated in and has now been removed.

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

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

  8. 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 is implicitly || 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.

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


    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")
    void main()
        Foo f = Bar.alloc.init;
        // check, at runtime, if the instance `f` implements the method `bar`
        if (f.respondsToSelector(sel_registerName("bar")))


  10. 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;
                return 0;
    void main()
  11. 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( == 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, and throws a ConvException in case of an integer overflow;

    auto json = parseJSON(`{"a": 123}`);

Dub changes

  1. All commands now accept a version specification

    Before this release dub could only get an exact version for some commands (describe, generate, fetch, etc...). All commands now accept a version specification, such as can be found in dub.json / dub.sdl:

    dub fetch 'foo@>0.2.0' dub describe foo@'>=0.3.0 <1.0.0'

    Note that commands such as describe will still not fetch from the network.

  2. Dub will now automatically exclude mainSourceFile from other configurations

    By default, Dub uses all files it can find under its sourcePaths. However, a common pattern when dealing with multiple targets is to use configurations to represent said targets. In the case those targets are executables, users would be forced to add main files from other configurations to the excludedSourceFiles list, or store the main in a different directory outside of the sourcePaths.

    To simplify this workflow, Dub will now exclude files listed in mainSourceFile for other configuration. In case this is not desirable, the files need to be manually added to the sourceFiles list.

  3. Add support for -betterC compiler flag to the visuald project generator

    If betterC is specified in the buildOptions, visuald project files will also be configured to use betterC.

  4. Caching of generated unittest runner (dub test)

    For projects without a user-defined unittest configuration dub test generates a main file automatically. This main file is now being cached and won't be regenerated won subsequent runs without file changes.

  5. Allow custom build settings to be defined for dependencies

    For example:

        "name": "example",
        "dependencies": {
            "vibe-d": { "version" : "~>0.9.2", "dflags" : ["-preview=in"] }

    In this example, -preview=in will be applied to vibe-d and all of its dependencies. Any field will be parsed, however only dflags is taken into account when compiling for now.

  6. DFLAGS and LFLAGS no longer propagate to nested dub invocations

    DFLAGS and LFLAGS will no longer be exported as environment variables by default when invoking pre-generate, pre-build, pre-run, post-generate, post-build, or post-run commands.

    If the previous behavior is still desired, they can be accessed using $DFLAGS and $LFLAGS in dub.json E.g.: preGenerateCommands : ["DFLAGS=$DFLAGS env | grep DFLAGS"]

    will output DFLAGS environment variable with all the dflags used.

  7. Use DC environment variable as default D compiler

    dub now respects the DC environment variable, meaning that DC=ldc2 dub build will behave as dub build --compiler=ldc2. In case both are supplied, the --compiler switch still has priority. Note that when DUB recursively invokes itself, for example in preGenerateCommands, it sets the DC variable to the compiler it is using, meaning that nested dub invocation will now use the same compiler.

  8. Fix #2051 "Running unit tests from DUB single file packages fails"

    Now dub is capable run test command in single mode like: dub test --single yoursinglefile.d

  9. Improve ldc cross compilation

    Enables co-existence and parallel compilation of the same project with different settings (e.g. cross compilation) by moving .dub/obj to $DUB_TARGET_PATH/obj.

  10. Filter ability for list command

    For list command added optional filtration by name and version specification:

    dub list foo dub list foo@'>=0.1.0 <1.0.0'

  11. Support for .netrc file added

    Basic authentication credentials defined in .netrc file will now be taken into account while connecting to secured repositories.

List of all bug fixes and enhancements in D 2.095.0:

DMD Compiler regressions

  1. Bugzilla 20608: [REG2.087] Cannot pass tuple.expand to auto ref T... template argument pack
  2. Bugzilla 21282: mixin of AliasSeq "cannot alias an expression"
  3. Bugzilla 21294: [REG 2.095]: DMD fails to link since PR11743
  4. Bugzilla 21312: [REG 2.095] Newly triggered is not an lvalue and cannot be modified
  5. Bugzilla 21325: Flags not set for ?: evaluation with floating point operands
  6. Bugzilla 21328: Forwarding static float array element inside a lambda crashes dmd backend
  7. Bugzilla 21357: [REG2.093] postblit aliases old and new struct pointers
  8. Bugzilla 21364: Improperly aligned struct when one member is a GPR and the other is an XMM

DMD Compiler bugs

  1. Bugzilla 3713: Tail call optimization not enabled with the ?: operator
  2. Bugzilla 8156: Very slow compilation with string-imported file ~100 MiB
  3. Bugzilla 10664: Win64: exception handling does not work with COMDAT folding
  4. Bugzilla 11049: array bounds error uses module file name rather than file name modified by #line directive
  5. Bugzilla 11435: Pushing indirect ref to byte or short can read beyond edge of valid memory
  6. Bugzilla 14708: destructor for temporary not called during stack unwinding
  7. Bugzilla 15909: Duplicate case error reports characters as numbers
  8. Bugzilla 19754: cast() sometimes yields lvalue, sometimes yields rvalue
  9. Bugzilla 19970: [CTFE] 0 ptr is not null
  10. Bugzilla 20195: -preview=nosharedaccess has some access problems
  11. Bugzilla 20604: [ICE] dtoh ICE with nested template structs (and probably most templates
  12. Bugzilla 20652: extern(C++) doesn't seem to mangle the types in core.simd right
  13. Bugzilla 20714: Struct with postblitting member does not call it's copy constructor
  14. Bugzilla 20716: Wrong code/ABI for extern(C++) interface method that returns non-POD
  15. Bugzilla 20916: hard to find where a deprecation comes from
  16. Bugzilla 20965: Implicitly generated postblit overrides disabled copy ctor
  17. Bugzilla 20970: Test Suite Azure Pipelines Windows_LDC_Debug x64-debug-ldc failed due to heisenbug
  18. Bugzilla 21218: dtoh: protection attributes should be emitted to headers
  19. Bugzilla 21227: import(".\file") doesn't work on Windows
  20. Bugzilla 21234: Import expression can read files outside of -J path in case of symlink/hardlink
  21. Bugzilla 21246: Compiler must show mismatching types when functions do not properly override
  22. Bugzilla 21255: "overload alias ... forward declaration" when overload set of imported template functions is passed to alias template parameter
  23. Bugzilla 21271: C++ header generation ignores extern(D) class methods affecting vtable layout
  24. Bugzilla 21283: [C++] Wrong mangling for ref of parameter pack
  25. Bugzilla 21293: dtoh: segfault when encountering opaque enum
  26. Bugzilla 21299: [LINK] undefined reference to dmd.root.stringtable.StringValue!(Type).StringValue.lstring()
  27. Bugzilla 21300: C++ header generation produce nonsense code on enum with enum as parent
  28. Bugzilla 21320: @live mistakes borrowed pointer for owner in parameter
  29. Bugzilla 21424: Variable is incremented twice
  30. Bugzilla 21464: Superfluous module-level import affects attribute inference
  31. Bugzilla 21479: ternary operator returns wrong val with ref return
  32. Bugzilla 21514: [ICE] cod1.d:4015: Assertion `retregs || !*pretregs' failed with -m32

DMD Compiler enhancements

  1. Bugzilla 8044: Print names, not casted values when using enum template parameter
  2. Bugzilla 21204: Error in generated copy constructor gives confusing message
  3. Bugzilla 21259: struct initialization with deprecated fields should issue deprecation warnings
  4. Bugzilla 21275: Overload resolution bypasses private access
  5. Bugzilla 21340: extern(C++,(emptyTuple)) should result in no namespace not an error

Phobos bugs

  1. Bugzilla 13930: std.concurrency can't send immutable AA to another thread
  2. Bugzilla 15425: std.traits.hasIndirections fails to recognize nested structs
  3. Bugzilla 18789: std.stdio messes up UTF conversions on output
  4. Bugzilla 18801: std.stdio.File doesn't work with MSVCRT's UTF-8 mode
  5. Bugzilla 20924: std.numeric.gcd cannot be used with const BigInt
  6. Bugzilla 21231: Unreachable warning for empty struct in VariantN with preview=fieldwise
  7. Bugzilla 21249: clamp() is not stable and is not constrained
  8. Bugzilla 21253: Can't compile Variant.visit!(...) with generic function
  9. Bugzilla 21296: std.variant.Variant cannot be initialized with immutable AA
  10. Bugzilla 21302: std.uni's documentation contains a dead link to its source file
  11. Bugzilla 21452: isCallable erroneously returns false on function templates

Phobos enhancements

  1. Bugzilla 6484: compose can't take multi arg functions
  2. Bugzilla 20869: std.algorithm.mutation : move is overly trusting of opPostMove
  3. Bugzilla 20980: std.bigint.BigInt: special case x & non-negative int to avoid unnecessary allocation
  4. Bugzilla 21233: std.conv.parse doesn't report the number of characters consumed
  5. Bugzilla 21237: isLvalueAssignable and isRvalueAssignable should be public
  6. Bugzilla 21347: std.functional.adjoin should work in BetterC
  7. Bugzilla 21407: Make std.math.NaN and std.math.getNaNPayload work in CTFE
  8. Bugzilla 21408: Make std.math.nextUp and nextDown and nextafter work in CTFE for extended-precision real
  9. Bugzilla 21430: Add const to front, save, & length properties of range returned by std.bitmanip.bitsSet

Druntime bugs

  1. Bugzilla 14226: invalid Runtime.traceHandler setup
  2. Bugzilla 21421: core.stdcpp.new_.cpp_delete does not work with classes
  3. Bugzilla 21441: TypeInfo_Enum.destroy and TypeInfo_Enum.postblit not calling destroy and postblit of base type
  4. Bugzilla 21442: Calling AA.remove from a destructor might lead to InvalidMemoryOperationError
  5. Bugzilla 21468: Inscrutable template error when core.stdcpp.vector of a struct with a core.stdcpp.vector field is referenced before the struct's definition
  6. Bugzilla 21484: Infinite recursion in core.memory : GC.{get,set,clr}Attr(const scope void*...)

Druntime enhancements

  1. Bugzilla 21030: Reduce template function instantiations related to array equality
  2. Bugzilla 21417: core.stdcpp.new_.cpp_delete unnecessarily requires destruction to be @nogc
  3. Bugzilla 21426: dup, idup for arrays plus keys, values for associative arrays: call postblits directly instead of via TypeInfo function pointer bugs

  1. Bugzilla 21189: Plain Old Data and copy constructors
  2. Bugzilla 21273: [spec] Inexistent contrast for shell snippets make them unreadable (CSS)

Installer bugs

  1. Bugzilla 21433: "bash: line 952: --list-keys: command not found" when running on Catalina
  2. Bugzilla 21439: is disabled for LDC on FreeBSD

Contributors to this release (61)

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

previous version: 2.094.2 – next version: 2.095.1