Bug 91049 - wrong location in -Wreturn-local-addr for a return with a conditional expression
Summary: wrong location in -Wreturn-local-addr for a return with a conditional expression
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 9.0
: P3 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wreturn-local-addr
  Show dependency treegraph
 
Reported: 2019-07-01 22:51 UTC by Martin Sebor
Modified: 2020-01-27 13:31 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-27 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2019-07-01 22:51:31 UTC
The location of the underlining in the warning for the test case below is wrong: it should point at the &i:

$ cat a.C && gcc -O2 -S -Wall a.C
struct X { };

void* f (int i)
{
  X x;
  return i ?
         &i :
         throw x;
}
a.C: In function ‘void* f(int)’:
a.C:8:16: warning: function may return address of local variable [-Wreturn-local-addr]
    8 |          throw x;
      |                ^
a.C:3:14: note: declared here
    3 | void* f (int i)
      |          ~~~~^


Clang gets it right:

a.C:7:11: warning: address of stack memory associated with parameter 'i' returned [-Wreturn-stack-address]

         &i :

          ^
Comment 1 Marek Polacek 2019-07-09 14:07:22 UTC
This warning is generated in gimple-ssa-isolate-paths.c.
Comment 2 Martin Sebor 2019-07-09 15:50:48 UTC
I'm not sure this a middle-end issue.  The path isolation pass uses the location of the return statement to issue the warning.  In C, the location is that of the whole operand to the statement.  That also doesn't seem quite right but it's less confusing than in C++ where the location corresponds to just one of the operand (the second one?).  When the operand is not the address of a local variable it's plain wrong.

The difference in the location between C and C++ can be seen as early as the Gimple dump.  It only shows the beginning location so it's not complete but it's the starting location that's the problem.  Here's C:

$ cat a.C && gcc -O2 -S -Wall -fdump-tree-gimple-lineno=/dev/stdout -xc a.C
void* g (int i)
{
  extern int j;
  return i ?
         &i :
         &j;
}

g (int i)
[a.C:2:1] {
  void * D.1913;
  int * iftmp.0;
  extern int j;

  [a.C:4:12] i.1_1 = i;
  [a.C:5:13] if (i.1_1 != 0) goto <D.1915>; else goto <D.1916>;
  <D.1915>:
  [a.C:5:13] iftmp.0 = [a.C:5:10] &i;
  goto <D.1917>;
  <D.1916>:
  [a.C:5:13] iftmp.0 = [a.C:6:10] &j;
  <D.1917>:
  [a.C:5:13] D.1913 = iftmp.0;
  [a.C:5:13] return D.1913;
}


a.C: In function ‘g’:
a.C:5:13: warning: function may return address of local variable [-Wreturn-local-addr]
    4 |   return i ?
      |          ~~~ 
    5 |          &i :
      |          ~~~^
    6 |          &j;
      |          ~~  
a.C:1:14: note: declared here
    1 | void* g (int i)
      |          ~~~~^


and here's the dump for the same test case compiled as C++:

g (int i)
[a.C:6:12] {
  void * D.2304;
  int * iftmp.0;
  extern int j;

  [a.C:6:11] i.1_1 = i;
  [a.C:6:11] if (i.1_1 != 0) goto <D.2306>; else goto <D.2307>;
  <D.2306>:
  [a.C:6:11] iftmp.0 = [a.C:5:10] &i;
  goto <D.2308>;
  <D.2307>:
  [a.C:6:11] iftmp.0 = [a.C:6:10] &j;
  <D.2308>:
  [a.C:6:11] D.2304 = iftmp.0;
  [a.C:6:11] return D.2304;
}