9
votes

Optimization on/off doesn't matter. This is simplified code to demonstrate the warning. In the original routine all assignments and compares are to function expressions that could return a variety of values.

procedure test;
var i, k: integer;
begin
k := 21;
repeat
  if k = 20 then break;
  i := 5
until i = 5;
end;
2
Because if the first call of if k = 20 then evaluates true then break will stop the loop and there is no assignment for i at all. The compiler did not check the values but only the jump possibilities. - Sir Rufo
@sir: That doesn't sound right. The warning comes on the "until". Put "i:=k" after the "until i=5" and the warning is still there. "i" is definitely initialized if/when "until" is reached. If the "break" is taken the "until" isn't reached so "i" shouldn't matter. Still seems like an inappropriate warning. - Witness Protection ID 44583292
Thats why the warning tells you "... may not have been initialized". There is no deep analysis of your code - Sir Rufo
"Deep" analysis isn't necessary. The warning simply shouldn't appear on any line immediately preceded by an assignment to the variable in question, which is the case here. If the warning came on the "end", the warning would be true, but still worthless since there are no references to "i" there. The compiler seems to be fooled by the "break", as though the break leads to the "until" like a "continue" would. - Witness Protection ID 44583292

2 Answers

8
votes

This does seem to be a weakness in the compiler.

repeat
  if k = 20 then break;
  i := 5
until i = 5;

A human static analysis can easily check that i is always assigned before it is read. The line before the until assigns it. If that assignment is skipped by the break, then the until test is also skipped.

So, this can only be described as a compiler bug because the compiler should be able to understand how break and until interact. Clearly the compiler's analysis depends on an understanding of these things, since removing the break will also remove the warning. So it can only be that the compiler doesn't understand well enough.

It turns out that the 32 bit Windows compiler still behaves the same way in the current Delphi release, XE7. But the 64 bit compiler correctly emits no warning for your code.

Note that you might expect the compiler to realise that the condition in the if test in your code always evaluates False. Well, the compiler won't. It does not perform static analysis of constant propagation through non constant variables. Its analysis takes no account of the values that you place in variables.

0
votes

The reason why Delphi warns you about this is the fact that local variables don't get initialized automatically. What this means? This means that if you try reading any such variable it will return some more or less random result (contents of the memory it points to).

So as soon as Delphi recognizes a posibility that some variable might be read before anything is written to it (initialization of a variable does write a default value into it) the warning will be raised.
And this would happen in your code if the value of "k" would be 20 becouse the "i := 5" line would be skipped.

How do you solve this warning in your case? Simply set some value to "i" outside any loops or any conditional statments. For instance:

procedure test;
var i, k: integer;
begin
  //Set initial value for i
  i := 0;
  k := 21;
  repeat
    if k = 20 then break;
    i := 5
  until i = 5;
end;