-mms_bitfields question

Hello,

We are using Clang for generating reflection data and ran into an issue with how Microsoft lays out bitfields. Here's the structure we were having a problem with:

        struct reflected woof
        {
           bool m_b1 : 1 reflected; // Clang bit offset: 0, MS bit offset: 0
           bool m_b2 : 1 reflected; // Clang bit offset: 1, MS bit offset: 1
           bool m_b3 : 1 reflected; // Clang bit offset: 2, MS bit offset: 2
           bool m_b4 : 1 reflected; // Clang bit offset: 3, MS bit offset: 3
           uint m_i1 reflected; // Clang bit offset: 32, MS bit offset: 32
           uint m_i2 : 5 reflected; // Clang bit offset: 64, MS bit offset: 64
           uint m_i3 : 8 reflected; // Clang bit offset: 69, MS bit offset: 69
           uint16 m_i5 : 2 reflected; // Clang bit offset: 77, MS bit offset: 96
           uint8 m_i4 : 2 reflected;
           uint8 m_ix1 : 2;
           uint16 m_i6 : 6 reflected;
        };

When compiling with Clang the bit offset of "m_i5" is 77, while when compiling with VS 2010 the bit offset is 96. We tried compiling with the "-mms-bitfields" command-line parameter but it didn't change the results. We stepped through Clang code and discovered that the "RecordLayoutBuilder::LayoutFields" function is looking for the "IsMsStruct" attribute. So we tried adding __attribute__((ms_struct)) to the structure and that fixed the problem. Adding "#pragma ms_struct on" also worked. We were wondering if the code inside "RecordLayoutBuilder::LayoutFields" should be checking "Context.getLangOpts().MSBitfields" along with "IsMsStruct":

        for (RecordDecl::field_iterator Field = D->field_begin(),
               FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
            if (IsMsStruct) { // <-- Should this check Context.getLangOpts().MSBitfields?
              FieldDecl *FD = *Field;
              if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
                ZeroLengthBitfield = FD;

        ...

          if (IsMsStruct && RemainingInAlignment && // <-- Should this check Context.getLangOpts().MSBitfields?
              LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {

Thanks for your help!

Jeremiah Zanin

Looking at the gcc docs, the computation of IsMsStruct (whether to use
ms_struct layout) should depend on getLangOpts().MSBitfields, and we
shouldn't check getLangOpts().MSBitfields directly anywhere else.

-Eli

Interesting. There is currently one place where it checks the compiler option (inside RecordLayoutBuilder::LayoutField) as well as IsMsStruct. There are several places just checking the MsStructAttr attribute. Would those need to be changed as well?

Jeremiah

Interesting. There is currently one place where it checks the compiler option (inside RecordLayoutBuilder::LayoutField) as well as IsMsStruct. There are several places just checking the MsStructAttr attribute. Would those need to be changed as well?

Yes... the -mms-bitfields is essentially a default which can be
overridden by ms_struct/gcc_struct.

-Eli

What's the best way to fix the places where the attribute is checked? Should RecordDecl have a member function or flag? Some other way?

Thanks!

Jeremiah