Skip to content

Commit 2c3fdc1

Browse files
author
Daniel Kroening
committed
fix for the underlying type of enums
1 parent ecb65f6 commit 2c3fdc1

File tree

5 files changed

+111
-79
lines changed

5 files changed

+111
-79
lines changed

regression/ansi-c/enum3/main.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@ enum __attribute__((packed)) { E3v1=1000, E3v2 } e3;
99
enum { E4v1=-1, E4v2 } e4; // not packed
1010
enum { E5v0=10, E5v1=0x100000000ll } e5;
1111
enum { E6 = E3v1 | 1 };
12-
13-
STATIC_ASSERT(sizeof(e1) == 1);
14-
STATIC_ASSERT(sizeof(e2) == 1);
15-
STATIC_ASSERT(sizeof(e3) == 2);
16-
STATIC_ASSERT(sizeof(E1v1) == sizeof(int));
17-
STATIC_ASSERT(sizeof(e4) == sizeof(int));
18-
// STATIC_ASSERT(sizeof(e5) == 8); // todo
12+
enum { E7v1=0, E7v2=sizeof(E7v1), E7v3=0x100000000ll };
13+
14+
STATIC_ASSERT(sizeof e1 == 1);
15+
STATIC_ASSERT(sizeof E1v1 == sizeof(int)); // but the constant is still at least int
16+
STATIC_ASSERT(sizeof e2 == 1);
17+
STATIC_ASSERT(sizeof e3 == 2);
18+
STATIC_ASSERT(sizeof E4v1 == sizeof(int));
19+
STATIC_ASSERT(sizeof e4 == sizeof(int));
20+
STATIC_ASSERT(sizeof e5 == 8);
21+
STATIC_ASSERT(E5v1 == 0x100000000ll);
22+
STATIC_ASSERT(E3v1 == 1000);
1923
STATIC_ASSERT(E6 == 1001);
24+
STATIC_ASSERT(E7v2 == sizeof(int));
25+
STATIC_ASSERT(sizeof E7v3 == sizeof(long long));
2026

2127
int main()
2228
{

regression/ansi-c/gcc_types_compatible_p1/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ STATIC_ASSERT(sizeof(long)!=4 || __builtin_types_compatible_p(uint64_t, unsigned
4848
STATIC_ASSERT(__builtin_types_compatible_p(int, const int));
4949
STATIC_ASSERT(__builtin_types_compatible_p(int, signed));
5050
STATIC_ASSERT(__builtin_types_compatible_p(typeof (hot), int));
51+
STATIC_ASSERT(__builtin_types_compatible_p(typeof (dingos), unsigned)); // ha!
5152
STATIC_ASSERT(__builtin_types_compatible_p(typeof (hot), typeof (laura)));
5253
STATIC_ASSERT(__builtin_types_compatible_p(int[5], int[]));
5354
STATIC_ASSERT(__builtin_types_compatible_p(same1, same2));

regression/ansi-c/gcc_types_compatible_p3/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ enum help_format {
1111
HELP_FORMAT_WEB,
1212
};
1313

14+
// The enums are 'unsigned int'
1415
enum help_format help_format = HELP_FORMAT_MAN;
1516
STATIC_ASSERT(__builtin_types_compatible_p(typeof(&help_format), unsigned int*));
1617

src/ansi-c/c_typecheck_base.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ class c_typecheck_baset:
205205
virtual void adjust_function_parameter(typet &type) const;
206206
virtual bool is_complete_type(const typet &type) const;
207207

208+
typet fitting_int_type(
209+
const mp_integer &min, const mp_integer &max,
210+
bool at_least_int) const;
211+
208212
void make_already_typechecked(typet &dest)
209213
{
210214
typet result(ID_already_typechecked);

src/ansi-c/c_typecheck_type.cpp

Lines changed: 92 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,48 @@ void c_typecheck_baset::typecheck_compound_body(
10191019

10201020
/*******************************************************************\
10211021
1022+
Function: c_typecheck_baset::fitting_int_type
1023+
1024+
Inputs:
1025+
1026+
Outputs:
1027+
1028+
Purpose:
1029+
1030+
\*******************************************************************/
1031+
1032+
typet c_typecheck_baset::fitting_int_type(
1033+
const mp_integer &min_value,
1034+
const mp_integer &max_value,
1035+
bool at_least_int) const
1036+
{
1037+
if(max_value<(mp_integer(1)<<(config.ansi_c.char_width-1)) &&
1038+
min_value>=-(mp_integer(1)<<(config.ansi_c.char_width-1)))
1039+
return at_least_int?signed_int_type():signed_char_type();
1040+
else if(max_value<(mp_integer(1)<<config.ansi_c.char_width) &&
1041+
min_value>=0)
1042+
return at_least_int?signed_int_type():unsigned_char_type();
1043+
else if(max_value<(mp_integer(1)<<(config.ansi_c.short_int_width-1)) &&
1044+
min_value>=-(mp_integer(1)<<(config.ansi_c.short_int_width-1)))
1045+
return at_least_int?signed_int_type():signed_short_int_type();
1046+
else if(max_value<(mp_integer(1)<<config.ansi_c.short_int_width) &&
1047+
min_value>=0)
1048+
return at_least_int?signed_int_type():unsigned_short_int_type();
1049+
else if(max_value<(mp_integer(1)<<(config.ansi_c.int_width-1)) &&
1050+
min_value>=-(mp_integer(1)<<(config.ansi_c.int_width-1)))
1051+
return signed_int_type();
1052+
else if(max_value<(mp_integer(1)<<config.ansi_c.int_width) &&
1053+
min_value>=0)
1054+
return unsigned_int_type();
1055+
else if(max_value<(mp_integer(1)<<(config.ansi_c.long_long_int_width-1)) &&
1056+
min_value>=-(mp_integer(1)<<(config.ansi_c.long_long_int_width-1)))
1057+
return signed_long_long_int_type();
1058+
else
1059+
return unsigned_long_long_int_type();
1060+
}
1061+
1062+
/*******************************************************************\
1063+
10221064
Function: c_typecheck_baset::typecheck_c_enum_type
10231065
10241066
Inputs:
@@ -1046,36 +1088,54 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
10461088
throw 0;
10471089
}
10481090

1049-
// enums start at zero
1050-
mp_integer value=0;
1051-
1052-
// track min and max to find a nice base type
1053-
mp_integer min_value=0, max_value=0;
1054-
1091+
// enums start at zero;
1092+
// we also track min and max to find a nice base type
1093+
mp_integer value=0, min_value=0, max_value=0;
1094+
10551095
std::list<c_enum_typet::c_enum_membert> enum_members;
10561096

1057-
Forall_operands(it, as_expr)
1058-
{
1059-
ansi_c_declarationt &declaration=to_ansi_c_declaration(*it);
1060-
1061-
// In C, enum constants always have type "int". They do not
1062-
// have the enum type.
1063-
declaration.type()=typet(ID_int);
1097+
// We need to determine a width, and a signedness
1098+
// to obtain an 'underlying type'.
1099+
// We just do int, but gcc might pick smaller widths
1100+
// if the type is marked as 'packed'.
1101+
// gcc/clang may also pick a larger width. Visual Studio doesn't.
10641102

1103+
for(auto & it : as_expr.operands())
1104+
{
1105+
ansi_c_declarationt &declaration=to_ansi_c_declaration(it);
10651106
exprt &v=declaration.declarator().value();
10661107

1067-
if(v.is_nil()) // no value given
1068-
v=from_integer(value, signed_int_type());
1069-
else
1108+
if(v.is_not_nil()) // value given?
10701109
{
10711110
exprt tmp_v=v;
10721111
typecheck_expr(tmp_v);
10731112
add_rounding_mode(tmp_v);
10741113
simplify(tmp_v, *this);
1075-
if(tmp_v.is_constant())
1076-
v=tmp_v;
1114+
if(tmp_v.is_true())
1115+
value=1;
1116+
else if(tmp_v.is_false())
1117+
value=0;
1118+
else if(!to_integer(tmp_v, value))
1119+
{
1120+
}
1121+
else
1122+
{
1123+
error().source_location=v.source_location();
1124+
error() << "enum is not a constant";
1125+
throw 0;
1126+
}
10771127
}
10781128

1129+
if(value<min_value) min_value=value;
1130+
if(value>max_value) max_value=value;
1131+
1132+
// The type of the enum constant is 'int', unless it it's larger.
1133+
typet underlying_type=
1134+
fitting_int_type(min_value, max_value, true);
1135+
1136+
v=from_integer(value, underlying_type);
1137+
1138+
declaration.type()=underlying_type;
10791139
typecheck_declaration(declaration);
10801140

10811141
irep_idt base_name=
@@ -1084,70 +1144,23 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
10841144
irep_idt identifier=
10851145
declaration.declarator().get_name();
10861146

1087-
// get value
1088-
const symbolt &symbol=lookup(identifier);
1089-
1090-
to_integer(symbol.value, value);
1091-
10921147
// store
10931148
c_enum_typet::c_enum_membert member;
10941149
member.set_identifier(identifier);
10951150
member.set_base_name(base_name);
10961151
member.set_value(integer2string(value));
10971152
enum_members.push_back(member);
1098-
1099-
if(value<min_value) min_value=value;
1100-
if(value>max_value) max_value=value;
1101-
1153+
11021154
// produce value for next constant
11031155
++value;
11041156
}
1105-
1157+
11061158
// Remove these now; we add them to the
11071159
// c_enum symbol later.
1108-
#ifdef OPERANDS_IN_GETSUB
11091160
as_expr.operands().clear();
1110-
#else
1111-
type.remove(ID_operands);
1112-
#endif
11131161

1114-
// We need to determine a width, and a signedness.
1115-
// We just do int, but gcc might pick smaller widths
1116-
// if the type is marked as 'packed'.
1117-
1118-
unsigned bits=0;
1119-
bool is_signed=min_value<0;
1120-
1121-
if(is_signed)
1122-
{
1123-
if(max_value<(1<<7) && min_value>=-(1<<7))
1124-
bits=1*8;
1125-
else if(max_value<(1<<15) && min_value>=-(1<<15))
1126-
bits=2*8;
1127-
else if(max_value<(mp_integer(1)<<31) && min_value>=-(mp_integer(1)<<31))
1128-
bits=4*8;
1129-
else
1130-
bits=8*8;
1131-
}
1132-
else // unsigned
1133-
{
1134-
if(max_value<(1<<8))
1135-
bits=1*8;
1136-
else if(max_value<(1<<16))
1137-
bits=2*8;
1138-
else if(max_value<(mp_integer(1)<<32))
1139-
bits=4*8;
1140-
else
1141-
bits=8*8;
1142-
}
1162+
bool is_packed=type.get_bool(ID_C_packed);
11431163

1144-
if(!type.get_bool(ID_C_packed))
1145-
{
1146-
// If it's not packed we do int as a minimum.
1147-
if(bits<config.ansi_c.int_width)
1148-
bits=config.ansi_c.int_width;
1149-
}
1150-
11511164
// tag?
11521165
if(type.find(ID_tag).is_nil())
11531166
{
@@ -1165,7 +1178,7 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
11651178
anon_identifier+=id2string(it->get_value());
11661179
}
11671180

1168-
if(type.get_bool(ID_C_packed))
1181+
if(is_packed)
11691182
anon_identifier+="#packed";
11701183

11711184
type.add(ID_tag).set(ID_identifier, anon_identifier);
@@ -1194,9 +1207,16 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
11941207
it++)
11951208
body.push_back(*it);
11961209

1197-
// We use a subtype to store signed and width
1198-
enum_tag_symbol.type.subtype().id(is_signed?ID_signedbv:ID_unsignedbv);
1199-
enum_tag_symbol.type.subtype().set(ID_width, bits);
1210+
// We use a subtype to store the underlying type.
1211+
// This is at least 'int' unless packed if negative,
1212+
// and at least 'unsigned int' otherwise.
1213+
typet underlying_type=
1214+
fitting_int_type(min_value, max_value, !is_packed);
1215+
if(underlying_type==signed_int_type() &&
1216+
min_value>=0)
1217+
underlying_type=unsigned_int_type();
1218+
1219+
enum_tag_symbol.type.subtype()=underlying_type;
12001220

12011221
// is it in the symbol table already?
12021222
symbol_tablet::symbolst::iterator s_it=

0 commit comments

Comments
 (0)