Bug 91049

Summary: wrong location in -Wreturn-local-addr for a return with a conditional expression
Product: gcc Reporter: Martin Sebor <msebor>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: minor CC: webrown.cpp
Priority: P3 Keywords: diagnostic
Version: 9.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2020-01-27 00:00:00
Bug Depends on:    
Bug Blocks: 90556    

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;
}