Bug 48001 - inconsistent warning within loop always taken and outside the loop
Summary: inconsistent warning within loop always taken and outside the loop
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.5.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Blocks: Wuninitialized
  Show dependency treegraph
Reported: 2011-03-05 20:43 UTC by jerome.borme
Modified: 2011-03-05 22:25 UTC (History)
1 user (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description jerome.borme 2011-03-05 20:43:33 UTC
I checked bug meta-bug #24639, also bug #43361 and bug #27589, but I could not b sure this is a duplicate. The 3rd test below is the surprising one.

gcc -c -Wuninitialized test.c

/* 1st test */
int main () {
  int i, x ;
  x++ ;       // printf ("%d", x) ; would give the same result
  return 0 ;
-->  ‘x’ is used uninitialized in this function
This is expected, we should be incrementing x without first initialization. It works the same for x++ and printf x.

/* 2nd test */
#include <stdio.h>
int main () {
  int i, x ;
  for (i = 0 ; i < 10 ; i++) printf ("%d", x) ;
  return 0 ;
--> ‘x’ may be used uninitialized in this function
I think this corresponds to bug #27589. We should not printf x without initializing, but the compiler cannot be sure if we will actually be printed or not before  evaluating the “for” test at runtime.

/* 3rd test */
int main () {
  int i, x ;
  for (i = 0 ; i < 10 ; i++) x++ ;
  return 0 ;
--> No warning at all.
This is surprising:
* Outside a loop, both printf and x++ give the same warning.
* Inside a loop, printf will give a warning, while x++ will not do it.
Comment 1 jerome.borme 2011-03-05 20:46:12 UTC
Added link to meta-
Comment 2 Manuel López-Ibáñez 2011-03-05 21:41:16 UTC
This is because printf has side-effects (printing) but x++ does not have any side-effects (x is unused), therefore, gcc removes x completely in the third testcase. I guess the loop is also removed completely. This is a too artificial testcase, in the sense that we do not care that x is uninitialized because it is never used for anything.

We warn for the first testcase because the mechanism for detecting "is" is different from the mechanism for detecting "may be". The former happens before we remove the unused x, but the latter happens after in order to not warn for dead code.

There is also the problem that GCC cannot detect that loops are taken at least once, which makes it say "maybe" when it should actually be "is".

To be consistent, I would say that GCC shouldn't warn in the first testcase, or should warn as "is used" in the third testcase.
Comment 3 jerome.borme 2011-03-05 22:25:23 UTC
Here is a more complete part of a program where I found the problem. The following code will allocates 3 vectors fx, fy, fz with specific length, then call a function to display the averaged value of the fx, fy and fz, and the averaged value of sqrt (fx^2+fy^2+fz^2). In the even more complete version, maximum and minimum values of fx, fy, fz and sqrt (...) are also computed. After calculation, values are displayed.

The initialization of sum_f has been forgotten, but no warning is issued, although sum_f is used in the loop.

(Actually for some reason when I run this test, sum_f seems to have 0 even if it is not written there, but I believe this is coincidence, because in the real calculation code the displayed value was wrong.)

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100

void average (int nmax, double *fx, double *fy, double *fz)  {
  double sum_fx = 0, sum_fy = 0, sum_fz = 0, cur_f = 0, sum_f ;
  long int i ;
  for (i = 0 ; i < nmax ; i++) {
    sum_fx += fx[i] ;
    sum_fy += fy[i] ;
    sum_fz += fz[i] ;
    cur_f  = pow ((fx[i] * fx[i]) + (fy[i] * fy[i]) + (fz[i] * fz[i]), 0.5) ;
    sum_f  += cur_f ;
  printf ("# Average field : %g %g %g %g\n", sum_fx/nmax, sum_fy/nmax, sum_fz/nmax, sum_f/nmax) ;

int main () {
  long int i ;
  double *fx, *fy, *fz ;
  fx = (double *) malloc (SIZE * sizeof (double)) ;
  fy = (double *) malloc (SIZE * sizeof (double)) ;
  fz = (double *) malloc (SIZE * sizeof (double)) ;
  for (i = 0 ; i < SIZE ; i++) {
    fx[i] = 1 ;
    fy[i] = 1 ;
    fz[i] = 1 ;
  average (SIZE, fx, fy, fz) ;
  return 0 ;