diff --git a/regression/ansi-c/enum9/main.c b/regression/ansi-c/enum9/main.c new file mode 100644 index 00000000000..437213acd72 --- /dev/null +++ b/regression/ansi-c/enum9/main.c @@ -0,0 +1,20 @@ +typedef enum : unsigned +{ + X +} my_enum1; + +enum my_enum2 : unsigned +{ + Y +}; + +struct S +{ + enum my_enum2 : unsigned a; + enum my_enum2 : unsigned b : 2; +}; + +int main() +{ + enum my_enum2 : unsigned enum_var1; +} diff --git a/regression/ansi-c/enum9/test.desc b/regression/ansi-c/enum9/test.desc new file mode 100644 index 00000000000..2da90e78820 --- /dev/null +++ b/regression/ansi-c/enum9/test.desc @@ -0,0 +1,14 @@ +CORE +main.c +--verbosity 2 +^EXIT=0$ +^SIGNAL=0$ +(main.c:1:\d+)|(main.c\(1\)): warning: ignoring specification of underlying type for enum +(main.c:6:\d+)|(main.c\(6\)): warning: ignoring specification of underlying type for enum +(main.c:13:\d+)|(main.c\(13\)): warning: ignoring specification of underlying type for enum +(main.c:14:\d+)|(main.c\(14\)): warning: ignoring specification of underlying type for enum +(main.c:19:\d+)|(main.c\(19\)): warning: ignoring specification of underlying type for enum +-- +-- +Checks that files containing enums with an underlying type specification can be +parsed, and that a warning is output saying that the specification is ignored diff --git a/src/ansi-c/c_typecheck_type.cpp b/src/ansi-c/c_typecheck_type.cpp index ea57e4edaa3..50dd7845c89 100644 --- a/src/ansi-c/c_typecheck_type.cpp +++ b/src/ansi-c/c_typecheck_type.cpp @@ -1160,6 +1160,12 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type) throw 0; } + if(as_expr.find(ID_enum_underlying_type).is_not_nil()) + { + warning().source_location = source_location; + warning() << "ignoring specification of underlying type for enum" << eom; + } + // enums start at zero; // we also track min and max to find a nice base type mp_integer value=0, min_value=0, max_value=0; @@ -1352,6 +1358,12 @@ void c_typecheck_baset::typecheck_c_enum_tag_type(c_enum_tag_typet &type) throw 0; } + if(type.find(ID_enum_underlying_type).is_not_nil()) + { + warning().source_location = type.source_location(); + warning() << "ignoring specification of underlying type for enum" << eom; + } + source_locationt source_location=type.source_location(); irept &tag=type.add(ID_tag); diff --git a/src/ansi-c/parser.y b/src/ansi-c/parser.y index 403194d3010..53bfb7e1d20 100644 --- a/src/ansi-c/parser.y +++ b/src/ansi-c/parser.y @@ -267,10 +267,14 @@ extern char *yyansi_ctext; %start grammar -%expect 1 /* the famous "dangling `else'" ambiguity */ +%expect 2 /* the famous "dangling `else'" ambiguity */ /* results in one shift/reduce conflict */ /* that we don't want to be reported */ + /* a second shift/reduce conflict arises due to enum underlying */ + /* type specifications and bitfield specifications, which are both */ + /* introduced by a ':' and follow a type */ + %{ /************************************************************************/ /*** rules **************************************************************/ @@ -1790,23 +1794,15 @@ bit_field_size: enum_name: enum_key gcc_type_attribute_opt - { - // an anon enum - } - '{' enumerator_list_opt '}' - gcc_type_attribute_opt + enum_underlying_type_opt { - parser_stack($1).operands().swap(parser_stack($5).operands()); - $$=merge($1, merge($2, $7)); // throw in the gcc attributes - } - | enum_key - gcc_type_attribute_opt - identifier_or_typedef_name + // an anon enum + if(parser_stack($3).is_not_nil()) { - // an enum with tag - parser_stack($1).set(ID_tag, parser_stack($3)); + parser_stack($1).set(ID_enum_underlying_type, parser_stack($3)); } - '{' enumerator_list_opt '}' + } + '{' enumerator_list_opt '}' gcc_type_attribute_opt { parser_stack($1).operands().swap(parser_stack($6).operands()); @@ -1815,14 +1811,54 @@ enum_name: | enum_key gcc_type_attribute_opt identifier_or_typedef_name - gcc_type_attribute_opt + enum_underlying_type_opt { - parser_stack($1).id(ID_c_enum_tag); // tag only + // an enum with tag parser_stack($1).set(ID_tag, parser_stack($3)); - $$=merge($1, merge($2, $4)); // throw in the gcc attributes + + if(parser_stack($4).is_not_nil()) + { + parser_stack($1).set(ID_enum_underlying_type, parser_stack($4)); + } + } + braced_enumerator_list_opt + gcc_type_attribute_opt + { + if(parser_stack($6).is_not_nil()) + { + parser_stack($1).operands().swap(parser_stack($6).operands()); + } + else + { + parser_stack($1).id(ID_c_enum_tag); + } + + $$=merge($1, merge($2, $7)); // throw in the gcc attributes } ; - + +enum_underlying_type_opt: + /* empty */ + { + init($$); + parser_stack($$).make_nil(); + } + | ':' basic_type_name + { + $$=$2; + } + +braced_enumerator_list_opt: + /* empty */ + { + init($$); + parser_stack($$).make_nil(); + } + | '{' enumerator_list_opt '}' + { + $$=$2; + } + enum_key: TOK_ENUM { $$=$1; diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index 84a2364a93d..917e1e79af6 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -212,6 +212,7 @@ IREP_ID_ONE(NULL) IREP_ID_ONE(null) IREP_ID_ONE(nullptr) IREP_ID_ONE(c_enum) +IREP_ID_ONE(enum_underlying_type) IREP_ID_ONE(enumeration) IREP_ID_ONE(elements) IREP_ID_ONE(unknown)