Bug 66459

Summary: bogus warning 'w.offset' may be used uninitialized in this function [-Wmaybe-uninitialized]
Product: gcc Reporter: Mario Baumann <mario-baumann>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: manu, mikael, tkoenig
Priority: P3 Keywords: diagnostic
Version: 5.1.0   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67679
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88455
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2019-02-03 00:00:00
Bug Depends on:    
Bug Blocks: 24639    
Attachments: Fortran Fixed Form File

Description Mario Baumann 2015-06-08 11:02:27 UTC
Created attachment 35716 [details]
Fortran Fixed Form File

Hi All,

The attached file generates bogus warnings if compiled with -Wall AND -O1(or higher optimizations).


> gfortran -c -Wall -O1 foo.F
foo.F:14:0:

                W(J,I) = 0
 ^
Warning: 'w.offset' may be used uninitialized in this function [-Wmaybe-uninitialized]
foo.F:14:0: Warning: 'w.dim[1].stride' may be used uninitialized in this function [-Wmaybe-uninitialized]
 

> gfortran -v
Using built-in specs.
COLLECT_GCC=./gfortran
COLLECT_LTO_WRAPPER=/Build/gcc/5.1.0/install/libexec/gcc/x86_64-apple-darwin13/5.1.0/lto-wrapper
Target: x86_64-apple-darwin13
Configured with: /Source/gcc/5.1.0/configure --prefix=/Build/gcc/5.1.0/install --build=x86_64-apple-darwin13 --enable-languages=c,c++,fortran,lto --enable-cloog-backend=isl --enable-stage1-checking --enable-lto --enable-libstdcxx-time --with-system-zlib --disable-cloog-version-check --disable-nls --disable-libquadmath-support
Thread model: posix
gcc version 5.1.0 (GCC)


NOTEs:
- -O0 works fine
- same behaviour with gcc-4.9.2
Comment 1 Mikael Morin 2015-06-08 14:46:36 UTC
Confirmed.
Possibly related bug: PR60500

(In reply to Mario Baumann from comment #0)
> - -O0 works fine

This is expected, uninitializedness may only become apparent to the compiler after some optimization passes have simplified/reorganized the code.
Comment 2 Dominique d'Humieres 2015-11-04 17:49:54 UTC
> Possibly related bug: PR60500

Likely, but I get the warning for this PR for 4.5.4, but not 4.4.7, while the warnings for PR60500 appear only for 4.7.3.
Comment 3 Manuel López-Ibáñez 2016-09-07 20:23:25 UTC
If you do

gfortran -Wuninitialized test.f90 -fdump-tree-all-all-lineno -O1

and look at test.f90.162t.uninit1, we see:

  # .MEM_24 = PHI <.MEM_15(D)(28), .MEM_68(37)>
  # w$dim$1$stride_46 = PHI <w$dim$1$stride_85(D)(28), [test.f90:9:0] w$dim$1$stride_22(37)>
  # w$offset_26 = PHI <w$offset_16(D)(28), [test.f90:9:0] w$offset_56(37)>

but this code is transformed by optimization. The unoptimized SSA contains:

  [test.f90:9:0] # VUSE <.MEM_18>
  _22 = [test.f90:9:0] *m_21(D);
  [test.f90:9:0] _23 = MAX_EXPR <_22, 0>;
  [test.f90:9:0] _24 = (integer(kind=8)D.9) _23;
...
  [test.f90:9:0] _39 = _24;
...
  [test.f90:9:0] _68 = ~_39;
...
  [test.f90:9:0] wD.3400.offsetD.3387 = _68;

and the gimple generated by Fortran contains something similar:

            [test.f90:9:0] D.3429 = [test.f90:9:0] *mD.3381;
            [test.f90:9:0] D.3430 = MAX_EXPR <D.3429, 0>;
            [test.f90:9:0] D.3402 = (integer(kind=8)D.9) D.3430;

It seems that *mD.3381 is not initialized.

(It is very strange that gfortran converts user-defined variables to lowercase. It makes reading the dumps more difficult. It also does many unnecessary copies, making the code harder to analyze.)
Comment 4 Thomas Koenig 2019-02-03 10:21:57 UTC
The code that gfortran generates is correct, it is just that
the middle-end does not quite understand it and generates a
warning for it.

The -fdump-tree-original dump shows

      if (*l)
        {
          {
[...]
            w.dtype = {.elem_len=4, .rank=2, .type=1};
            D.3881 = (integer(kind=8)) MAX_EXPR <*m, 0>;
            D.3882 = NON_LVALUE_EXPR <__builtin_expect ((integer(kind=8)) (D.3881 == 0), 0, 46) ? 0 : __builtin_expect ((integer(kind=8)) (9223372036854775807 / D.3881 <= 0), 0, 41) ? 1 : 0>;
            D.3883 = NON_LVALUE_EXPR <D.3881>;
            D.3884 = (integer(kind=8)) MAX_EXPR <*n, 0>;
            D.3885 = (__builtin_expect ((integer(kind=8)) (D.3884 == 0), 0, 46) ? 0 : __builtin_expect ((integer(kind=8)) (9223372036854775807 / D.3884 < D.3883), 0, 41) ? 1 : 0) + D.3882;
            D.3886 = D.3883 * D.3884;
            D.3887 = D.3886;
            D.3888 = (__builtin_expect ((integer(kind=8)) ((unsigned long) D.3886 > 4611686018427387903), 0, 41) ? 1 : 0) + D.3885;
            D.3889 = ~NON_LVALUE_EXPR <D.3883>;
  
            if (D.3891)
              {
                size.0 = 0;
              }
            else
              {
                size.0 = (unsigned long) D.3886 * 4;
              }
            overflow.1 = D.3888;
            if (__builtin_expect ((integer(kind=8)) (overflow.1 != 0), 0, 41))
              {
                _gfortran_runtime_error (&"Ganzzahl\xc3\xbcberlauf bei der Berechnung des zu reservierenden Speichers"[1]{lb: 1 sz: 1});
              }
            else
              {
                if (__builtin_expect ((integer(kind=8)) (w.data != 0B), 0, 43))
                  {
                    _gfortran_runtime_error_at (&"At line 9 of file b.f"[1]{lb: 1 sz: 1}, &"Versuch, bereits reservierte Variable \xc2\xbb%s\xc2\xab zu reservieren"[1]{lb: 1 sz: 1}, &"w"[1]{lb: 1 sz: 1});
                  }
                else
                  {
                    w.data = (void * restrict) __builtin_malloc (MAX_EXPR <size.0, 1>);
                    if (__builtin_expect ((integer(kind=8)) (w.data == 0B), 0, 42))
                      {
                        _gfortran_os_error (&"Reservierung w\xc3\xbcrde Speichergrenze \xc3\xbcberschreiten"[1]{lb: 1 sz: 1});
                      }
                  }
              }
            w.dim[0].lbound = 1;
            w.dim[0].ubound = (integer(kind=8)) *m;
            w.dim[0].stride = 1;
            w.dim[1].lbound = 1;
            w.dim[1].ubound = (integer(kind=8)) *n;
            w.dim[1].stride = D.3883;
            w.offset = D.3889;
          }
        }

and then

                      if ((integer(kind=4)[0:] * restrict) w.data != 0B)
                        {
                          (*(integer(kind=4)[0:] * restrict) w.data)[(w.offset + (integer(kind=8)) i * w.dim[1].stride) + (integer(kind=8)) j] = 0;

Now, the thing is that, on leaving the if (*l) block, data has to be non-zero,
otherwise _gfortran_os_error would have been called (which is marked
with TREE_THIS_VOLATILE, hence noreturn). So, the variables 

Is there something the Fortran front end can do better? If not, I think
this is better classified as a middle-end bug.
Comment 5 Marc Glisse 2019-02-03 12:00:30 UTC
ESRA creates
  w$offset_132 = PHI <w$offset_95(D)(2), w$offset_103(21)>
before we read n. LIM later pulls some computations using w$offset_132 before the test on w.data, but that's not really relevant. I don't think there is anything the front-end can do about that, it seems to be purely middle-end, SRA creating exactly what uninit likes to warn about.