On 8/27/21 12:23 AM, Richard Biener wrote:
On Thu, Aug 26, 2021 at 9:30 PM Martin Sebor <mse...@gmail.com> wrote:

On 8/26/21 10:38 AM, Martin Sebor wrote:
On 8/26/21 1:00 AM, Richard Biener wrote:
On Wed, Aug 25, 2021 at 10:03 PM Martin Sebor <mse...@gmail.com> wrote:

Richard, some time ago you mentioned you'd had trouble getting
-Wuninitialized to print the note pointing to the uninitialized
variable.  I said I'd look into it, and so I did.  The attached
patch simplifies the warn_uninit() function to get rid of some
redundant cruft: besides a few pointless null tests and
a duplicate argument it also does away with ancient code that's
responsible for the problem you saw.  It turns out that tests
for the problem are already in the test suite but have been
xfailed since the day they were added, so the patch simply
removes the xfails.  I'll go ahead and commit this cleanup
as obvious later this week unless you have suggestions for
further changes.

I do see lots of useful refactoring.

-  if (context != NULL && gimple_has_location (context))
-    location = gimple_location (context);
-  else if (phiarg_loc != UNKNOWN_LOCATION)
-    location = phiarg_loc;
-  else
-    location = DECL_SOURCE_LOCATION (var);
+  /* Use either the location of the read statement or that of the PHI
+     argument, or that of the uninitialized variable, in that order,
+     whichever is valid.  */
+  location_t location = gimple_location (context);
+  if (location == UNKNOWN_LOCATION)
+    {
+      if (phi_arg_loc == UNKNOWN_LOCATION)
+       location = DECL_SOURCE_LOCATION (var);
+      else
+       location = phi_arg_loc;
+    }

the comment is an improvement but I think the original flow is
easier to follow ;)

It doesn't really simplify things so I can revert it.

I've done that and pushed r12-3165, and...

-      if (xloc.file != floc.file
-         || linemap_location_before_p (line_table, location, cfun_loc)
-         || linemap_location_before_p (line_table,
cfun->function_end_locus,
-                                       location))
-       inform (DECL_SOURCE_LOCATION (var), "%qD was declared here",
var);
...
+  inform (var_loc, "%qD was declared here", var);

and this is the actual change that "fixes" the missing diagnostics?  Can
you explain what the reason for the original sing-and-dance was?  It
looks like it tries to print the 'was declared here' only for locations
within the current function (but then it probably intended to do that
on the DECL_SOURCE_LOCATION (var), not on whatever we are
choosing now)?

The author(s) of the logic wanted to print the note only for variables
declared in functions other than the one the uninitialized read is in.
The idea first appears in pr17506, comment #25 (and attachment 12131).
At that time GCC would print no note at all and pr17506 was about
inlining making it difficult to find the uninitialized variable.
The originally reported problem can still be reproduced on Godbolt
(with the original very large translation unit):
    https://godbolt.org/z/8WW43rxnd

I've reduced it to a small test case:
    https://godbolt.org/z/rnPEfPqPf

It looks like they didn't think it would also be a problem if
the variable was defined and read in the same function, even
if the read was far away from the declaration.

Ah, OK.  I think that makes sense in principle, the test just looked
really weird - for the 'decl' it would be most natural to use sth
like decl_function_context (DECL_ORIGIN (var)) to determine
the function the variable was declared in and for the location of
the uninitialized use you'd similarly use

   tree ctx = BLOCK_ORIGIN (LOCATION_BLOCK (location));
   while (TREE_CODE ((ctx = BLOCK_SUPERCONTEXT (ctx))) != FUNCTION_DECL)
      ;

and then you can compare both functions.  This of course requires
a good location of the uninitialized use.

So I'm not sure whether we want to increase verboseness for say

int foo ()
{
    int i;
    i = i + 1;
    return i;
}

by telling the user 'i' was declared the line before the uninitialized use.

In this contrived case the note may not be important but it doesn't
hurt.  It's the more realistic cases of large functions with problem
statements far away from the objects they operate on, often indirectly,
via pointers, where providing the additional context is helpful.

This is also why most other middle end warnings (all those I worked
on) as well as other instances of -Wmaybe-uninitialized issue these
(and other) notes to provide enough detail to understand the problem.
The one we're discussion is an outlier.  For example this code:

void f (const int*, ...);

void g (int i)
{
  int a[4], *p = a + i;
  f (p, p[4]);
}

results in two warnings, each with its own note(s):

z.c: In function ‘g’:
z.c:6:3: warning: ‘a’ is used uninitialized [-Wuninitialized]
    6 |   f (p, p[4]);
      |   ^~~~~~~~~~~
z.c:5:7: note: ‘a’ declared here
    5 |   int a[4], *p = a + i;
      |       ^
z.c:6:3: warning: array subscript 4 is outside array bounds of ‘int[4]’ [-Warray-bounds]
    6 |   f (p, p[4]);
      |   ^~~~~~~~~~~
z.c:5:7: note: at offset 16 into object ‘a’ of size 16
    5 |   int a[4], *p = a + i;
      |       ^

Sure, it might seem like overkill for such a contrived example, but
again, it's the real-world code with functions dozens or hundreds
of lines long that I'm trying to help.


But I do think the code deserves a comment, so do you mind adding
one to say what it is about?

If you agree with the trend above in general, is the patch okay to
commit as is?

Martin


Thanks,
Richard.


That said, I'd prefer if you can commit the refactoring independently
of this core change and can try to dig why this was added and what
it was supposed to do.

Sure, let me do that.  Please let me know if the fix for the note
is okay to commit as is on its own.

...the removal of the test guarding the note is attached.


Martin


Thanks,
Richard.

Tested on x86_64-linux.

Martin



Reply via email to