https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378

Pedro Alves <alves.ped at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |alves.ped at gmail dot com

--- Comment #2 from Pedro Alves <alves.ped at gmail dot com> ---
It's indeed about [[no_unique_address]], and empty objects.

Here's a smaller reproducer:

$ cat test.cpp
struct Empty {​​​​​​​}​​​​​​​;
struct S
{​​​​​​​
  [[no_unique_address]] Empty empty;
}​​​​​​​ s;

$ g++ test.cpp -g -c -o test.o
$ readelf --debug-dump test.o | grep "DW_AT_data_member_location:"
    <3d>   DW_AT_data_member_location: -1

If you replace Empty with anything that isn't empty, you no longer get the -1.

Notice this too:

~~~
$ cat test1.cpp
#include <stdio.h>
#include <stddef.h>

struct Empty {};

struct S
{
  [[no_unique_address]] Empty empty1;
  [[no_unique_address]] Empty empty2;
  [[no_unique_address]] Empty empty3;
} s;

int main ()
{
  printf ("&s.empty1 = %p\n", &s.empty1);
  printf ("&s.empty2 = %p\n", &s.empty2);
  printf ("&s.empty3 = %p\n", &s.empty3);
  printf ("s = %p\n", &s);
  printf ("offset empty1 = %ld\n", offsetof (struct S, empty1));
  printf ("offset empty2 = %ld\n", offsetof (struct S, empty2));
  printf ("offset empty3 = %ld\n", offsetof (struct S, empty3));
  return 0;
}
~~~

The debug info shows:

 <2><a3>: Abbrev Number: 10 (DW_TAG_member)
    <a4>   DW_AT_name        : (indirect string, offset: 0x186f): empty1
...
    <af>   DW_AT_data_member_location: -1
 <2><b0>: Abbrev Number: 2 (DW_TAG_member)
    <b1>   DW_AT_name        : (indirect string, offset: 0x1876): empty2
...
    <ba>   DW_AT_data_member_location: 0
 <2><bb>: Abbrev Number: 2 (DW_TAG_member)
    <bc>   DW_AT_name        : (indirect string, offset: 0x187d): empty3
...
    <c5>   DW_AT_data_member_location: 1

While at run time, we get:

$ ./test1
&s.empty1 = 0x5627442ab011
&s.empty2 = 0x5627442ab012
&s.empty3 = 0x5627442ab013
s = 0x5627442ab011
offset empty1 = 0
offset empty2 = 1
offset empty3 = 2

So (0, 1, 2) at runtime, but (-1, 0, 1) in the DWARF.


And then note this, with a non-empty field added before
the empty ones:

~~~~
$ cat test2.cpp 
#include <stdio.h>
#include <stddef.h>

struct Empty {};

struct S
{
  int i;
  [[no_unique_address]] Empty empty1;
  [[no_unique_address]] Empty empty2;
} s;

int main ()
{
  printf ("&s.i = %p\n", &s.i);
  printf ("&s.empty1 = %p\n", &s.empty1);
  printf ("&s.empty2 = %p\n", &s.empty2);
  printf ("s = %p\n", &s);
  printf ("offset i = %ld\n", offsetof (struct S, i));
  printf ("offset empty1 = %ld\n", offsetof (struct S, empty1));
  printf ("offset empty2 = %ld\n", offsetof (struct S, empty2));
  return 0;
}

we see:

 <2><a3>: Abbrev Number: 9 (DW_TAG_member)
    <a4>   DW_AT_name        : i
...
    <ad>   DW_AT_data_member_location: 0
 <2><ae>: Abbrev Number: 10 (DW_TAG_member)
    <af>   DW_AT_name        : (indirect string, offset: 0x1872): empty1
...
    <ba>   DW_AT_data_member_location: -1
 <2><bb>: Abbrev Number: 11 (DW_TAG_member)
    <bc>   DW_AT_name        : (indirect string, offset: 0x1879): empty2
...
    <c7>   DW_AT_data_member_location: 3

while at run time:

 $ ./test2 
 &s.i = 0x561fac538038
 &s.empty1 = 0x561fac538038
 &s.empty2 = 0x561fac53803c
 s = 0x561fac538038
 offset i = 0
 offset empty1 = 0
 offset empty2 = 4

So it was (0, -1, 3) in the DWARF and (0, 0, 4) at run time.

This all seems to suggest an off by one for the empty fields in
the DWARF.

Reply via email to