https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378
Pedro Alves changed:
What|Removed |Added
CC||alves.ped at gmail dot com
--- Comment #2 from Pedro Alves ---
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
#include
struct Empty {};
struct S
{
[[no_unique_address]] Empty empty1;
[[no_unique_address]] Empty empty2;
[[no_unique_address]] Empty empty3;
} s;
int main ()
{
printf (" = %p\n", );
printf (" = %p\n", );
printf (" = %p\n", );
printf ("s = %p\n", );
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>: Abbrev Number: 10 (DW_TAG_member)
DW_AT_name: (indirect string, offset: 0x186f): empty1
...
DW_AT_data_member_location: -1
<2>: Abbrev Number: 2 (DW_TAG_member)
DW_AT_name: (indirect string, offset: 0x1876): empty2
...
DW_AT_data_member_location: 0
<2>: Abbrev Number: 2 (DW_TAG_member)
DW_AT_name: (indirect string, offset: 0x187d): empty3
...
DW_AT_data_member_location: 1
While at run time, we get:
$ ./test1
= 0x5627442ab011
= 0x5627442ab012
= 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
#include
struct Empty {};
struct S
{
int i;
[[no_unique_address]] Empty empty1;
[[no_unique_address]] Empty empty2;
} s;
int main ()
{
printf (" = %p\n", );
printf (" = %p\n", );
printf (" = %p\n", );
printf ("s = %p\n", );
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>: Abbrev Number: 9 (DW_TAG_member)
DW_AT_name: i
...
DW_AT_data_member_location: 0
<2>: Abbrev Number: 10 (DW_TAG_member)
DW_AT_name: (indirect string, offset: 0x1872): empty1
...
DW_AT_data_member_location: -1
<2>: Abbrev Number: 11 (DW_TAG_member)
DW_AT_name: (indirect string, offset: 0x1879): empty2
...
DW_AT_data_member_location: 3
while at run time:
$ ./test2
= 0x561fac538038
= 0x561fac538038
= 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.