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

            Bug ID: 70066
           Summary: alignas imposes the wrong limit on data members
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

On the x86_64-*-linux-gnu target, G++ enforces 128 bytes as the maximum
alignment for data members, even though GCC accepts much more restrictive
alignments.  For example, in the program below the struct is aligned on a
128-byte boundary in C++ but on a 256-byte boundary in C.

The C++ restriction is enforced by the
check_cxx_fundamental_alignment_constraints() function defined in
c-family/c-common.c.  The function uses the locally defined macro
MAX_TARGET_FIELD_ALIGNMENT as the upper bound on the alignment:

  #ifdef BIGGEST_FIELD_ALIGNMENT
  #define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_FIELD_ALIGNMENT
  #else
  #define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_ALIGNMENT
  #endif

The macro BIGGEST_FIELD_ALIGNMENT is not defined in this file, so the function
falls back on BIGGEST_ALIGNMENT which is 128 (the __BIGGEST_ALIGNMENT__ user
macro is defined to 16).

The BIGGEST_FIELD_ALIGNMENT macro is defined in config/i386/i386.h with the
following comment:

  /* ??? Blah -- this macro is used directly by libobjc.  Since it
     supports no vector modes, cut out the complexity and fall back
     on BIGGEST_FIELD_ALIGNMENT.  */
  #ifdef IN_TARGET_LIBS
  #ifdef __x86_64__
  #define BIGGEST_FIELD_ALIGNMENT 128
  ...

which happens to be the same as BIGGEST_ALIGNMENT.  However, both alignments
are in *bits* not *bytes* as assumed by the C++ functions, so G++ not only
enforces a more restrictive limit than G++, it also uses the wrong units.

In contrast, the far more liberal alignment limit enforced by the C front end
in the check_user_alignment() function uses the following test, allowing for
alignments of as great as 2^28 bytes:

  else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG)
    {
      error ("requested alignment is too large");
      return -1;


$ (set -x; cat t.c; cc="/build/gcc-trunk/gcc/xgcc -B /build/gcc-trunk/gcc"; for
lang in c c++; do $cc -S -Wall -Wextra -Wpedantic -x$lang t.c; done)
+ cat t.c
#if !__cplusplus
#  define alignas _Alignas
#endif

struct S { alignas (256) int i; };
+ cc='/build/gcc-trunk/gcc/xgcc -B /build/gcc-trunk/gcc'
+ for lang in c c++
+ /build/gcc-trunk/gcc/xgcc -B /build/gcc-trunk/gcc -S -Wall -Wextra -Wpedantic
-xc t.c
+ for lang in c c++
+ /build/gcc-trunk/gcc/xgcc -B /build/gcc-trunk/gcc -S -Wall -Wextra -Wpedantic
-xc++ t.c
t.c:5:30: warning: requested alignment 256 is larger than 128 [-Wattributes]
 struct S { alignas (256) int i; };
                              ^

Reply via email to