diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 6e11827f39c..14d7f63bf4e 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,25 @@ +2017-12-07 Joseph Myers + + * c-decl.c (build_compound_literal): Add parameter alignas_align + and set alignment of decl if nonzero. + * c-parser.c (c_keyword_starts_typename): Allow RID_ALIGNAS. + (c_parser_declspecs): Allow RID_ALIGNAS to follow a type, like a + qualifier. + (c_parser_struct_declaration): Update syntax comment. + (c_parser_type_name): Add alignas_ok argument and pass it to + c_parser_declspecs. + (c_parser_cast_expression): Pass true to c_parser_type_name and + give error if a cast used an _Alignas specifier. + (c_parser_sizeof_expression): Pass true to c_parser_type_name and + give error if sizeof (type-name) used an _Alignas specifier. + (c_parser_alignof_expression): Pass true to c_parser_type_name and + give error if _Alignof (type-name) used an _Alignas specifier. + (c_parser_postfix_expression_after_paren_type): Check specified + alignment for a compound literal and pass it to + build_compound_literal. + * c-parser.h (c_parser_type_name): Update prototype. + * c-tree.h (build_compound_literal): Update prototype. + 2017-12-07 Martin Sebor PR c/81544 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index aaa96787472..4a36c54d21e 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -5272,10 +5272,13 @@ mark_forward_parm_decls (void) literal, which may be an incomplete array type completed by the initializer; INIT is a CONSTRUCTOR at LOC that initializes the compound literal. NON_CONST is true if the initializers contain something - that cannot occur in a constant expression. */ + that cannot occur in a constant expression. If ALIGNAS_ALIGN is nonzero, + it is the (valid) alignment for this compound literal, as specified + with _Alignas. */ tree -build_compound_literal (location_t loc, tree type, tree init, bool non_const) +build_compound_literal (location_t loc, tree type, tree init, bool non_const, + unsigned int alignas_align) { /* We do not use start_decl here because we have a type, not a declarator; and do not use finish_decl because the decl should be stored inside @@ -5299,6 +5302,11 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const) DECL_IGNORED_P (decl) = 1; TREE_TYPE (decl) = type; c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl); + if (alignas_align) + { + SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); + DECL_USER_ALIGN (decl) = 1; + } store_init_value (loc, decl, init, NULL_TREE); if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index e9267fe9cc1..d3985480504 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -504,6 +504,7 @@ c_keyword_starts_typename (enum rid keyword) case RID_ACCUM: case RID_SAT: case RID_AUTO_TYPE: + case RID_ALIGNAS: return true; default: if (keyword >= RID_FIRST_INT_N @@ -2594,7 +2595,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, has simply forgotten a semicolon, so we exit. */ if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) && c_parser_next_tokens_start_typename (parser, la) - && !c_parser_next_token_is_qualifier (parser)) + && !c_parser_next_token_is_qualifier (parser) + && !c_parser_next_token_is_keyword (parser, RID_ALIGNAS)) break; if (c_parser_next_token_is (parser, CPP_NAME)) @@ -3225,6 +3227,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) specifier-qualifier-list: type-specifier specifier-qualifier-list[opt] type-qualifier specifier-qualifier-list[opt] + alignment-specifier specifier-qualifier-list[opt] attributes specifier-qualifier-list[opt] struct-declarator-list: @@ -4410,20 +4413,22 @@ c_parser_attributes (c_parser *parser) return attrs; } -/* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). +/* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK + says whether alignment specifiers are OK (only in cases that might + be the type name of a compound literal). type-name: specifier-qualifier-list abstract-declarator[opt] */ struct c_type_name * -c_parser_type_name (c_parser *parser) +c_parser_type_name (c_parser *parser, bool alignas_ok) { struct c_declspecs *specs = build_null_declspecs (); struct c_declarator *declarator; struct c_type_name *ret; bool dummy = false; - c_parser_declspecs (parser, specs, false, true, true, false, false, + c_parser_declspecs (parser, specs, false, true, true, alignas_ok, false, cla_prefer_type); if (!specs->declspecs_seen_p) { @@ -7019,7 +7024,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) struct c_expr expr; matching_parens parens; parens.consume_open (parser); - type_name = c_parser_type_name (parser); + type_name = c_parser_type_name (parser, true); parens.skip_until_found_close (parser); if (type_name == NULL) { @@ -7035,6 +7040,9 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) return c_parser_postfix_expression_after_paren_type (parser, type_name, cast_loc); + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in cast"); { location_t expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_cast_expression (parser, NULL); @@ -7238,7 +7246,7 @@ c_parser_sizeof_expression (c_parser *parser) matching_parens parens; parens.consume_open (parser); expr_loc = c_parser_peek_token (parser)->location; - type_name = c_parser_type_name (parser); + type_name = c_parser_type_name (parser, true); parens.skip_until_found_close (parser); finish = parser->tokens_buf[0].location; if (type_name == NULL) @@ -7260,6 +7268,9 @@ c_parser_sizeof_expression (c_parser *parser) goto sizeof_expr; } /* sizeof ( type-name ). */ + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in %"); c_inhibit_evaluation_warnings--; in_sizeof--; result = c_expr_sizeof_type (expr_loc, type_name); @@ -7321,7 +7332,7 @@ c_parser_alignof_expression (c_parser *parser) matching_parens parens; parens.consume_open (parser); loc = c_parser_peek_token (parser)->location; - type_name = c_parser_type_name (parser); + type_name = c_parser_type_name (parser, true); end_loc = c_parser_peek_token (parser)->location; parens.skip_until_found_close (parser); if (type_name == NULL) @@ -7342,6 +7353,10 @@ c_parser_alignof_expression (c_parser *parser) goto alignof_expr; } /* alignof ( type-name ). */ + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in %qE", + alignof_spelling); c_inhibit_evaluation_warnings--; in_alignof--; ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, @@ -8969,7 +8984,21 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, ? CONSTRUCTOR_NON_CONST (init.value) : init.original_code == C_MAYBE_CONST_EXPR); non_const |= !type_expr_const; - expr.value = build_compound_literal (start_loc, type, init.value, non_const); + unsigned int alignas_align = 0; + if (type != error_mark_node + && type_name->specs->align_log != -1) + { + alignas_align = 1U << type_name->specs->align_log; + if (alignas_align < min_align_of_type (type)) + { + error_at (type_name->specs->locations[cdw_alignas], + "%<_Alignas%> specifiers cannot reduce " + "alignment of compound literal"); + alignas_align = 0; + } + } + expr.value = build_compound_literal (start_loc, type, init.value, non_const, + alignas_align); set_c_expr_source_range (&expr, init.src_range); expr.original_code = ERROR_MARK; expr.original_type = NULL; diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h index 21e40541ce6..ff8cdda6917 100644 --- a/gcc/c/c-parser.h +++ b/gcc/c/c-parser.h @@ -187,6 +187,6 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id); extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, bool, bool, bool, enum c_lookahead_kind); -extern struct c_type_name *c_parser_type_name (c_parser *); +extern struct c_type_name *c_parser_type_name (c_parser *, bool = false); #endif diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index cbc5e0e8bcc..c542d682f3e 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -672,7 +672,8 @@ extern void set_init_index (location_t, tree, tree, struct obstack *); extern void set_init_label (location_t, tree, location_t, struct obstack *); extern void process_init_element (location_t, struct c_expr, bool, struct obstack *); -extern tree build_compound_literal (location_t, tree, tree, bool); +extern tree build_compound_literal (location_t, tree, tree, bool, + unsigned int); extern void check_compound_literal_type (location_t, struct c_type_name *); extern tree c_start_case (location_t, location_t, tree, bool); extern void c_finish_case (tree, tree); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3a22f217a17..dab24f42438 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-12-07 Joseph Myers + + * gcc.dg/c11-align-7.c, gcc.dg/c11-align-8.c, + gcc.dg/c11-align-9.c, gcc.dg/gnu11-align-1.c: New tests. + * gcc.dg/c11-align-5.c (test): Update expected error for sizeof + case. + 2017-12-07 Richard Sandiford * gcc.target/aarch64/asm-2.c: New test. diff --git a/gcc/testsuite/gcc.dg/c11-align-5.c b/gcc/testsuite/gcc.dg/c11-align-5.c index f3a14779ff8..08ec65a8b9f 100644 --- a/gcc/testsuite/gcc.dg/c11-align-5.c +++ b/gcc/testsuite/gcc.dg/c11-align-5.c @@ -19,7 +19,7 @@ test (void) struct s { int n; }; __builtin_offsetof (struct s _Alignas (int), n); /* { dg-error "expected" } */ __typeof (long double _Alignas (0)) e; /* { dg-error "expected" } */ - sizeof (int _Alignas (int)); /* { dg-error "expected" } */ + sizeof (int _Alignas (int)); /* { dg-error "specified for type name" } */ _Alignas (int _Alignas (float)) int t; /* { dg-error "expected" } */ __builtin_types_compatible_p (signed _Alignas (0), unsigned); /* { dg-error "expected" } */ int a[_Alignas (int) 10]; /* { dg-error "expected expression before" } */ diff --git a/gcc/testsuite/gcc.dg/c11-align-7.c b/gcc/testsuite/gcc.dg/c11-align-7.c new file mode 100644 index 00000000000..631986ac30f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-align-7.c @@ -0,0 +1,20 @@ +/* Test C11 alignment support. Test code valid after the resolution + of DR#444: alignment specifiers for struct and union members and + compound literals. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +#include + +struct s +{ + _Alignas (_Alignof (max_align_t)) char c; +}; + +union u +{ + _Alignas (_Alignof (max_align_t)) char c; +}; + +char *p = &(_Alignas (_Alignof (max_align_t)) char) { 1 }; +size_t size = sizeof (_Alignas (_Alignof (max_align_t)) char) { 1 }; diff --git a/gcc/testsuite/gcc.dg/c11-align-8.c b/gcc/testsuite/gcc.dg/c11-align-8.c new file mode 100644 index 00000000000..a201674cf95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-align-8.c @@ -0,0 +1,18 @@ +/* Test C11 alignment support. Test invalid use of alignment + specifiers in type names in cases not permitted by the resolution + of DR#444. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +#include + +void +f (void) +{ + _Generic (1, int: 1, _Alignas (8) long: 2); /* { dg-error "expected" } */ + sizeof (_Alignas (8) long); /* { dg-error "specified for type name" } */ + _Alignof (_Alignas (8) long); /* { dg-error "specified for type name" } */ + (_Alignas (8) long) 0; /* { dg-error "specified for type name" } */ + _Atomic (_Alignas (8) long) x; /* { dg-error "expected" } */ + _Alignas (_Alignas (8) long) long y; /* { dg-error "expected" } */ +} diff --git a/gcc/testsuite/gcc.dg/c11-align-9.c b/gcc/testsuite/gcc.dg/c11-align-9.c new file mode 100644 index 00000000000..3c9cf55756e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-align-9.c @@ -0,0 +1,9 @@ +/* Test C11 alignment support. Test reducing alignment (assumes there + are at least some alignment constraints), case of compound literals. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ +/* { dg-skip-if "no alignment constraints" { "avr-*-*" } } */ + +#include + +max_align_t *p = &(_Alignas (_Alignof (char)) max_align_t) { 1 }; /* { dg-error "reduce alignment" } */ diff --git a/gcc/testsuite/gcc.dg/gnu11-align-1.c b/gcc/testsuite/gcc.dg/gnu11-align-1.c new file mode 100644 index 00000000000..50522d7bed5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu11-align-1.c @@ -0,0 +1,8 @@ +/* Test C11 alignment support. Test code valid after the resolution + of DR#444: alignment specifiers for compound literals in _Alignof. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu11" } */ + +#include + +size_t align = _Alignof (_Alignas (_Alignof (max_align_t)) char) { 1 };