LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 48875 - Wrong size of struct with overaligned bitfield
Summary: Wrong size of struct with overaligned bitfield
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: C (show other bugs)
Version: 11.0
Hardware: PC Linux
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-01-25 11:30 PST by ju.orth
Modified: 2021-01-26 07:37 PST (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ju.orth 2021-01-25 11:30:28 PST
Consider

struct Y {
        __declspec(align(128)) int i:1;
};

struct Z {
        char c;
        struct Y y;
};

int f(void) {
    return _Alignof(struct Y);
}

int g(void) {
    return sizeof(struct Z);
}

int h(void) {
    return &((struct Z *)0)->y;   // offsetof(struct Z, y)
}

MSVC returns

128
16
8

clang returns

128
256
128

on the aarch64-pc-windows-msvc target.

Apparently, on ARM targets, bitfields in structs increase the alignment of the struct to at most 8 bytes. Even though _Alignof incorrectly returns a higher value.
Comment 1 ju.orth 2021-01-26 07:37:15 PST
After some testing, the real behavior seems to be as follows:

// The effect of #pragma pack(N) depends on the target.
//
// x86: By default, there is no maximum field alignment. N={1,2,4} set the maximum field
//      alignment to that value. All other N activate the default.
// x64: By default, there is no maximum field alignment. N={1,2,4,8} set the maximum field
//      alignment to that value. All other N activate the default.
// arm: By default, the maximum field alignment is 8. N={1,2,4,8,16} set the maximum field
//      alignment to that value. All other N activate the default.
// arm64: By default, the maximum field alignment is 8. N={1,2,4,8} set the maximum field
//        alignment to that value. N=16 disables the maximum field alignment. All other N
//        activate the default.

struct A {
        __declspec(align(128)) int i:1;
};

struct B {
        struct A x;
};

#pragma pack(4)
struct C {
        struct A x;
};
#pragma pack()

#pragma pack(8)
struct D {
        struct A x;
};
#pragma pack()

#pragma pack(16)
struct E {
        struct A x;
};
#pragma pack()

#pragma pack(32)
struct F {
        struct A x;
};
#pragma pack()

static void f(void) {
#if defined(_M_IX86)
        static_assert(_Alignof(struct B) == 128, "");
        static_assert(_Alignof(struct C) == 4, "");
        static_assert(_Alignof(struct D) == 128, "");
        static_assert(_Alignof(struct E) == 128, "");
        static_assert(_Alignof(struct F) == 128, "");
#elif defined(_M_X64)
        static_assert(_Alignof(struct B) == 128, "");
        static_assert(_Alignof(struct C) == 4, "");
        static_assert(_Alignof(struct D) == 8, "");
        static_assert(_Alignof(struct E) == 128, "");
        static_assert(_Alignof(struct F) == 128, "");
#elif defined(_M_ARM)
        static_assert(_Alignof(struct B) == 8, "");
        static_assert(_Alignof(struct C) == 4, "");
        static_assert(_Alignof(struct D) == 8, "");
        static_assert(_Alignof(struct E) == 16, "");
        static_assert(_Alignof(struct F) == 8, "");
#elif defined(_M_ARM64)
        static_assert(_Alignof(struct B) == 8, "");
        static_assert(_Alignof(struct C) == 4, "");
        static_assert(_Alignof(struct D) == 8, "");
        static_assert(_Alignof(struct E) == 128, "");
        static_assert(_Alignof(struct F) == 8, "");
#else
        static_assert(0, "unknown target");
#endif
}