diff options
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r-- | gcc/c/c-parser.cc | 139 |
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))) |