[dmd-internals] Errors emitted by the optimizer and the as-if rule

kenji hara k.hara.pg at gmail.com
Sat Aug 18 11:38:53 PDT 2012


2012/8/19 David Nadlinger <code at klickverbot.at>:
> Kenji's fix for issue 8339 introduces code which accesses a
> void-initialized variable without setting it first:
> https://github.com/D-Programming-Language/phobos/commit/4a0546480078d51a0ad4dbf141c71bf818e034ec
>
> I'm aware that it is contained inside an is(typeof()) check, and it
> seems like a clever solution to work around the underlying issue.
> However, DMD, with the optimizer enabled, would actually refuse to
> compile the code (even if a __traits(compiles, …) check returned
> true!), because access of uninitialized data is detected during data
> flow analysis somewhere in the optimizer, producing a "variable used
> before set"-type error.
>
> My point, which is only tangentially related to the bug fix in
> question, is that the optimizer in DMD grossly violates the "as-if"
> rule by changing the definition of what is legal D code. For example,
> the spec [1] says that accessing an uninitialized value results in
> undefined behavior. To me, this implies that code like this is fine if
> it is never executed. Yet, DMD for example refuses to compile a
> function which contains such an access of uninitialized data (or a
> null pointer dereference, …), even if that function is never invoked.
>
> In my opinion, this is clearly a bug. We can chose to either make
> accessing uninitialized data illegal – but the semantics of this are
> difficult to define in the general case due to the requirement of
> elaborate data flow analysis, somewhat defeating the point of having
> VoidInitializer in the first place –, _or_ to make it undefined
> behavior. Right now, we are doing a little of both, which is arguable
> the worst solution. It causes unexpected behavior of is(typeof()) and
> friends, and, much worse, leads to problems with cross-compiler
> compatibility: If a program includes piece of code which uses
> uninitialized data is never executed at runtime, it works fine when
> compiled GDC and LDC, in perfect agreement with the spec, yet DMD
> refuses to accept it.
>
> Yes, emitting a warning if use of uninitialized data is detected is
> most likely a good idea, but changing the language semantics depending
> on whether the optimizer is enabled is not.
>
> What do you think?

My answer is: optimizer doesn't affect the result of semantic analysis.
In other words, flow analysis by the optimizer also doesn't affect to
the compilation.

With the current DMD implementation, there is two *flow analysis*, the
former is checked by the front-end, the latter is checked by the
back-end. See the example code.

void foo() nothrow
{
    throw new Exception("");
    // "function test.foo 'foo' is nothrow yet may throw"
}
int bar(int n)
{
    if (n != 0)
        n = 1;
    else
        assert(0);
    // "function test.bar no return exp; or assert(0); at end of function"
}
void main()
{
    int n = void;
    printf("%d\n", n);
    // "Error: variable n used before set" with -O switch
}

nothrow and no return analysis, which occurs with and without -o-
switch, are checked by the front-end, and that is a part of language
specification.
The "used before set"  error disappears if you don't specify -O.
Therefore it is backend optimizer's work, and is not a part of the
spec.

Today, the flow analysis for uninitialized variable is not needed in
semantic analysis, so it doesn't become matter.

Kenji Hara


More information about the dmd-internals mailing list