aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2017-12-07 18:47:20 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2017-12-07 18:47:20 +0000
commit4b2b493f86452d7941bf591b91bd348166f8ad1d (patch)
tree1c5ec854c5192aac243178dd75fcfda1fbb8e618 /gcc/c/c-parser.c
parentc348cab062adf3946fdadff884b7f43774d72d8f (diff)
downloadgcc-4b2b493f86452d7941bf591b91bd348166f8ad1d.zip
gcc-4b2b493f86452d7941bf591b91bd348166f8ad1d.tar.gz
gcc-4b2b493f86452d7941bf591b91bd348166f8ad1d.tar.bz2
Allow _Alignas in compound literals (C11 DR#444).
C11 DR#444 dealt with how C11 intended to allow alignment specifiers on struct and union members, but failed to include that in the syntax. The final resolution of that DR also allows alignment specifiers in type names in compound literals (in order to apply an increased alignment to the unnamed object created by the compound literal), but not other cases of type names. This patch implements allowing alignment specifiers in compound literals and adds tests for the resolution of the DR (including that they are allowed on struct and union members, which GCC already implemented). Because the parser has to parse the parenthesized type name of a compound literal before it can tell that it's a compound literal (rather than, depending on the context, a cast expression or sizeof (type-name) or _Alignof (type-name)), this means _Alignas specifiers are allowed syntactically in those contexts and then an error is given once it's known to be an invalid use (whereas _Alignas specifiers are disallowed syntactically in other contexts where type names can occur and a compound literal is not possible). Bootstrapped with no regressions on x86_64-pc-linux-gnu. gcc/c: * 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. gcc/testsuite: * 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. From-SVN: r255482
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r--gcc/c/c-parser.c45
1 files changed, 37 insertions, 8 deletions
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index e9267fe..d398548 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 %<sizeof%>");
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;