Skip to content

Instantly share code, notes, and snippets.

@burner
Last active May 29, 2026 15:37
Show Gist options
  • Select an option

  • Save burner/bed17b477eafd0f14385bef378a0eb73 to your computer and use it in GitHub Desktop.

Select an option

Save burner/bed17b477eafd0f14385bef378a0eb73 to your computer and use it in GitHub Desktop.
dlang deprecations

DMD Compiler Deprecation Reference

This document catalogs all active deprecation messages emitted by the DMD compiler, grouped by category. Each entry explains what is deprecated, why, and shows how to update your code.

Table of Contents

  1. Format String Checking (printf/scanf)
  2. Postblit Constructors
  3. Storage Class Issues
  4. Type System
  5. Function Semantics
  6. Statement-Level Issues
  7. Casts and Conversions
  8. Traits
  9. Expression-Level Issues
  10. Command-Line Switches
  11. Module and Symbol Deprecations
  12. Lexer

1. Format String Checking (printf/scanf)

DMD validates format strings in printf- and scanf-style functions at compile time. Mismatches between format specifiers and arguments are flagged as deprecations.

Source: compiler/src/dmd/chkformat.d

1.1 Invalid Format Specifier

format specifier "%.*s" is invalid

A format string contains a specifier that is not recognized by the C standard.

Deprecated:

import core.stdc.stdio : printf;

printf("%z"); // `%z` is not a valid specifier

Fix: Use a valid format specifier such as %d, %s, %x, %f, etc.

1.2 More Format Specifiers Than Arguments

more format specifiers than %d arguments

The format string references more arguments than are actually passed.

Deprecated:

import core.stdc.stdio : printf;

printf("%d %d %d", 1, 2); // 3 specifiers but only 2 arguments

Fix: Either add the missing arguments or remove the extra specifiers:

printf("%d %d", 1, 2);       // match arguments to specifiers
printf("%d %d %d", 1, 2, 3); // supply all three arguments

1.3 Argument Type Mismatch

argument X for format specification "Y" must be TYPE, not ACTUAL

The type of an argument does not match what the format specifier expects.

Deprecated:

import core.stdc.stdio : printf;

printf("%s", 42);       // `%s` expects a string, not an int
printf("%d", "hello");  // `%d` expects an int, not a string

Fix: Match argument types to their format specifiers:

printf("%d", 42);         // int for %d
printf("%s", "hello");    // string for %s

2. Postblit Constructors

Postblit constructors this(this) control copy semantics for structs. Qualified postblits (const, immutable, shared) are deprecated because the postblit always operates on the mutable copy being constructed.

Source: compiler/src/dmd/parse.d

2.1 Immutable Postblit

immutable postblit is deprecated. Please use an unqualified postblit.

Deprecated:

struct S
{
    immutable this(this) { } // deprecated
}

Replacement:

struct S
{
    this(this) { } // unqualified postblit
}

2.2 Shared Postblit

shared postblit is deprecated. Please use an unqualified postblit.

Deprecated:

struct S
{
    shared this(this) { } // deprecated
}

Replacement:

struct S
{
    this(this) { } // unqualified postblit
}

2.3 Const Postblit

const postblit is deprecated. Please use an unqualified postblit.

Deprecated:

struct S
{
    const this(this) { } // deprecated
}

Replacement:

struct S
{
    this(this) { } // unqualified postblit
}

2.4 Implicitly-Generated Postblit Hides Copy Constructor

struct S implicitly-generated postblit hides copy constructor.

A struct has fields with postblits and also defines a copy constructor. The implicitly-generated postblit takes priority, which can be surprising.

Source: compiler/src/dmd/clone.d

Deprecated:

struct Child
{
    this(this) { } // field postblit
}

struct S
{
    Child c;
    this(ref return scope S rhs) { } // copy constructor

    // DMD implicitly generates a postblit from `Child`'s postblit,
    // which hides this copy constructor.
}

Fix: Explicitly define a postblit, or disable it:

struct S
{
    Child c;
    @disable this(this); // disable the postblit, use copy constructor
    this(ref return scope S rhs) { }
}

3. Storage Class Issues

3.1 auto and ref Must Be Adjacent (Parameters)

auto and ref storage classes should be adjacent

When declaring a parameter as auto ref, the keywords auto and ref must appear next to each other.

Source: compiler/src/dmd/parse.d (deprecated in 2.111)

Deprecated:

void foo(auto const ref x) { } // auto and ref separated by const

Replacement:

void foo(const auto ref x) { } // auto ref adjacent
void foo(auto ref const x) { } // auto ref adjacent

3.2 auto ref Return Must Have auto and ref Adjacent

auto ref return type must have auto and ref adjacent

Same as above, but for function return types.

Source: compiler/src/dmd/funcsem.d (deprecated in 2.112)

Deprecated:

auto const ref foo() { return x; } // auto and ref separated

Replacement:

auto ref foo() { return x; } // auto ref adjacent

3.3 Function With enum Storage Class

function cannot have enum storage class

A function declaration was marked with enum, which makes no sense for functions.

Source: compiler/src/dmd/parse.d (deprecated in 2.105)

Deprecated:

enum void foo() { } // nonsensical

Fix: Remove the enum storage class from the function.

3.4 Storage Class Has No Effect in Type Aliases

storage class X has no effect in type aliases

A type alias was declared with a storage class (e.g., const, immutable) that does not apply to aliases.

Source: compiler/src/dmd/parse.d (deprecated since 2020)

Deprecated:

const alias T = int; // const has no effect on the alias
immutable alias T = int; // immutable has no effect

Fix: Remove the storage class from the alias:

alias T = int;

4. Type System

4.1 Complex Types

use of complex type TYPE is deprecated, use std.complex.Complex!(BASE) instead

Built-in complex types (cfloat, cdouble, creal) have been deprecated in favor of std.complex.Complex.

Source: compiler/src/dmd/typesem.d (deprecated in 2.097)

Deprecated:

cfloat z = 1.0f + 2.0fi;
cdouble z2 = 1.0 + 2.0i;

Replacement:

import std.complex;
auto z = Complex!float(1.0f, 2.0f);
auto z2 = Complex!double(1.0, 2.0);

4.2 Imaginary Types

use of imaginary type TYPE is deprecated, use BASE instead

Built-in imaginary types (ifloat, idouble, ireal) have been deprecated. The imaginary literal suffix i still works with the corresponding real type.

Source: compiler/src/dmd/typesem.d (deprecated in 2.097)

Deprecated:

ifloat x = 2.0fi;
idouble y = 3.0i;

Replacement:

// Use std.complex.Complex or plain floating point with imaginary literals
import std.complex;
auto x = Complex!float(0, 2.0f);
auto y = Complex!double(0, 3.0);

4.3 Package Not Accessible Without Static Import

SYMBOL is not accessible here, perhaps add 'static import PACKAGE;'

A symbol from a package is used but not directly accessible in the current scope.

Source: compiler/src/dmd/typesem.d

Deprecated:

import std.algorithm; // selective import
// using a symbol that requires static import

Fix: Use a static import to access the package:

static import std.algorithm;

4.4 in Parameters With Non-D Linkage

using in parameters with extern(LINK) functions is deprecated

The in keyword is shorthand for scope const, but its semantics do not translate to non-D calling conventions (e.g., extern(C), extern(C++)).

Source: compiler/src/dmd/typesem.d

Deprecated:

extern(C) void foo(in int x) { } // in is D-specific

Fix: Use explicit qualifiers instead:

extern(C) void foo(const int x) { } // explicit const
extern(C) void foo(int x) { }       // plain parameter

4.5 Typesafe Variadic Parameters With Class Type

typesafe variadic parameters with a class type (TYPE ARG...) are deprecated

D's typesafe variadic syntax T args... is a legacy feature when T is a class type.

Source: compiler/src/dmd/typesem.d (deprecated in 2.111)

Deprecated:

class Foo { }
void bar(Foo args...) { } // class typesafe variadic

Fix: Use an array parameter instead:

void bar(Foo[] args) { }

5. Function Semantics

5.1 Function Template Marked override

a function template is not virtual so cannot be marked override

Function templates are never virtual because they may have multiple instantiations. Marking them override is meaningless.

Source: compiler/src/dmd/parse.d (deprecated in 2.104)

Deprecated:

class C
{
    override void foo(T)() { } // template cannot be virtual
}

Fix: Remove override from template functions:

class C
{
    void foo(T)() { }
}

5.2 Function Template Marked abstract

a function template is not virtual so cannot be marked abstract

Same rationale as above. Function templates are never virtual.

Source: compiler/src/dmd/parse.d (deprecated in 2.104)

Deprecated:

abstract class C
{
    abstract void foo(T)() { } // template cannot be abstract
}

Fix: Remove abstract from template functions.

5.3 Overriding a Deprecated Method

DERIVED is overriding the deprecated method BASE

A non-deprecated function overrides a base class method that is marked deprecated. The overriding function should also be marked deprecated or the base method should no longer be deprecated.

Source: compiler/src/dmd/funcsem.d

Deprecated:

class Base
{
    deprecated void foo() { }
}

class Derived : Base
{
    override void foo() { } // overriding deprecated method without being deprecated
}

Fix: Mark the overriding function as deprecated too:

class Derived : Base
{
    deprecated override void foo() { }
}

5.4 Implicitly Overriding @__future Base Class Method

method NAME implicitly overrides @__future base class method; rename the former

A method in a derived class has the same name as a base class method marked @__future without using override. The @__future attribute means the base method will be added in a future version, so implicit overriding is suspicious.

Source: compiler/src/dmd/funcsem.d

Deprecated:

class Base
{
    @__future void foo() { }
}

class Derived : Base
{
    void foo() { } // implicitly overrides @__future method
}

Fix: Either add override or rename the method to avoid the collision:

class Derived : Base
{
    override void foo() { }  // explicit override
    // OR
    void bar() { }           // different name
}

5.5 @disable on Overriding Function

NAME cannot be annotated with @disable because it is overriding a function in the base class

An overriding function cannot be disabled because the base class contract requires it to be callable.

Source: compiler/src/dmd/funcsem.d

Deprecated:

class Base
{
    void foo() { }
}

class Derived : Base
{
    @disable override void foo() { } // cannot disable an override
}

Fix: Either don't override, or don't disable:

class Derived : Base
{
    override void foo() { } // override without disabling
}

5.6 deprecated on Overriding Function

NAME cannot be marked as deprecated because it is overriding a function in the base class

An overriding function inherits deprecation from its base, so marking it explicitly is redundant.

Source: compiler/src/dmd/funcsem.d

Deprecated:

class Base
{
    void foo() { }
}

class Derived : Base
{
    deprecated override void foo() { } // cannot mark override as deprecated
}

Fix: Remove deprecated from the overriding function:

class Derived : Base
{
    override void foo() { }
}

5.7 Overriding extern(C++) With const Qualified Function

overriding extern(C++) function BASE with const qualified function DERIVED is deprecated

C++ covariant rules differ from D's. Overriding an extern(C++) function while adding const qualification is deprecated.

Source: compiler/src/dmd/funcsem.d (deprecated in 2.110)

Deprecated:

extern(C++) class Base
{
    void foo() { }
}

extern(C++) class Derived : Base
{
    override void foo() const { } // adding const to extern(C++) override
}

Fix: Match the const qualifiers of the base class method, or remove override:

extern(C++) class Derived : Base
{
    override void foo() { } // match base class signature
}

5.8 Dual-Context Function

FUNCTION function requires a dual-context, which is deprecated

A nested function that requires access to two enclosing scopes (a "dual context") uses an underspecified feature that is being removed.

Source: compiler/src/dmd/semantic3.d (deprecated in 2.096)

Deprecated:

void outer()
{
    int a = 1;
    void middle()
    {
        int b = 2;
        void inner()
        {
            // inner needs both 'a' from outer and 'b' from middle
            // => dual context
            auto x = a + b;
        }
    }
}

Fix: Restructure the code so the inner function only needs one context, or pass needed variables explicitly:

void outer()
{
    int a = 1;
    void middle()
    {
        int b = 2;
        // Pass 'a' as a parameter instead of capturing from outer scope
        auto inner = (int outerA) {
            auto x = outerA + b; // only one enclosing context
        };
        inner(a);
    }
}

5.9 @safe Function Calling Unsafe Code (DIP1000 Transition)

@safe function CALLER calling CALLEE

During the DIP1000 transition, functions explicitly marked @safe that call code which will become @system under DIP1000 rules emit a deprecation.

Source: compiler/src/dmd/expressionsem.d, compiler/src/dmd/safe.d

Deprecated:

@safe void foo()
{
    int* p;
    // calling code that will become @system under DIP1000
    *p = 42;
}

Fix: Mark the function as @system or @trusted, or fix the safety violation:

@system void foo()
{
    int* p;
    *p = 42;
}

5.10 Function Overload Conflict With Different Attributes

FUNCTION NAME cannot overload extern(D) function at LOCATION

Two extern(D) functions with the same name and parameter types but different function attributes (e.g., @safe vs @system) cannot coexist.

Source: compiler/src/dmd/semantic2.d

Deprecated:

void foo() @safe { }
void foo() @system { } // different attributes, same signature

Fix: Use different function names or make the signatures distinct.


6. Statement-Level Issues

6.1 Bare catch Without Exception Type

catch statement without an exception specification is deprecated

A bare catch { } catches all Throwable, which is overly broad.

Source: compiler/src/dmd/parse.d

Deprecated:

try
{
    riskyOperation();
}
catch // no exception type specified
{
    handleIt();
}

Replacement:

try
{
    riskyOperation();
}
catch (Throwable) // explicit type
{
    handleIt();
}

6.2 return in scope(failure) Body

return statements cannot be in scope(failure) bodies.

A return inside a scope(failure) block can silently skip error handling.

Source: compiler/src/dmd/statementsem.d (deprecated in 2.100)

Deprecated:

void foo()
{
    scope(failure) return; // skipping error handling
    riskyOperation();
}

Fix: Use a try/catch block instead:

void foo()
{
    try
    {
        riskyOperation();
    }
    catch (Exception e)
    {
        // handle error properly
    }
}

6.3 Non-Zero Compile-Time Return From opApply

cannot return non-zero compile-time value from opApply

In a foreach using opApply, the loop body returns a non-zero compile-time constant. The opApply convention requires that non-zero results come from the delegate call.

Source: compiler/src/dmd/statementsem.d

Deprecated:

struct S
{
    int opApply(scope int delegate(size_t) dg)
    {
        return 1; // non-zero compile-time return from opApply
    }
}

void main()
{
    S s;
    foreach (i; s) { }
}

Fix: Return the delegate's result instead:

struct S
{
    int opApply(scope int delegate(size_t) dg)
    {
        foreach (i; 0 .. 10)
        {
            if (auto result = dg(i))
                return result; // propagate delegate result
        }
        return 0;
    }
}

6.4 asm Statement Marked @safe

asm statement cannot be marked @safe, use @system or @trusted instead

Inline assembly cannot be verified as memory-safe by the compiler.

Source: compiler/src/dmd/statementsem.d (deprecated in 2.104)

Deprecated:

@safe void foo()
{
    asm { nop; } // asm cannot be @safe
}

Replacement:

@system void foo()
{
    asm { nop; }
}

// OR use @trusted if you have verified safety
@trusted void foo()
{
    asm { nop; }
}

6.5 Throwing Qualified Type

cannot throw object of qualified type TYPE

Objects thrown with throw must be mutable or const, not immutable, shared, or inout.

Source: compiler/src/dmd/statementsem.d (deprecated in 2.102)

Deprecated:

immutable(Exception) e = new Exception("oops");
throw e; // throwing immutable object

Fix: Use a mutable or const exception:

auto e = new Exception("oops");
throw e;

6.6 Catching Non-Mutable/Non-Const Qualified Type

can only catch mutable or const qualified types, not TYPE

A catch block specifies an exception type with qualifiers beyond const (e.g., immutable, shared, inout).

Source: compiler/src/dmd/statementsem.d (deprecated in 2.105)

Deprecated:

try { ... }
catch (immutable Exception e) { } // cannot catch immutable

catch (shared Exception e) { }    // cannot catch shared

Fix: Catch by mutable or const reference:

try { ... }
catch (Exception e) { }        // mutable
catch (const Exception e) { }  // const

6.7 For-Loop Increment Has No Effect

EXPR has no effect

The increment expression of a for loop has no side effects and its value is discarded.

Source: compiler/src/dmd/statementsem.d (deprecated in 2.100)

Deprecated:

int x;
for (int i = 0; i < 10; x) // `x` has no effect as increment
{
    i++;
}

Fix: Use a meaningful increment:

for (int i = 0; i < 10; i++) { }

6.8 Return Expression Has No Effect

EXPR has no effect

A return expression in a void function has no side effects.

Source: compiler/src/dmd/statementsem.d (deprecated in 2.111)

Deprecated:

void foo()
{
    int x;
    return x; // returning value from void function, and x has no side effects
}

Fix: Remove the expression from return, or make it meaningful:

void foo()
{
    int x;
    return; // plain return from void function
}

6.9 Foreach Loop Index Implicit size_t Conversion

foreach: loop index implicitly converted from size_t to TYPE

The index variable in a foreach over an array has a type smaller than size_t, which could truncate for large arrays.

Source: compiler/src/dmd/statementsem.d

Deprecated:

int[] arr = [1, 2, 3];
foreach (int i, elem; arr) // int is smaller than size_t
{
    // i might overflow for large arrays
}

Fix: Use size_t or auto for the index:

foreach (size_t i, elem; arr) { }
foreach (i, elem; arr) { } // auto infers size_t

7. Casts and Conversions

7.1 Casting Delegate to Pointer

casting from TYPE to TYPE is deprecated

Casting a delegate to a pointer type accesses the delegate's internal representation, which is not portable.

Source: compiler/src/dmd/dcast.d

Deprecated:

void delegate() dg;
auto p = cast(void*) dg; // accessing delegate internals

Fix: If you need the function pointer, use .funcptr:

void delegate() dg;
auto fp = dg.funcptr; // explicit, portable access

7.2 Integral Promotion Not Done

integral promotion not done for EXPR, remove '-revert=intpromote' switch or cast(int)(EXPR)

Small integer types (byte, ubyte, short, ushort, char, wchar, dchar) should be promoted to int before arithmetic, per C rules. This only fires when the -revert=intpromote switch is active.

Source: compiler/src/dmd/dcast.d

Deprecated:

// compiled with -revert=intpromote
short a = 1, b = 2;
auto c = a + b; // no integral promotion to int

Fix: Remove -revert=intpromote from the command line, or cast explicitly:

short a = 1, b = 2;
auto c = cast(int)(a + b); // explicit promotion

7.3 Truncating Conversion in Compound Assignment

TYPE OP TYPE is performing truncating conversion

A compound assignment (+=, -=, *=, /=, %=, ^^=) on an integer type with a floating-point right operand causes a truncating conversion.

Source: compiler/src/dmd/expressionsem.d

Deprecated:

int x = 10;
x += 1.5; // truncating 1.5 to int

Fix: Cast explicitly or use matching types:

int x = 10;
x += cast(int) 1.5; // explicit cast
x += 1;             // matching types

8. Traits

8.1 __traits(isVirtualFunction) Renamed

traits(isVirtualFunction) is deprecated. Use traits(isVirtualMethod) instead

The name isVirtualFunction has been renamed to isVirtualMethod for clarity.

Source: compiler/src/dmd/traits.d (deprecated in 2.101)

Deprecated:

static assert(__traits(isVirtualFunction, obj.foo));

Replacement:

static assert(__traits(isVirtualMethod, obj.foo));

8.2 __traits(getVirtualFunctions) Renamed

traits(getVirtualFunctions) is deprecated. Use traits(getVirtualMethods) instead

The name getVirtualFunctions has been renamed to getVirtualMethods for clarity.

Source: compiler/src/dmd/traits.d (deprecated in 2.101)

Deprecated:

alias methods = __traits(getVirtualFunctions, MyClass);

Replacement:

alias methods = __traits(getVirtualMethods, MyClass);

8.3 __traits(getAttributes) on Overloaded Function

__traits(getAttributes) may only be used for individual functions, not the overload set NAME

__traits(getAttributes) was applied to an overloaded symbol instead of a specific overload.

Source: compiler/src/dmd/traits.d (deprecated in 2.100)

Deprecated:

void foo() { }
void foo(int x) { }

@(1) void foo();
@(2) void foo(int);

// getAttributes on overload set, not individual function
enum attrs = __traits(getAttributes, foo);

Fix: Use __traits(getOverloads) to select a specific overload:

// Select the first overload specifically
enum attrs = __traits(getAttributes, __traits(getOverloads, foo)[0]);

9. Expression-Level Issues

9.1 assert With String Literal Condition

assert condition cannot be a string literal

Using a string literal as the condition of assert was previously treated as truthy (non-empty string = true), which is error-prone.

Source: compiler/src/dmd/expressionsem.d (deprecated in 2.107)

Deprecated:

assert("this should be true"); // string literal as condition

Fix: Use a boolean condition:

assert(true, "this should be true"); // proper assert with message

9.2 static assert With String Literal Condition

static assert condition cannot be a string literal

Same as above, but for static assert.

Source: compiler/src/dmd/semantic2.d (deprecated in 2.107)

Deprecated:

static assert("this should be true");

Fix:

static assert(true, "this should be true");

9.3 Arrow Syntax Returning a Delegate

using (args) => { ... } to create a delegate that returns a delegate is error-prone.

When (args) => { ... } is written with curly braces after =>, it creates a delegate whose return value is another delegate. This is almost never what was intended.

Source: compiler/src/dmd/parse.d

Deprecated:

auto dg = (int x) => { return x + 1; };
// This creates a delegate that returns a delegate(int) => int
// NOT a delegate(int) => int

Fix: Use one of these forms instead:

// Multi-statement function literal (no =>)
auto dg = (int x) { return x + 1; };

// Single-expression lambda (no curly braces)
auto dg = (int x) => x + 1;

// If you truly want a delegate that returns a delegate, be explicit:
auto dg = (int x) => () { return x + 1; };

9.4 Initializing Field With Itself

cannot initialize field NAME with itself

In a constructor, a field is assigned to itself, likely due to a naming conflict between a parameter and a field.

Source: compiler/src/dmd/expressionsem.d (deprecated in 2.111)

Deprecated:

struct S
{
    int data;
    this(int data)
    {
        this.data = data; // both sides refer to the same field!
    }
}

Fix: Use distinct parameter names:

struct S
{
    int data;
    this(int value)
    {
        this.data = value;
    }
}

9.5 Identity Comparison of Static Arrays

identity comparison of static arrays implicitly coerces them to slices, which are compared by reference

Using is to compare static arrays implicitly slices them, comparing pointers instead of values.

Source: compiler/src/dmd/expressionsem.d

Deprecated:

int[3] a = [1, 2, 3];
int[3] b = [1, 2, 3];
if (a is b) { } // compares slice addresses, not values

Fix: Use == for value comparison:

if (a == b) { } // value comparison

9.6 Type Used as Value

type TYPE has no value

A type name was used as an operand to + or - where a value was expected.

Source: compiler/src/dmd/expressionsem.d (deprecated in 2.111)

Deprecated:

enum E { a, b }
auto x = E + 1; // E is a type, not a value

Fix: Use a value of that type:

auto x = E.a + 1;       // use an enum member
auto y = E.init + 1;    // use .init

9.7 Variable Shadowing in Foreach

SYMBOL NAME is shadowing SYMBOL NAME

A foreach loop variable has the same name as an outer variable, hiding it.

Source: compiler/src/dmd/expressionsem.d

Deprecated:

int x = 42;
foreach (x; [1, 2, 3]) // shadows outer `x`
{
    // `x` here is the loop variable, not the outer one
}

Fix: Use a different name for the loop variable:

int x = 42;
foreach (elem; [1, 2, 3])
{
    // `x` is still 42
}

9.8 Slice of Static Array Temporary Assigned to Longer-Lived Variable

slice of static array temporary returned by FUNC assigned to longer lived variable VAR

A function returns a static array by value, the result is sliced, and that slice is assigned to a variable that outlives the temporary. When the temporary is destroyed, the slice dangles.

Source: compiler/src/dmd/escape.d

Deprecated:

int[3] makeArray() { return [1, 2, 3]; }

void foo()
{
    int[] slice = makeArray()[]; // slice of temporary, dangles
}

Fix: Store the result in a variable of the static array type:

void foo()
{
    int[3] arr = makeArray(); // own the data
    int[] slice = arr[];      // safe: slice points to owned data
}

9.9 Const Variable Initialization in static this

MOD TYPE NAME initialization is not allowed in static this

A const variable initialized in a non-shared static constructor should use a shared static this instead, because const variables are implicitly shared across threads.

Source: compiler/src/dmd/expressionsem.d

Deprecated:

const int gValue;

static this()
{
    gValue = 42; // const variable in non-shared static ctor
}

Fix: Use a shared static constructor:

const int gValue;

shared static this()
{
    gValue = 42; // shared static ctor for const globals
}

10. Command-Line Switches

10.1 -dip25 No Longer Has Effect

-dip25 no longer has any effect

DIP25 (ref return scope checking) is now always enabled.

Source: compiler/src/dmd/mars.d

Fix: Remove -dip25 from your build configuration. The behavior is now the default.

10.2 -noboundscheck Deprecated

-noboundscheck is deprecated. Use -boundscheck=off instead

The -noboundscheck flag has been replaced by the more flexible -boundscheck=off.

Source: compiler/src/dmd/mars.d

Deprecated:

dmd -noboundscheck myapp.d

Replacement:

dmd -boundscheck=off myapp.d

10.3 -transition=16997 Is Now Default

-transition=16997 is now the default behavior

The fix from D language issue 16997 is now always applied.

Source: compiler/src/dmd/mars.d

Fix: Remove -transition=16997 from your build configuration.

10.4 -transition=intpromote Is Now Default

-transition=intpromote is now the default behavior

Integral promotion rules are now the default behavior.

Source: compiler/src/dmd/mars.d

Fix: Remove -transition=intpromote from your build configuration.

10.5 Deprecated Transition Features

-transition=FEATURE no longer has any effect.

A transition feature that was previously opt-in is now always enabled.

Source: compiler/src/dmd/mars.d

Fix: Remove the -transition=FEATURE flag from your build configuration.


11. Module and Symbol Deprecations

11.1 Using a Deprecated Symbol

SYMBOL NAME is deprecated

SYMBOL NAME is deprecated - MESSAGE

Using a symbol (function, variable, etc.) that has been marked with deprecated or deprecated("message").

Source: compiler/src/dmd/dsymbolsem.d

Deprecated:

deprecated("use bar instead") void foo() { }

void main()
{
    foo(); // using deprecated symbol
}

Fix: Use the recommended replacement:

void bar() { }

void main()
{
    bar(); // use the non-deprecated alternative
}

11.2 Deprecated alias this

alias NAME this is deprecated

alias NAME this is deprecated - MESSAGE

An alias this declaration is marked deprecated and code triggers it through implicit conversion.

Source: compiler/src/dmd/dsymbolsem.d

Deprecated:

struct S
{
    int value;
    deprecated alias value this; // deprecated alias this
}

void main()
{
    S s = S(42);
    int x = s; // triggers deprecated alias this
}

11.3 Deprecated Module

MODULE NAME is deprecated

MODULE NAME is deprecated - MESSAGE

Importing a module that has been marked deprecated.

Source: compiler/src/dmd/dsymbolsem.d

Deprecated:

deprecated("use std.regex instead") module oldregex;

// in another file:
import oldregex; // importing deprecated module

Fix: Import the recommended replacement module instead.

11.4 Non-D Linkage Static Constructor/Destructor

static CONSTRUCTOR can only be of D linkage

A static this() or static ~this() was declared inside a scope with non-D linkage (e.g., extern(C)).

Source: compiler/src/dmd/dsymbolsem.d

Deprecated:

extern(C)
{
    static this() { } // static ctor with C linkage
}

Fix: Move the static constructor outside the extern(C) block:

extern(C)
{
    // C-linkage declarations
}

static this() { } // D linkage (correct)

12. Lexer

12.1 C Preprocessor Directive in Token String

token string requires valid D tokens, not #NAME

A token string (q{ ... }) contains a C preprocessor directive like #define or #include, which is not a valid D token.

Source: compiler/src/dmd/lexer.d

Deprecated:

auto s = q{
    #include <stdio.h> // C preprocessor directive in token string
};

Fix: Use a plain string literal if you need to include non-D text:

auto s = `
    #include <stdio.h>
`;

Summary

Category Count Primary Source Files
Format String Checking 8 chkformat.d
Postblit Constructors 4 parse.d, clone.d
Storage Class Issues 4 parse.d, funcsem.d
Type System 5 typesem.d
Function Semantics 10 funcsem.d, parse.d, semantic3.d, safe.d, expressionsem.d, semantic2.d
Statement-Level Issues 9 statementsem.d, parse.d
Casts and Conversions 3 dcast.d, expressionsem.d
Traits 4 traits.d
Expression-Level Issues 9 expressionsem.d, escape.d, parse.d, semantic2.d
Command-Line Switches 5 mars.d
Module and Symbol Deprecations 5 dsymbolsem.d
Lexer 1 lexer.d
Total 67
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment