Consider this simple Fortran test case: program uninit integer :: p,q p = -1 call sub(p, q) if (p<q) print *,"..." contains subroutine sub(i, o) integer, intent(in) :: i integer, intent(out) :: o if (i<0) then print *, "..." else o = 1 end if end subroutine end With -Wall and -O1 (or higher), all recent gfortran versions print: if (p<q) print *,"..." Warning: ‘q’ is used uninitialized in this function [-Wuninitialized] However, with -O0 or -Og, no warning is issued. It should be possible to detect that 'o' may be uninitialized by looking only at the subroutine itself (without any information about the caller).
The warning is issued because we inline sub. As we do not know whether 'o' is used we don't issue a warning in sub() that o is not initialized (does intent(out) mean it comes in uninitialized?). Just looking at the program sub has intent(out) q and thus we can reasonably expect it to be initialized. So - is 'o' uninitialized in subroutine test(o) integer, intent(out) :: o print *, o end subroutine ? It doesn't seem so (we don't warn but I also think we have no way to annotate sth as uninitalized that is passed by reference).
(In reply to Richard Biener from comment #1) > (does intent(out) mean it comes in uninitialized?) Yes. To quote the Fortran 2008 standard (from section 5.3.10): "The INTENT (OUT) attribute for a nonpointer dummy argument specifies that the dummy argument becomes undefined on invocation of the procedure, except for any subcomponents that are default-initialized (4.5.4.6)." > So - is 'o' uninitialized in > > subroutine test(o) > integer, intent(out) :: o > print *, o > end subroutine > > ? Absolutely (see above). Even if the actual argument has been initialized before invocation of the subroutine, the Fortran standard requires the compiler to treat 'o' as being uninitialized on entering the subroutine. > (we don't warn but I also think we have no way to > annotate sth as uninitalized that is passed by reference). :(
Here is a variant of the example in comment 0, where the subroutine has been substituted by a function: program uninit integer :: p,q p = -1 q = f(p) if (p<q) print *,"..." contains function f(i) result(o) integer, intent(in) :: i integer :: o if (i<0) then print *, "..." else o = 1 end if end function end This neither gives a warning (with -Wall) nor a runtime error (with -fcheck=all), but the function result (and thereby q) is clearly uninitialized. If I remove the conditional initialization of 'o' completely, I get: Warning: Return value ‘o’ of function ‘f’ declared at (1) not set [-Wreturn-type]
Confirmed from 4.8 up to trunk (8.0).
Pr31279 asks for a warning for a warning for call-by-reference arguments with known intent(in). This is the converse, but as I mentioned in pr31279 comment #7 the middle end infrastructure to issue these warnings is in place. The Fortran front end needs to make use of it. That being said, detecting read accesses to write-only arguments within the annotated function itself isn't implemented yet (only passing uninitialized arguments to read-only arguments is). So I suggest tracking the Fortran changes in pr31279 and the missing middle-end support here. $ cat z.c && gcc -S -Wall z.c __attribute__ ((access (read_only, 1))) void f1 (int *); void f2 (void) { int i; f1 (&i); // -Wuninitialized (good) } __attribute__ ((access (write_only, 1))) int g1 (int *p) { return *p; // missing warning } z.c: In function ‘f2’: z.c:7:3: warning: ‘i’ is used uninitialized [-Wuninitialized] 7 | f1 (&i); // -Wuninitialized (good) | ^~~~~~~ z.c:2:6: note: in a call to ‘f1’ declared with attribute ‘access (read_only, 1)’ here 2 | void f1 (int *); | ^~ z.c:6:7: note: ‘i’ declared here 6 | int i; | ^
I'm no longer working on this.
GCC 12.1 is being released, retargeting bugs to GCC 12.2.
GCC 12.2 is being released, retargeting bugs to GCC 12.3.
GCC 12.3 is being released, retargeting bugs to GCC 12.4.