As noted in PR 52023, C11 _Alignof should return the *least* alignment required for a type in any context - meaning that on 32-bit x86, _Alignof (double) and _Alignof (long long) should be 4 not 8 because of the reduced alignment inside structures. (C++11 defines alignment requirements differently to be the requirement for a complete object of the given type, with an example involving virtual bases, so this issue doesn't apply to C++11 alignof.)
As far as I can tell there isn't anything in the compiler to compute this least alignment at present (it's the alignment you should be able to assume for an arbitrary pointer to the type, for example - except that actually trying to assume such alignments has been liable to run into problems, both because people expect small integers cast to pointer types to work as magic constants even if not properly aligned, and because people widely assume that badly aligned pointers will generally work on non-strict-alignment targets such as x86). This patch implements checks using BIGGEST_ALIGNMENT, BIGGEST_FIELD_ALIGNMENT and then calling ADJUST_FIELD_ALIGN on a synthetic FIELD_DECL - which, while not necessarily fully general, will I believe give the correct results for all ADJUST_FIELD_ALIGN definitions we have at present. Similarly, the testcase inherently needs to use __alignof__ (expression) or otherwise depend on things outside C11 as C11 doesn't provide a way to examine how aligned a given object is. The change is only made for C11 _Alignof (and _Alignas which is defined in terms of _Alignof), not for GNU __alignof__ to avoid breaking compatibility with uses of __alignof__ to define naturally-aligned fields on targets with this field-alignment peculiarity. Bootstrapped with no regressions on x86_64-unknown-linux-gnu (and spot-checked alignment values with -m32). Applied to mainline. c-family: 2013-12-04 Joseph Myers <jos...@codesourcery.com> PR c/52023 * c-common.c (c_sizeof_or_alignof_type): Add parameter min_alignof and check field alignment if set. * c-common.h (c_sizeof_or_alignof_type): Update prototype. (c_sizeof, c_alignof): Update calls to c_sizeof_or_alignof_type. c: 2013-12-04 Joseph Myers <jos...@codesourcery.com> PR c/52023 * c-parser.c (c_parser_alignas_specifier): Use c_sizeof_or_alignof_type instead of c_alignof. (c_parser_alignof_expression): Likewise, with min_alignof parameter depending on alignof spelling used. cp: 2013-12-04 Joseph Myers <jos...@codesourcery.com> PR c/52023 * typeck.c (cxx_sizeof_or_alignof_type): Update call to c_sizeof_or_alignof_type. objc: 2013-12-04 Joseph Myers <jos...@codesourcery.com> PR c/52023 * objc-act.c (objc_synthesize_getter): Update calls to c_sizeof_or_alignof_type. testsuite: 2013-12-04 Joseph Myers <jos...@codesourcery.com> PR c/52023 * gcc.dg/c11-align-6.c: New test. Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 205668) +++ objc/objc-act.c (working copy) @@ -7273,6 +7273,7 @@ objc_synthesize_getter (tree klass, tree class_met the same type, there is no need to lookup the ivar. */ size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property), true /* is_sizeof */, + false /* min_alignof */, false /* complain */); if (PROPERTY_NONATOMIC (property)) @@ -7474,6 +7475,7 @@ objc_synthesize_setter (tree klass, tree class_met the same type, there is no need to lookup the ivar. */ size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property), true /* is_sizeof */, + false /* min_alignof */, false /* complain */); if (PROPERTY_NONATOMIC (property)) Index: c/c-parser.c =================================================================== --- c/c-parser.c (revision 205668) +++ c/c-parser.c (working copy) @@ -3045,7 +3045,8 @@ c_parser_alignas_specifier (c_parser * parser) { struct c_type_name *type = c_parser_type_name (parser); if (type != NULL) - ret = c_alignof (loc, groktypename (type, NULL, NULL)); + ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL), + false, true, 1); } else ret = c_parser_expr_no_commas (parser, NULL).value; @@ -6446,11 +6447,12 @@ c_parser_alignof_expression (c_parser *parser) location_t loc = c_parser_peek_token (parser)->location; tree alignof_spelling = c_parser_peek_token (parser)->value; gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); + bool is_c11_alignof = strcmp (IDENTIFIER_POINTER (alignof_spelling), + "_Alignof") == 0; /* A diagnostic is not required for the use of this identifier in the implementation namespace; only diagnose it for the C11 spelling because of existing code using the other spellings. */ - if (!flag_isoc11 - && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0) + if (!flag_isoc11 && is_c11_alignof) { if (flag_isoc99) pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %qE", @@ -6494,7 +6496,9 @@ c_parser_alignof_expression (c_parser *parser) /* alignof ( type-name ). */ c_inhibit_evaluation_warnings--; in_alignof--; - ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL)); + ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, + NULL, NULL), + false, is_c11_alignof, 1); ret.original_code = ERROR_MARK; ret.original_type = NULL; return ret; Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 205668) +++ cp/typeck.c (working copy) @@ -1562,7 +1562,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_c } return c_sizeof_or_alignof_type (input_location, complete_type (type), - op == SIZEOF_EXPR, + op == SIZEOF_EXPR, false, complain); } Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 205668) +++ c-family/c-common.c (working copy) @@ -4921,14 +4921,17 @@ c_common_get_alias_set (tree t) } /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where - the second parameter indicates which OPERATOR is being applied. + the IS_SIZEOF parameter indicates which operator is being applied. The COMPLAIN flag controls whether we should diagnose possibly ill-formed constructs or not. LOC is the location of the SIZEOF or - TYPEOF operator. */ + TYPEOF operator. If MIN_ALIGNOF, the least alignment required for + a type in any context should be returned, rather than the normal + alignment for that type. */ tree c_sizeof_or_alignof_type (location_t loc, - tree type, bool is_sizeof, int complain) + tree type, bool is_sizeof, bool min_alignof, + int complain) { const char *op_name; tree value = NULL; @@ -4994,6 +4997,22 @@ c_sizeof_or_alignof_type (location_t loc, value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), size_int (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT)); + else if (min_alignof) + { + unsigned int align = TYPE_ALIGN (type); + align = MIN (align, BIGGEST_ALIGNMENT); +#ifdef BIGGEST_FIELD_ALIGNMENT + align = MIN (align, BIGGEST_FIELD_ALIGNMENT); +#endif + tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, + type); + unsigned int field_align = align; +#ifdef ADJUST_FIELD_ALIGN + field_align = ADJUST_FIELD_ALIGN (field, field_align); +#endif + align = MIN (align, field_align); + value = size_int (align / BITS_PER_UNIT); + } else value = size_int (TYPE_ALIGN_UNIT (type)); } Index: c-family/c-common.h =================================================================== --- c-family/c-common.h (revision 205668) +++ c-family/c-common.h (working copy) @@ -759,7 +759,7 @@ extern tree c_wrap_maybe_const (tree, bool); extern tree c_save_expr (tree); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); -extern tree c_sizeof_or_alignof_type (location_t, tree, bool, int); +extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ @@ -792,8 +792,8 @@ extern bool keyword_is_type_qualifier (enum rid); extern bool keyword_is_decl_specifier (enum rid); extern bool cxx_fundamental_alignment_p (unsigned); -#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, 1) -#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1) +#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, false, 1) +#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1) /* Subroutine of build_binary_op, used for certain operations. */ extern tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise); Index: testsuite/gcc.dg/c11-align-6.c =================================================================== --- testsuite/gcc.dg/c11-align-6.c (revision 0) +++ testsuite/gcc.dg/c11-align-6.c (revision 0) @@ -0,0 +1,40 @@ +/* Test C11 _Alignof returning minimum alignment for a type. PR + 52023. */ +/* { dg-do run } */ +/* { dg-options "-std=c11" } */ + +extern void abort (void); +extern void exit (int); + +#define CHECK_ALIGN(TYPE) \ + do \ + { \ + struct { char c; TYPE v; } x; \ + if (_Alignof (TYPE) > __alignof__ (x.v)) \ + abort (); \ + } \ + while (0) + +int +main (void) +{ + CHECK_ALIGN (_Bool); + CHECK_ALIGN (char); + CHECK_ALIGN (signed char); + CHECK_ALIGN (unsigned char); + CHECK_ALIGN (signed short); + CHECK_ALIGN (unsigned short); + CHECK_ALIGN (signed int); + CHECK_ALIGN (unsigned int); + CHECK_ALIGN (signed long); + CHECK_ALIGN (unsigned long); + CHECK_ALIGN (signed long long); + CHECK_ALIGN (unsigned long long); + CHECK_ALIGN (float); + CHECK_ALIGN (double); + CHECK_ALIGN (long double); + CHECK_ALIGN (_Complex float); + CHECK_ALIGN (_Complex double); + CHECK_ALIGN (_Complex long double); + exit (0); +} -- Joseph S. Myers jos...@codesourcery.com