Bug 45510 - Bug with anonymous unions and bit-fields
Summary: Bug with anonymous unions and bit-fields
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-09-02 23:39 UTC by runipg@broadcom.com
Modified: 2010-09-03 20:53 UTC (History)
1 user (show)

See Also:
Host: x86_64-unknown-linux-gnu
Target: x86_64-unknown-linux-gnu
Build: x86_64-unknown-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description runipg@broadcom.com 2010-09-02 23:39:04 UTC
        I have isolated the problem to a very small test program. 

         There are 2 tests in main, testa builds an anonymous union with bit-fields in it. testb builds a similar anonymous union but this time with a named structure in it but otherwise identical members.

         testa gives incorrect results (seems to ignore bit-fields). testb gives correct results. 

         This is the output of the program.

testa
bf0.data=0
bf0.a=0
bf0.b=0
bf0.data=1
bf0.a=1
bf0.b=1
bf0.data=1
bf0.a=1
bf0.b=1
testb
bf0.data=0
bf0.my.a=0
bf0.my.b=0
bf0.data=1
bf0.my.a=1
bf0.my.b=0
bf0.data=3
bf0.my.a=1
bf0.my.b=1

Environment:
System: Linux lc-sj1-2293 2.6.9-67.ELsmp #1 SMP Wed Nov 7 13:56:44 EST 2007 x86_64 x86_64 x86_64 GNU/Linux
Architecture: x86_64

	
host: x86_64-unknown-linux-gnu
build: x86_64-unknown-linux-gnu
target: x86_64-unknown-linux-gnu
configured with: ./configure --prefix=/tools/oss/packages/x86_64-rhel4/gcc/4.1.1 --with-gnu-as --with-as=/tools/oss/packages/x86_64-rhel4/binutils/default/bin/as --with-gnu-ld --with-ld=/tools/oss/packages/x86_64-rhel4/binutils/default/bin/ld --enable-languages=c,c++,objc

How-To-Repeat:

#include <iostream>
using namespace std;

struct bfa {
      union {
            unsigned int a : 1,
               b : 4;
            unsigned int data;
      };
};

struct bfb {
      struct my_struct {
            unsigned int a : 1,
               b : 4;
      };

      union {
            my_struct my;
            unsigned int data;
      };
};

void
testa()
{
   cout << __func__ << endl;

   bfa bf0;
   bf0.data = 0;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << bf0.b << endl;

   bf0.a = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << hex << bf0.b << endl;

   bf0.b = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << hex << bf0.b << endl;
}

void
testb()
{
   cout << __func__ << endl;

   bfb bf0;
   bf0.data = 0;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.my.a=" << bf0.my.a << endl;
   cout << "bf0.my.b=" << bf0.my.b << endl;

   bf0.my.a = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.my.a=" << bf0.my.a << endl;
   cout << "bf0.my.b=" << hex << bf0.my.b << endl;

   bf0.my.b = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.my.a=" << bf0.my.a << endl;
   cout << "bf0.my.b=" << hex << bf0.my.b << endl;
}

int
main(int argc, char** argv)
{
   testa();
   testb();
   return 0;
}
Comment 1 runipg@broadcom.com 2010-09-02 23:39:04 UTC
Fix:
	As mentioned testb is a work-around for the coding style used in testa.
Comment 2 Paolo Carlini 2010-09-03 00:02:18 UTC
Without having seriously looked into your code, I note that two completely different, closed source compilers (ICC and SunStudio) leads to the same behavior as GCC at runtime. Does your code actually "work" (behaves like you expect) somewhere?
Comment 3 runipg@broadcom.com 2010-09-03 01:03:01 UTC
Subject: Re:  Bug with anonymous unions and bit-fields

That was fast and interesting that two other compilers behave the same. 
Unfortunately I don't have access to any other compiler.  I am simply 
befuddled by the behavior though. I wouldn't file a bug, if I thought it 
was frivolous.

paolo dot carlini at oracle dot com wrote:
> ------- Comment #2 from paolo dot carlini at oracle dot com  2010-09-03 00:02 -------
> Without having seriously looked into your code, I note that two completely
> different, closed source compilers (ICC and SunStudio) leads to the same
> behavior as GCC at runtime. Does your code actually "work" (behaves like you
> expect) somewhere?
>
>
>   


Comment 4 Paolo Carlini 2010-09-03 01:09:48 UTC
Fair enough, but first blush I also don't see any text in the C++ Standard guaranteeing the behavior you want, wondered if you actually can get it with other compilers, maybe as implementation defined. Somebody else will properly triage this PR, anyway...
Comment 5 Andrew Pinski 2010-09-03 01:10:46 UTC
      union {
            unsigned int a : 1,
               b : 4;
            unsigned int data;
      };


This is an union of three elements each over lapping, that is a:1 overlaps with b:4 and data.  So this is expected behavior as far as I can tell.
Comment 6 Andrew Pinski 2010-09-03 01:13:01 UTC
You can use a GCC extension of anonymous structs:
struct bfa {
      union {
            struct {
            unsigned int a : 1,
               b : 4;
            };
            unsigned int data;
      };
};

To get the behavior you want.
Comment 7 runipg@broadcom.com 2010-09-03 03:31:10 UTC
Subject: Re:  Bug with anonymous unions and bit-fields

Wow, So there is a diff inside and outside a struct? 

This is very counter-intuitive but I am  to accept your explanation if that's what the language says. 

Thanks so much for looking into it and responding. Sorry if it is not a bug, I googled for anything similar before filing it.

-Runip

On 02-Sep-2010, at 6:11 PM, pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> wrote:

> 
> 
> ------- Comment #5 from pinskia at gcc dot gnu dot org  2010-09-03 01:10 -------
>      union {
>            unsigned int a : 1,
>               b : 4;
>            unsigned int data;
>      };
> 
> 
> This is an union of three elements each over lapping, that is a:1 overlaps with
> b:4 and data.  So this is expected behavior as far as I can tell.
> 
> 
> -- 
> 
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45510
> 
> ------- You are receiving this mail because: -------
> You reported the bug, or are watching the reporter.
> 

Comment 8 Paolo Carlini 2010-09-03 10:46:59 UTC
If you look at the actual Standard, both alignment and allocation of bit-fields are implementation defined. Thus, as far as I can see, at best we are talking about non-portable implementation defined behavior. If you want my advice, try to stay away from those tricks, with and without anonymous struct.
Comment 9 runipg@broadcom.com 2010-09-03 14:45:59 UTC
Subject: Re:  Bug with anonymous unions and bit-fields

Thank you so much. You can close this bug if you wish.


-Runip

On 03-Sep-2010, at 3:47 AM, paolo dot carlini at oracle dot com <gcc-bugzilla@gcc.gnu.org> wrote:

> 
> 
> ------- Comment #8 from paolo dot carlini at oracle dot com  2010-09-03 10:46 -------
> If you look at the actual Standard, both alignment and allocation of bit-fields
> are implementation defined. Thus, as far as I can see, at best we are talking
> about non-portable implementation defined behavior. If you want my advice, try
> to stay away from those tricks, with and without anonymous struct.
> 
> 
> -- 
> 
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45510
> 
> ------- You are receiving this mail because: -------
> You reported the bug, or are watching the reporter.
> 

Comment 10 runipg@broadcom.com 2010-09-03 19:19:28 UTC
Subject: Re:  Bug with anonymous unions and bit-fields

Your suggestion works:

struct bfc {
      union {
            struct {
                  unsigned int a : 1,
                     b : 4;
            };
            unsigned int data;
      };
};

void
testc()
{
   cout << __func__ << endl;

   bfc bf0;
   bf0.data = 0;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << bf0.b << endl;

   bf0.a = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << hex << bf0.b << endl;

   bf0.b = 1;

   cout << "bf0.data=" << hex << bf0.data << endl;
   cout << "bf0.a=" << bf0.a << endl;
   cout << "bf0.b=" << hex << bf0.b << endl;
}

Output is ....

testc
bf0.data=0
bf0.a=0
bf0.b=0
bf0.data=1
bf0.a=1
bf0.b=0
bf0.data=3
bf0.a=1
bf0.b=1
-----------------------------------------------------------------------------------

I guess the fundamental issue which confused me was:

struct bfa {
      union {
            unsigned int a : 1,
               b : 4;
            unsigned int data;
      };
};

that it appeared to be a union of 2 integers (one bit-field) rather than 
the implementation version where the union is of 3 integers 
(two-bitfields).  If the standard does not say anything specific about 
it, then I guess the compiler is free to do whatever it wants.

In fact, I tried a slight variation on bfa, where I tried to force 
alignment on the first integer packing.

struct bfd {
      union {
            unsigned int a : 1,
               b : 4,
                   : 0;   //force alignment
            unsigned int data;
      };
};

However this gives the same result as bfa.

So I guess semantically it is very confusing to a user. Perhaps this 
part of the language should be tightened.

Thanks Paolo!

-Runip

paolo dot carlini at oracle dot com wrote:
> ------- Comment #8 from paolo dot carlini at oracle dot com  2010-09-03 10:46 -------
> If you look at the actual Standard, both alignment and allocation of bit-fields
> are implementation defined. Thus, as far as I can see, at best we are talking
> about non-portable implementation defined behavior. If you want my advice, try
> to stay away from those tricks, with and without anonymous struct.
>
>
>   


Comment 11 Jakub Jelinek 2010-09-03 20:53:32 UTC
I don't see anything confusing about it.  If you have:
union { int a, b, c; } u;
u.a overlaps u.b and u.c as well, and the same applies to bitfields.  union isn't struct, see ISO C99 6.7.2.1/5.  The standard is clear on this.
Comment 12 runipg@broadcom.com 2010-09-03 21:12:33 UTC
Subject: Re:  Bug with anonymous unions and bit-fields

Okay, I guess I was confused by "struct or union" semantics. Thanks!


jakub at gcc dot gnu dot org wrote:
> ------- Comment #11 from jakub at gcc dot gnu dot org  2010-09-03 20:53 -------
> I don't see anything confusing about it.  If you have:
> union { int a, b, c; } u;
> u.a overlaps u.b and u.c as well, and the same applies to bitfields.  union
> isn't struct, see ISO C99 6.7.2.1/5.  The standard is clear on this.
>
>
>