This patch adds support for most of the C1X alignment features (_Alignas, _Alignof, max_align_t, stdalign.h).
_Alignof is essentially GNU __alignof__, but restricted to be applied to types not expressions and not allowed on function types. It goes through the existing code, but with diagnostics for these cases (if pedantic) added along with such checks for use with pre-C1X standards (if pedantic). C++11 alignof also disallows use on function types, which was wrongly accepted before this patch; the fix is in common code and I added a C++ testcase for it. _Alignas is similar to the "aligned" attribute, but the value 0 is allowed as an operand. The checking code is shared with that attribute; a previously missing check that the operand has integer type (recall that integer constants cast to pointer types are represented as INTEGER_CSTs with pointer type) is added as it's required for _Alignas but also seems appropriate for the attribute. stddef.h gets a new type max_align_t (also in C++11 so enabled for that as well). I hope the definition here is appropriate for all supported targets. typedef struct { long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); } max_align_t; (The attributes there are because some targets may give types lower alignment inside structures and unions than outside; 32-bit x86 in particular.) As with stdnoreturn.h, the contents of stdalign.h are conditioned out for C++; I'll leave it to C++ people to work out what's most useful there if something nonempty is wanted (stdnoreturn.h is empty for C++, stdbool.h defines _Bool and bool to bool, true to true etc.). Also as with that header, I did nothing about adding it to USER_H in the MIPS SDE configuration, which I suggested there <http://gcc.gnu.org/ml/gcc-patches/2011-08/msg01521.html> should be deprecated. Missing from this patch are support for _Alignas in structures and unions, and checks that alignments are supported in the context in which they are used. Both of these involve issues I've raised with the WG14 reflector; for the former, the C1X syntax is missing productions to allow _Alignas in structures although it appears to be intended to be allowed. For the latter, the relevant context given alignment in structures ought to be the declaration of an object using the structure type rather than the type declaration itself, though "context" is only mentioned in constraints for _Alignas declarations. I think the right way of making the checks is unconditional errors if an object with static storage duration has an alignment greater than MAX_OFILE_ALIGNMENT (presently just a warning), or an object with automatic storage duration has an alignment greater than MAX_STACK_ALIGNMENT (presently the alignment is quietly ignored) - whether those alignments come from _Alignas or from the existing attributes; I don't think the existing behavior of compiling code without following the specified alignment is sensible. But obviously changing this does risk breaking existing code that specifies more alignment than it needs. The checks for alignof not being used pre-C1X if pedantic are conditional on the _Alignof spelling being used (rather than the existing __alignof or __alignof__) because otherwise they break bootstrap (code such as ansidecl.h expects to use __alignof__ without __extension__). Bootstrapped with no regressions on x86_64-unknown-linux-gnu. Applied to mainline. 2011-11-06 Joseph Myers <jos...@codesourcery.com> * c-decl.c (shadow_tag_warned, grokdeclarator): Handle _Alignas specifiers. (build_null_declspecs): Initialize align_log and alignas_p fields. (declspecs_add_alignas): New. * c-parser.c (c_token_starts_declspecs): Handle RID_ALIGNAS. (c_parser_declspecs): Handle _Alignas specifiers. (c_parser_alignas_specifier): New. (c_parser_alignof_expression): Diagnose alignof use for non-C1X. Diagnose _Alignof (expression). * c-tree.h (struct c_declspecs): Add align_log and alignas_p fields. (declspecs_add_alignas): Declare. * ginclude/stddef.h (max_align_t): Define for C1X and C++11. * ginclude/stdalign.h: New. * Makefile.in (USER_H): Add stdalign.h. c-family: 2011-11-06 Joseph Myers <jos...@codesourcery.com> * c-common.c (c_common_reswords): Add _Alignas and _Alignof. (c_sizeof_or_alignof_type): Diagnose alignof applied to a function type. (check_user_alignment): New. Split out of handle_aligned_attribute. Disallow integer constants with noninteger types. Conditionally allow zero. (handle_aligned_attribute): Use check_user_alignment. * c-common.h (RID_ALIGNAS, check_user_alignment): New. testsuite: 2011-11-06 Joseph Myers <jos...@codesourcery.com> * g++.dg/cpp0x/alignof3.C, gcc.dg/c1x-align-1.c, gcc.dg/c1x-align-2.c, gcc.dg/c1x-align-3.c, gcc.dg/c1x-align-4.c, gcc.dg/c90-align-1.c, gcc.dg/c99-align-1.c: New tests. * gcc.dg/gnu89-const-expr-1.c, gcc.dg/gnu90-const-expr-1.c, gcc.dg/gnu99-const-expr-1.c, gcc.dg/gnu99-static-1.c: Update expected diagnostics. Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 181033) +++ c-family/c-common.c (working copy) @@ -404,6 +404,8 @@ static int resort_field_decl_cmp (const */ const struct c_common_resword c_common_reswords[] = { + { "_Alignas", RID_ALIGNAS, D_CONLY }, + { "_Alignof", RID_ALIGNOF, D_CONLY }, { "_Bool", RID_BOOL, D_CONLY }, { "_Complex", RID_COMPLEX, 0 }, { "_Imaginary", RID_IMAGINARY, D_CONLY }, @@ -4332,7 +4334,18 @@ c_sizeof_or_alignof_type (location_t loc value = size_one_node; } else - value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + { + if (complain) + { + if (c_dialect_cxx ()) + pedwarn (loc, OPT_pedantic, "ISO C++ does not permit " + "%<alignof%> applied to a function type"); + else + pedwarn (loc, OPT_pedantic, "ISO C does not permit " + "%<_Alignof%> applied to a function type"); + } + value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + } } else if (type_code == VOID_TYPE || type_code == ERROR_MARK) { @@ -6670,6 +6683,36 @@ handle_section_attribute (tree *node, tr return NULL_TREE; } +/* Check whether ALIGN is a valid user-specified alignment. If so, + return its base-2 log; if not, output an error and return -1. If + ALLOW_ZERO then 0 is valid and should result in a return of -1 with + no error. */ +int +check_user_alignment (const_tree align, bool allow_zero) +{ + int i; + + if (!INTEGRAL_TYPE_P (TREE_TYPE (align)) + || TREE_CODE (align) != INTEGER_CST) + { + error ("requested alignment is not an integer constant"); + return -1; + } + else if (allow_zero && integer_zerop (align)) + return -1; + else if ((i = tree_log2 (align)) == -1) + { + error ("requested alignment is not a power of 2"); + return -1; + } + else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG) + { + error ("requested alignment is too large"); + return -1; + } + return i; +} + /* Handle a "aligned" attribute; arguments as in struct attribute_spec.handler. */ @@ -6693,21 +6736,8 @@ handle_aligned_attribute (tree *node, tr else if (TYPE_P (*node)) type = node, is_type = 1; - if (TREE_CODE (align_expr) != INTEGER_CST) - { - error ("requested alignment is not a constant"); - *no_add_attrs = true; - } - else if ((i = tree_log2 (align_expr)) == -1) - { - error ("requested alignment is not a power of 2"); - *no_add_attrs = true; - } - else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG) - { - error ("requested alignment is too large"); - *no_add_attrs = true; - } + if ((i = check_user_alignment (align_expr, false)) == -1) + *no_add_attrs = true; else if (is_type) { if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) Index: c-family/c-common.h =================================================================== --- c-family/c-common.h (revision 181033) +++ c-family/c-common.h (working copy) @@ -106,6 +106,9 @@ enum rid RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, RID_FRACT, RID_ACCUM, + /* C1X */ + RID_ALIGNAS, + /* This means to warn that this is a C++ keyword, and then treat it as a normal identifier. */ RID_CXX_COMPAT_WARN, @@ -724,6 +727,7 @@ extern void finish_fname_decls (void); extern const char *fname_as_string (int); extern tree fname_decl (location_t, unsigned, tree); +extern int check_user_alignment (const_tree, bool); extern void check_function_arguments (const_tree, int, tree *); extern void check_function_arguments_recurse (void (*) (void *, tree, Index: ginclude/stddef.h =================================================================== --- ginclude/stddef.h (revision 181033) +++ ginclude/stddef.h (working copy) @@ -1,4 +1,4 @@ -/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002, 2004, 2009 +/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002, 2004, 2009, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -412,6 +412,20 @@ typedef __WINT_TYPE__ wint_t; /* Offset of member MEMBER in a struct of type TYPE. */ #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 199901L) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) +#ifndef _GCC_MAX_ALIGN_T +#define _GCC_MAX_ALIGN_T +/* Type whose alignment is supported in every context and is at least + as great as that of any standard type not using alignment + specifiers. */ +typedef struct { + long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); + long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); +} max_align_t; +#endif +#endif /* C1X or C++11. */ + #endif /* _STDDEF_H was defined this time */ #endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__ Index: ginclude/stdalign.h =================================================================== --- ginclude/stdalign.h (revision 0) +++ ginclude/stdalign.h (revision 0) @@ -0,0 +1,39 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* ISO C1X: 7.15 Alignment <stdalign.h>. */ + +#ifndef _STDALIGN_H +#define _STDALIGN_H + +#ifndef __cplusplus + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif + +#endif /* stdalign.h */ Index: testsuite/gcc.dg/gnu99-static-1.c =================================================================== --- testsuite/gcc.dg/gnu99-static-1.c (revision 181033) +++ testsuite/gcc.dg/gnu99-static-1.c (working copy) @@ -11,7 +11,7 @@ /* __alignof__, OK. */ static int f0(void); -void g0(void) { __alignof__(f0()); } +void g0(void) { __alignof__(f0()); } /* { dg-error "__alignof__ \\(expression\\)" } */ /* __typeof__ not variably modified, OK. */ static int f1(void); Index: testsuite/gcc.dg/c1x-align-4.c =================================================================== --- testsuite/gcc.dg/c1x-align-4.c (revision 0) +++ testsuite/gcc.dg/c1x-align-4.c (revision 0) @@ -0,0 +1,8 @@ +/* Test C1X alignment support. Test reducing alignment (assumes there + are at least some alignment constraints). */ +/* { dg-do compile } */ +/* { dg-options "-std=c1x -pedantic-errors" } */ + +#include <stddef.h> + +_Alignas (_Alignof (char)) max_align_t x; /* { dg-error "reduce alignment" } */ Index: testsuite/gcc.dg/c1x-align-1.c =================================================================== --- testsuite/gcc.dg/c1x-align-1.c (revision 0) +++ testsuite/gcc.dg/c1x-align-1.c (revision 0) @@ -0,0 +1,41 @@ +/* Test C1X alignment support. Test valid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=c1x -pedantic-errors" } */ + +#include <stddef.h> + +_Alignas (_Alignof (max_align_t)) char c; +extern _Alignas (max_align_t) char c; +extern char c; + +extern _Alignas (max_align_t) short s; +_Alignas (max_align_t) short s; + +_Alignas (int) int i; +extern int i; + +_Alignas (max_align_t) long l; + +_Alignas (max_align_t) long long ll; + +_Alignas (max_align_t) float f; + +_Alignas (max_align_t) double d; + +_Alignas (max_align_t) _Complex long double cld; + +_Alignas (0) _Alignas (int) _Alignas (char) char ca[10]; + +_Alignas ((int) _Alignof (max_align_t) + 0) int x; + +enum e { E = _Alignof (max_align_t) }; +_Alignas (E) int y; + +void +func (void) +{ + _Alignas (max_align_t) long long auto_ll; +} + +/* Valid, but useless. */ +_Alignas (0) struct s; /* { dg-warning "useless" } */ Index: testsuite/gcc.dg/c99-align-1.c =================================================================== --- testsuite/gcc.dg/c99-align-1.c (revision 0) +++ testsuite/gcc.dg/c99-align-1.c (revision 0) @@ -0,0 +1,6 @@ +/* Test _Alignof and _Alignas not in C99. */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ + +int a = _Alignof (int); /* { dg-error "ISO C99 does not support '_Alignof'" } */ +_Alignas (int) int b; /* { dg-error "ISO C99 does not support '_Alignas'" } */ Index: testsuite/gcc.dg/c90-align-1.c =================================================================== --- testsuite/gcc.dg/c90-align-1.c (revision 0) +++ testsuite/gcc.dg/c90-align-1.c (revision 0) @@ -0,0 +1,6 @@ +/* Test _Alignof and _Alignas not in C90. */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */ + +int a = _Alignof (int); /* { dg-error "ISO C90 does not support '_Alignof'" } */ +_Alignas (int) int b; /* { dg-error "ISO C90 does not support '_Alignas'" } */ Index: testsuite/gcc.dg/gnu90-const-expr-1.c =================================================================== --- testsuite/gcc.dg/gnu90-const-expr-1.c (revision 181033) +++ testsuite/gcc.dg/gnu90-const-expr-1.c (working copy) @@ -23,7 +23,7 @@ f (void) E5 = __imag__ 0, /* __alignof__ always constant. */ E6 = __alignof__ (int[n]), /* { dg-error "ISO C90 forbids variable length array" } */ - E7 = __alignof__ (a), + E7 = __alignof__ (a), /* { dg-error "__alignof__ \\(expression\\)" } */ /* __extension__ ignored for constant expression purposes. */ E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant expression" } */ E9 = __extension__ 0, Index: testsuite/gcc.dg/c1x-align-2.c =================================================================== --- testsuite/gcc.dg/c1x-align-2.c (revision 0) +++ testsuite/gcc.dg/c1x-align-2.c (revision 0) @@ -0,0 +1,92 @@ +/* Test C1X alignment support. Test valid code using stdalign.h. */ +/* { dg-do run } */ +/* { dg-options "-std=c1x -pedantic-errors" } */ + +#include <stdalign.h> +#include <stddef.h> + +extern int strcmp (const char *, const char *); + +extern void exit (int); +extern void abort (void); + +alignas (alignof (max_align_t)) char c; +extern alignas (max_align_t) char c; +extern char c; + +extern alignas (max_align_t) short s; +alignas (max_align_t) short s; + +alignas (int) int i; +extern int i; + +alignas (max_align_t) long l; + +alignas (max_align_t) long long ll; + +alignas (max_align_t) float f; + +alignas (max_align_t) double d; + +alignas (max_align_t) _Complex long double cld; + +alignas (0) alignas (int) alignas (char) char ca[10]; + +alignas ((int) alignof (max_align_t) + 0) int x; + +enum e { E = alignof (max_align_t) }; +alignas (E) int y; + +void +func (void) +{ + alignas (max_align_t) long long auto_ll; +} + +/* Valid, but useless. */ +alignas (0) struct s; /* { dg-warning "useless" } */ + +#ifndef alignas +#error "alignas not defined" +#endif + +#ifndef alignof +#error "alignof not defined" +#endif + +#ifndef __alignas_is_defined +#error "__alignas_is_defined not defined" +#endif + +#if __alignas_is_defined != 1 +#error "__alignas_is_defined not 1" +#endif + +#ifndef __alignof_is_defined +#error "__alignof_is_defined not defined" +#endif + +#if __alignof_is_defined != 1 +#error "__alignof_is_defined not 1" +#endif + +#define str(x) #x +#define xstr(x) str(x) + +const char *s1 = xstr(alignas); +const char *s2 = xstr(alignof); +const char *s3 = xstr(__alignas_is_defined); +const char *s4 = xstr(__alignof_is_defined); + +int +main (void) +{ + if (strcmp (s1, "_Alignas") != 0) + abort (); + if (strcmp (s2, "_Alignof") != 0) + abort (); + if (strcmp (s3, "1") != 0) + abort (); + if (strcmp (s4, "1") != 0) + abort (); +} Index: testsuite/gcc.dg/gnu89-const-expr-1.c =================================================================== --- testsuite/gcc.dg/gnu89-const-expr-1.c (revision 181033) +++ testsuite/gcc.dg/gnu89-const-expr-1.c (working copy) @@ -23,7 +23,7 @@ f (void) E5 = __imag__ 0, /* __alignof__ always constant. */ E6 = __alignof__ (int[n]), /* { dg-error "ISO C90 forbids variable length array" } */ - E7 = __alignof__ (a), + E7 = __alignof__ (a), /* { dg-error "__alignof__ \\(expression\\)" } */ /* __extension__ ignored for constant expression purposes. */ E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant expression" } */ E9 = __extension__ 0, Index: testsuite/gcc.dg/gnu99-const-expr-1.c =================================================================== --- testsuite/gcc.dg/gnu99-const-expr-1.c (revision 181033) +++ testsuite/gcc.dg/gnu99-const-expr-1.c (working copy) @@ -23,7 +23,7 @@ f (void) E5 = __imag__ 0, /* __alignof__ always constant. */ E6 = __alignof__ (int[n]), - E7 = __alignof__ (a), + E7 = __alignof__ (a), /* { dg-error "__alignof__ \\(expression\\)" } */ /* __extension__ ignored for constant expression purposes. */ E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant expression" } */ E9 = __extension__ 0, Index: testsuite/gcc.dg/c1x-align-3.c =================================================================== --- testsuite/gcc.dg/c1x-align-3.c (revision 0) +++ testsuite/gcc.dg/c1x-align-3.c (revision 0) @@ -0,0 +1,42 @@ +/* Test C1X alignment support. Test invalid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=c1x -pedantic-errors" } */ + +int a = _Alignof (void (void)); /* { dg-error "function" } */ +struct s; +int b = _Alignof (struct s); /* { dg-error "incomplete" } */ +int c = _Alignof (void); /* { dg-error "void" } */ +int d = _Alignof (a); /* { dg-error "expression" } */ + +_Alignas (void (void)) char e; /* { dg-error "function" } */ +_Alignas (struct s) char f; /* { dg-error "incomplete" } */ +_Alignas (void) char g; /* { dg-error "void" } */ + +_Alignas (-__INT_MAX__-1) char h; /* { dg-error "too large|power of 2" } */ +_Alignas (-__INT_MAX__) char h2; /* { dg-error "too large|power of 2" } */ +_Alignas ((-__INT_MAX__-1)/2) char h3; /* { dg-error "too large|power of 2" } */ +_Alignas ((-__INT_MAX__-1)/4) char h4; /* { dg-error "too large|power of 2" } */ +_Alignas ((-__INT_MAX__-1)/8) char h5; /* { dg-error "too large|power of 2" } */ +_Alignas (-__LONG_LONG_MAX__-1) char i; /* { dg-error "too large|power of 2" } */ +_Alignas (-(__LONG_LONG_MAX__-1)/2) char i2; /* { dg-error "too large|power of 2" } */ +_Alignas (-(__LONG_LONG_MAX__-1)/4) char i3; /* { dg-error "too large|power of 2" } */ +_Alignas (-(__LONG_LONG_MAX__-1)/8) char i4; /* { dg-error "too large|power of 2" } */ +_Alignas (-(__LONG_LONG_MAX__-1)/16) char i5; /* { dg-error "too large|power of 2" } */ +_Alignas (-1) char j; /* { dg-error "power of 2" } */ +_Alignas (3) char k; /* { dg-error "power of 2" } */ + +_Alignas ((void *) 1) char k; /* { dg-error "integer constant" } */ +int x; +_Alignas (x) char l; /* { dg-error "integer constant" } */ + +_Alignas (0) struct s; /* { dg-error "does not redeclare tag" } */ + +_Alignas (0) typedef int T; /* { dg-error "alignment specified for typedef" } */ +void func (_Alignas (0) int); /* { dg-error "alignment specified for unnamed parameter" } */ +void f2 (_Alignas (0) int parm2) {} /* { dg-error "alignment specified for parameter" } */ +void +f3 (void) +{ + register _Alignas (0) int reg; /* { dg-error "register" } */ +} +_Alignas (0) void f4 (void); /* { dg-error "alignment specified for function" } */ Index: testsuite/g++.dg/cpp0x/alignof3.C =================================================================== --- testsuite/g++.dg/cpp0x/alignof3.C (revision 0) +++ testsuite/g++.dg/cpp0x/alignof3.C (revision 0) @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-options "-std=c++0x -pedantic" } +int main(void) +{ + alignof(void (void)); // { dg-warning "function type" } +} Index: c-tree.h =================================================================== --- c-tree.h (revision 181033) +++ c-tree.h (working copy) @@ -238,6 +238,10 @@ struct c_declspecs { NULL; attributes (possibly from multiple lists) will be passed separately. */ tree attrs; + /* The base-2 log of the greatest alignment required by an _Alignas + specifier, in bytes, or -1 if no such specifiers with nonzero + alignment. */ + int align_log; /* The storage class specifier, or csc_none if none. */ enum c_storage_class storage_class; /* Any type specifier keyword used such as "int", not reflecting @@ -294,6 +298,9 @@ struct c_declspecs { BOOL_BITFIELD restrict_p : 1; /* Whether "_Sat" was specified. */ BOOL_BITFIELD saturating_p : 1; + /* Whether any alignment specifier (even with zero alignment) was + specified. */ + BOOL_BITFIELD alignas_p : 1; /* The address space that the declaration belongs to. */ addr_space_t address_space; }; @@ -510,6 +517,7 @@ extern struct c_declspecs *declspecs_add extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *, addr_space_t); +extern struct c_declspecs *declspecs_add_alignas (struct c_declspecs *, tree); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); /* in c-objc-common.c */ Index: c-decl.c =================================================================== --- c-decl.c (revision 181033) +++ c-decl.c (working copy) @@ -3707,6 +3707,17 @@ shadow_tag_warned (const struct c_declsp warned = 1; pending_xref_error (); } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->alignas_p) + { + if (warned != 1) + pedwarn (input_location, 0, + "empty declaration with %<_Alignas%> " + "does not redeclare tag"); + warned = 1; + pending_xref_error (); + } else { pending_invalid_xref = 0; @@ -3782,6 +3793,12 @@ shadow_tag_warned (const struct c_declsp warned = 2; } + if (!warned && !in_system_header && declspecs->alignas_p) + { + warning (0, "useless %<_Alignas%> in empty declaration"); + warned = 2; + } + if (warned != 1) { if (!found_tag) @@ -4894,6 +4911,7 @@ grokdeclarator (const struct c_declarato tree expr_dummy; bool expr_const_operands_dummy; enum c_declarator_kind first_non_attr_kind; + unsigned int alignas_align = 0; if (TREE_CODE (type) == ERROR_MARK) return error_mark_node; @@ -5737,6 +5755,46 @@ grokdeclarator (const struct c_declarato if (bitfield) check_bitfield_type_and_width (&type, width, name); + /* Reject invalid uses of _Alignas. */ + if (declspecs->alignas_p) + { + if (storage_class == csc_typedef) + error_at (loc, "alignment specified for typedef %qE", name); + else if (storage_class == csc_register) + error_at (loc, "alignment specified for %<register%> object %qE", + name); + else if (decl_context == PARM) + { + if (name) + error_at (loc, "alignment specified for parameter %qE", name); + else + error_at (loc, "alignment specified for unnamed parameter"); + } + else if (bitfield) + { + if (name) + error_at (loc, "alignment specified for bit-field %qE", name); + else + error_at (loc, "alignment specified for unnamed bit-field"); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + error_at (loc, "alignment specified for function %qE", name); + else if (declspecs->align_log != -1) + { + alignas_align = 1U << declspecs->align_log; + if (alignas_align < TYPE_ALIGN_UNIT (type)) + { + if (name) + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of %qE", name); + else + error_at (loc, "%<_Alignas%> specifiers cannot reduce " + "alignment of unnamed field"); + alignas_align = 0; + } + } + } + /* Did array size calculations overflow? */ if (TREE_CODE (type) == ARRAY_TYPE @@ -6117,6 +6175,13 @@ grokdeclarator (const struct c_declarato /* Record constancy and volatility. */ c_apply_type_quals_to_decl (type_quals, decl); + /* Apply _Alignas specifiers. */ + if (alignas_align) + { + DECL_ALIGN (decl) = alignas_align * BITS_PER_UNIT; + DECL_USER_ALIGN (decl) = 1; + } + /* If a type has volatile components, it should be stored in memory. Otherwise, the fact that those components are volatile will be ignored, and would even crash the compiler. @@ -8709,6 +8774,7 @@ build_null_declspecs (void) ret->expr = 0; ret->decl_attr = 0; ret->attrs = 0; + ret->align_log = -1; ret->typespec_word = cts_none; ret->storage_class = csc_none; ret->expr_const_operands = true; @@ -8732,6 +8798,7 @@ build_null_declspecs (void) ret->volatile_p = false; ret->restrict_p = false; ret->saturating_p = false; + ret->alignas_p = false; ret->address_space = ADDR_SPACE_GENERIC; return ret; } @@ -9522,6 +9589,22 @@ declspecs_add_attrs (struct c_declspecs return specs; } +/* Add an _Alignas specifier (expression ALIGN, or type whose + alignment is ALIGN) to the declaration specifiers SPECS, returning + SPECS. */ +struct c_declspecs * +declspecs_add_alignas (struct c_declspecs *specs, tree align) +{ + int align_log; + specs->alignas_p = true; + if (align == error_mark_node) + return specs; + align_log = check_user_alignment (align, true); + if (align_log > specs->align_log) + specs->align_log = align_log; + return specs; +} + /* Combine "long", "short", "signed", "unsigned" and "_Complex" type specifiers with any other type specifier to determine the resulting type. This is where ISO C checks on complex types are made, since Index: Makefile.in =================================================================== --- Makefile.in (revision 181033) +++ Makefile.in (working copy) @@ -376,6 +376,7 @@ USER_H = $(srcdir)/ginclude/float.h \ $(srcdir)/ginclude/varargs.h \ $(srcdir)/ginclude/stdfix.h \ $(srcdir)/ginclude/stdnoreturn.h \ + $(srcdir)/ginclude/stdalign.h \ $(EXTRA_HEADERS) USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@ Index: c-parser.c =================================================================== --- c-parser.c (revision 181033) +++ c-parser.c (working copy) @@ -650,6 +650,7 @@ c_token_starts_declspecs (c_token *token case RID_FRACT: case RID_ACCUM: case RID_SAT: + case RID_ALIGNAS: return true; default: return false; @@ -1120,6 +1121,7 @@ static struct c_typespec c_parser_enum_s static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); static tree c_parser_struct_declaration (c_parser *); static struct c_typespec c_parser_typeof_specifier (c_parser *); +static tree c_parser_alignas_specifier (c_parser *); static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn, bool *); static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, @@ -1890,9 +1892,11 @@ c_parser_static_assert_declaration_no_se type-specifier declaration-specifiers[opt] type-qualifier declaration-specifiers[opt] function-specifier declaration-specifiers[opt] + alignment-specifier declaration-specifiers[opt] Function specifiers (inline) are from C99, and are currently - handled as storage class specifiers, as is __thread. + handled as storage class specifiers, as is __thread. Alignment + specifiers are from C1X. C90 6.5.1, C99 6.7.1: storage-class-specifier: @@ -1991,6 +1995,7 @@ c_parser_declspecs (c_parser *parser, st { struct c_typespec t; tree attrs; + tree align; location_t loc = c_parser_peek_token (parser)->location; /* If we cannot accept a type, exit if the next token must start @@ -2169,6 +2174,10 @@ c_parser_declspecs (c_parser *parser, st attrs = c_parser_attributes (parser); declspecs_add_attrs (specs, attrs); break; + case RID_ALIGNAS: + align = c_parser_alignas_specifier (parser); + declspecs_add_alignas (specs, align); + break; default: goto out; } @@ -2751,6 +2760,45 @@ c_parser_typeof_specifier (c_parser *par return ret; } +/* Parse an alignment-specifier. + + C1X 6.7.5: + + alignment-specifier: + _Alignas ( type-name ) + _Alignas ( constant-expression ) +*/ + +static tree +c_parser_alignas_specifier (c_parser * parser) +{ + tree ret = error_mark_node; + location_t loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); + c_parser_consume_token (parser); + if (!flag_isoc1x) + { + if (flag_isoc99) + pedwarn (loc, OPT_pedantic, + "ISO C99 does not support %<_Alignas%>"); + else + pedwarn (loc, OPT_pedantic, + "ISO C90 does not support %<_Alignas%>"); + } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return ret; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + ret = c_alignof (loc, groktypename (type, NULL, NULL)); + } + else + ret = c_parser_expr_no_commas (parser, NULL).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return ret; +} + /* Parse a declarator, possibly an abstract declarator (C90 6.5.4, 6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may be redeclared; otherwise it may not. KIND indicates which kind of @@ -5759,6 +5807,8 @@ c_parser_cast_expression (c_parser *pars __alignof__ ( type-name ) && identifier + (C1X permits _Alignof with type names only.) + unary-operator: one of __extension__ __real__ __imag__ @@ -5942,7 +5992,21 @@ c_parser_alignof_expression (c_parser *p { struct c_expr expr; 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)); + /* A diagnostic is not required for the use of this identifier in + the implementation namespace; only diagnose it for the C1X + spelling because of existing code using the other spellings. */ + if (!flag_isoc1x + && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0) + { + if (flag_isoc99) + pedwarn (loc, OPT_pedantic, "ISO C99 does not support %qE", + alignof_spelling); + else + pedwarn (loc, OPT_pedantic, "ISO C90 does not support %qE", + alignof_spelling); + } c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_alignof++; @@ -5991,6 +6055,8 @@ c_parser_alignof_expression (c_parser *p mark_exp_read (expr.value); c_inhibit_evaluation_warnings--; in_alignof--; + pedwarn (loc, OPT_pedantic, "ISO C does not allow %<%E (expression)%>", + alignof_spelling); ret.value = c_alignof_expr (loc, expr.value); ret.original_code = ERROR_MARK; ret.original_type = NULL; -- Joseph S. Myers jos...@codesourcery.com