Uninitialized variable warnings

Zack Weinberg zack@rabi.columbia.edu
Wed Mar 31 23:46:00 GMT 1999


>>>>There are a number of other places where gcc has gotten it wrong, and
>>>>a few places where the warning indicates a real bug.  There's also one
>>>>worrisome case, where we get it right or not unpredictably:
[...]
>>>Could you be more precise about "unpredictably"?
[...]
>>I mean that given two similar chunks of code one will get a warning
>>and the other won't, and the significant difference may seem to be
>>absolutely irrelevant as far as a human is concerned.  A good example
>>is the `plist' variable in objc-act.c:generate_protocol_list.  We warn
>>on that.  Prune everything else out of the function, and the compiler
>>doesn't warn anymore.
>
>Hmm, so it's possible there's an uninitialized-variable bug in the
>compiler, 

Unless we have false _negatives_ in -Wuninitialized, there don't seem
to be any problems with the section of the code (flow - I think) that
generates the warnings.

>but it might just be that the uninitialized-variable analysis
>(including all RTL transforms that precede it) is overly sensitive
>to things that would normally be thought of as irrelevant to the
>issue of whether a particular variable is initialized.

I believe it is CSE which is too sensitive.  Here is a real example.

/* x86, 2.93.12 19990314
   -O  -Wall: warning
   -O2 -Wall: warning
   -O  -Wall -DCASE2: no warning
   -O  -Wall -DCASE3: warning
   -O2 -Wall -DCASE3: no warning */

struct operation {
    short op;
    char rprio;
#ifndef CASE2
    char flags;
#endif
    char unsignedp;
    long value;
};

extern struct operation cpp_lex (void);

void
cpp_parse_expr (void)
{
  int rprio;
  struct operation op;

  for (;;)
    {
      op = cpp_lex ();

      switch (op.op)
	{
	case 0:
	  break;
#ifndef CASE3
	case 1:
	  return;
#endif
	case 2:
	  rprio = 1;
	  break;
	default:
	  return;
	}

      if (op.op == 0)
	return;

      if (rprio != 1)
	abort();
    }
}

This is too complicated for flow to get the uninit warnings right no
matter which case it is.  However, CSE is able to collapse CASE2 down to 

for (;;)
  {
    op = cpp_lex ();
    if (op.op != 2)
      break;
  }

which flow understands.  It can do the same with CASE3, but only if -O2.

Now, the only significant differences in -dj dumps for default and
CASE2 are that CASE2 has (subreg:HI (reg:DI N)) in a few places where
default has (reg:HI N), and the single insn that initializes reg N is
different in mode and offset.  I don't think there's a good reason for
cse to get this wrong.

zw



More information about the Gcc mailing list