dmd icon indicating copy to clipboard operation
dmd copied to clipboard

Inconsistent use-before-initialization behavior for aggregate fields

Open limepoutine opened this issue 1 month ago • 0 comments

Follow-up of Issue 15869. The fix is a band-aid and initialization is still extremely fragile depending on which optimization kicks in.

struct S {
    bool value;
    int a, b, c, d;
}

struct X(int opt) {
    S s = S(true);

    this(bool) {
        s = copyS();
    }

    static if (opt == 1) { // URVO
        S copyS() { return S(s.value); }
    }

    static if (opt == 2) { // NRVO
        S copyS() {
            S result;
            result.value = s.value;
            return result;
        }
    }

    static if (opt == 3) { // No RVO
        S copyS() {
            S result;
            result.value = s.value;
            return result;
            return S();
        }
    }
}

void main() {
    import std.stdio;

    X!1 x1 = X!1(true);
    X!2 x2 = X!2(true);
    X!3 x3 = X!3(true);

    writeln("URVO:   ", x1.s.value);
    writeln("NRVO:   ", x2.s.value);
    writeln("No RVO: ", x3.s.value);
}

Output on both DMD 2.111 and master:

$ dmd -run test.d
URVO:   false
NRVO:   false
No RVO: true

$ dmd -inline -run test.d
URVO:   true
NRVO:   false
No RVO: true

Adding an unused return statement changes the behavior, which is insane and prevents writing safe code IMO. I actually spent some time keeping the broken inliner behavior intact when working on the inliner.

limepoutine avatar Nov 21 '25 03:11 limepoutine