aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc139
1 files changed, 116 insertions, 23 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 602e023..5bdcd93 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -3011,6 +3011,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
}
t.expr = NULL_TREE;
t.expr_const_operands = true;
+ t.has_enum_type_specifier = false;
declspecs_add_type (name_token->location, specs, t);
continue;
}
@@ -3027,6 +3028,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
t.expr = NULL_TREE;
t.expr_const_operands = true;
+ t.has_enum_type_specifier = false;
declspecs_add_type (loc, specs, t);
continue;
}
@@ -3087,6 +3089,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
t.spec = c_parser_peek_token (parser)->value;
t.expr = NULL_TREE;
t.expr_const_operands = true;
+ t.has_enum_type_specifier = false;
declspecs_add_type (loc, specs, t);
c_parser_consume_token (parser);
break;
@@ -3151,6 +3154,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
t.spec = error_mark_node;
t.expr = NULL_TREE;
t.expr_const_operands = true;
+ t.has_enum_type_specifier = false;
if (type != NULL)
t.spec = groktypename (type, &t.expr,
&t.expr_const_operands);
@@ -3218,17 +3222,20 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2).
enum-specifier:
- enum gnu-attributes[opt] identifier[opt] { enumerator-list }
- gnu-attributes[opt]
- enum gnu-attributes[opt] identifier[opt] { enumerator-list , }
- gnu-attributes[opt]
+ enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt]
+ { enumerator-list } gnu-attributes[opt]
+ enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt]
+ { enumerator-list , } gnu-attributes[opt] enum-type-specifier[opt]
enum gnu-attributes[opt] identifier
- The form with trailing comma is new in C99. The forms with
- gnu-attributes are GNU extensions. In GNU C, we accept any expression
- without commas in the syntax (assignment expressions, not just
- conditional expressions); assignment expressions will be diagnosed
- as non-constant.
+ The form with trailing comma is new in C99; enum-type-specifiers
+ are new in C2x. The forms with gnu-attributes are GNU extensions.
+ In GNU C, we accept any expression without commas in the syntax
+ (assignment expressions, not just conditional expressions);
+ assignment expressions will be diagnosed as non-constant.
+
+ enum-type-specifier:
+ : specifier-qualifier-list
enumerator-list:
enumerator
@@ -3256,6 +3263,7 @@ c_parser_enum_specifier (c_parser *parser)
tree std_attrs = NULL_TREE;
tree attrs;
tree ident = NULL_TREE;
+ tree fixed_underlying_type = NULL_TREE;
location_t enum_loc;
location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
@@ -3274,6 +3282,83 @@ c_parser_enum_specifier (c_parser *parser)
enum_loc = ident_loc;
c_parser_consume_token (parser);
}
+ if (c_parser_next_token_is (parser, CPP_COLON)
+ /* Distinguish an enum-type-specifier from a bit-field
+ declaration of the form "enum e : constant-expression;". */
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ pedwarn_c11 (enum_loc, OPT_Wpedantic,
+ "ISO C does not support specifying %<enum%> underlying "
+ "types before C2X");
+ if (ident)
+ {
+ /* The tag is in scope during the enum-type-specifier (which
+ may refer to the tag inside typeof). */
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident,
+ have_std_attrs, std_attrs, true);
+ if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec))
+ error_at (enum_loc, "%<enum%> declared both with and without "
+ "fixed underlying type");
+ }
+ else
+ {
+ /* There must be an enum definition, so this initialization
+ (to avoid possible warnings about uninitialized data)
+ will be replaced later (either with the results of that
+ definition, or with the results of error handling for the
+ case of no tag and no definition). */
+ ret.spec = NULL_TREE;
+ ret.kind = ctsk_tagdef;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = true;
+ }
+ c_parser_consume_token (parser);
+ struct c_declspecs *specs = build_null_declspecs ();
+ c_parser_declspecs (parser, specs, false, true, false, false, false,
+ false, true, cla_prefer_id);
+ finish_declspecs (specs);
+ if (specs->default_int_p)
+ error_at (enum_loc, "no %<enum%> underlying type specified");
+ else if (TREE_CODE (specs->type) != INTEGER_TYPE
+ && TREE_CODE (specs->type) != BOOLEAN_TYPE)
+ {
+ error_at (enum_loc, "invalid %<enum%> underlying type");
+ specs->type = integer_type_node;
+ }
+ else if (specs->restrict_p)
+ error_at (enum_loc, "invalid use of %<restrict%>");
+ fixed_underlying_type = TYPE_MAIN_VARIANT (specs->type);
+ if (ident)
+ {
+ /* The type specified must be consistent with any previously
+ specified underlying type. If this is a newly declared
+ type, it is now a complete type. */
+ if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)
+ && ENUM_UNDERLYING_TYPE (ret.spec) == NULL_TREE)
+ {
+ TYPE_MIN_VALUE (ret.spec) =
+ TYPE_MIN_VALUE (fixed_underlying_type);
+ TYPE_MAX_VALUE (ret.spec) =
+ TYPE_MAX_VALUE (fixed_underlying_type);
+ TYPE_UNSIGNED (ret.spec) = TYPE_UNSIGNED (fixed_underlying_type);
+ SET_TYPE_ALIGN (ret.spec, TYPE_ALIGN (fixed_underlying_type));
+ TYPE_SIZE (ret.spec) = NULL_TREE;
+ TYPE_PRECISION (ret.spec) =
+ TYPE_PRECISION (fixed_underlying_type);
+ ENUM_UNDERLYING_TYPE (ret.spec) = fixed_underlying_type;
+ layout_type (ret.spec);
+ }
+ else if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)
+ && !comptypes (fixed_underlying_type,
+ ENUM_UNDERLYING_TYPE (ret.spec)))
+ {
+ error_at (enum_loc, "%<enum%> underlying type incompatible with "
+ "previous declaration");
+ fixed_underlying_type = ENUM_UNDERLYING_TYPE (ret.spec);
+ }
+ }
+ }
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
/* Parse an enum definition. */
@@ -3284,7 +3369,7 @@ c_parser_enum_specifier (c_parser *parser)
forward order at the end. */
tree values;
timevar_push (TV_PARSE_ENUM);
- type = start_enum (enum_loc, &the_enum, ident);
+ type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type);
values = NULL_TREE;
c_parser_consume_token (parser);
while (true)
@@ -3368,6 +3453,7 @@ c_parser_enum_specifier (c_parser *parser)
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = fixed_underlying_type != NULL_TREE;
timevar_pop (TV_PARSE_ENUM);
return ret;
}
@@ -3378,6 +3464,7 @@ c_parser_enum_specifier (c_parser *parser)
ret.kind = ctsk_tagref;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = false;
return ret;
}
/* Attributes may only appear when the members are defined or in
@@ -3386,15 +3473,18 @@ c_parser_enum_specifier (c_parser *parser)
standard C). */
if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON))
c_parser_error (parser, "expected %<;%>");
- ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs,
- std_attrs);
- /* In ISO C, enumerated types can be referred to only if already
- defined. */
- if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+ if (fixed_underlying_type == NULL_TREE)
{
- gcc_assert (ident);
- pedwarn (enum_loc, OPT_Wpedantic,
- "ISO C forbids forward references to %<enum%> types");
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs,
+ std_attrs, false);
+ /* In ISO C, enumerated types without a fixed underlying type
+ can be referred to only if already defined. */
+ if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+ {
+ gcc_assert (ident);
+ pedwarn (enum_loc, OPT_Wpedantic,
+ "ISO C forbids forward references to %<enum%> types");
+ }
}
return ret;
}
@@ -3590,6 +3680,7 @@ c_parser_struct_or_union_specifier (c_parser *parser)
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = false;
timevar_pop (TV_PARSE_STRUCT);
return ret;
}
@@ -3600,6 +3691,7 @@ c_parser_struct_or_union_specifier (c_parser *parser)
ret.kind = ctsk_tagref;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = false;
return ret;
}
/* Attributes may only appear when the members are defined or in
@@ -3608,7 +3700,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
c_parser_error (parser, "expected %<;%>");
/* ??? Existing practice is that GNU attributes are ignored after
the struct or union keyword when not defining the members. */
- ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs);
+ ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs,
+ false);
return ret;
}
@@ -3817,6 +3910,7 @@ c_parser_typeof_specifier (c_parser *parser)
ret.spec = error_mark_node;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ ret.has_enum_type_specifier = false;
if (c_parser_next_token_is_keyword (parser, RID_TYPEOF))
{
is_unqual = false;
@@ -19153,15 +19247,14 @@ restart:
&& TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
&& TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
- (TREE_OPERAND (lhs, 1), 0), 0)))
- == BOOLEAN_TYPE)
+ && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0))))
/* Undo effects of boolean_increment for post {in,de}crement. */
lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
/* FALLTHRU */
case MODIFY_EXPR:
if (TREE_CODE (lhs) == MODIFY_EXPR
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0))))
{
/* Undo effects of boolean_increment. */
if (integer_onep (TREE_OPERAND (lhs, 1)))