Skip to content

Commit 2877122

Browse files
author
Daniel Kroening
committed
further work on the type of enums in C
1 parent 4a883d0 commit 2877122

File tree

3 files changed

+115
-35
lines changed

3 files changed

+115
-35
lines changed

regression/ansi-c/gcc_types_compatible_p3/main.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,34 @@ enum help_format_neg {
2626
N_HELP_FORMAT_WEB,
2727
};
2828

29+
// The enum is signed if one of the values is negative
2930
enum help_format_neg help_format_neg = N_HELP_FORMAT_NONE;
3031
STATIC_ASSERT(__builtin_types_compatible_p(typeof(&help_format_neg), int*));
3132

33+
// The underlying type gets unsigned as needed.
34+
enum unsigned_enum { UINT=0xffffffff };
35+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(UINT), unsigned int));
36+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(enum unsigned_enum), unsigned int));
37+
38+
// The enum gets bigger as required, but note that the constant is now unsigned.
39+
enum large_enum1 { LARGE_CONSTANT1=0x100000000 };
40+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(LARGE_CONSTANT1), unsigned long));
41+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(enum large_enum1), unsigned long));
42+
43+
// Also works when signed
44+
enum large_enum2 { NEG=-1, LARGE_CONSTANT2=0x100000000 };
45+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(LARGE_CONSTANT2), signed long));
46+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(enum large_enum2), signed long));
47+
48+
// 'Packed' is interesting.
49+
enum __attribute__((packed)) packed_enum1 { POS_PACKED=1 };
50+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(POS_PACKED), signed int));
51+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(enum packed_enum1), unsigned char));
52+
53+
enum __attribute__((packed)) packed_enum2 { NEG_PACKED=-1 };
54+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(NEG_PACKED), signed int));
55+
STATIC_ASSERT(__builtin_types_compatible_p(typeof(enum packed_enum2), signed char));
56+
3257
#endif
3358

3459
int main()

src/ansi-c/c_typecheck_base.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,12 @@ 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(
208+
typet enum_constant_type(
209+
const mp_integer &min, const mp_integer &max) const;
210+
211+
typet enum_underlying_type(
209212
const mp_integer &min, const mp_integer &max,
210-
bool at_least_int) const;
213+
bool is_packed) const;
211214

212215
void make_already_typechecked(typet &dest)
213216
{

src/ansi-c/c_typecheck_type.cpp

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ void c_typecheck_baset::typecheck_compound_body(
10191019

10201020
/*******************************************************************\
10211021
1022-
Function: c_typecheck_baset::fitting_int_type
1022+
Function: c_typecheck_baset::enum_constant_type
10231023
10241024
Inputs:
10251025
@@ -1029,34 +1029,92 @@ Function: c_typecheck_baset::fitting_int_type
10291029
10301030
\*******************************************************************/
10311031

1032-
typet c_typecheck_baset::fitting_int_type(
1032+
typet c_typecheck_baset::enum_constant_type(
10331033
const mp_integer &min_value,
1034-
const mp_integer &max_value,
1035-
bool at_least_int) const
1034+
const mp_integer &max_value) const
10361035
{
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)))
1036+
// enum constants are at least 'int', but may be made larger.
1037+
// 'Packing' has no influence.
1038+
if(max_value<(mp_integer(1)<<(config.ansi_c.int_width-1)) &&
1039+
min_value>=-(mp_integer(1)<<(config.ansi_c.int_width-1)))
10511040
return signed_int_type();
10521041
else if(max_value<(mp_integer(1)<<config.ansi_c.int_width) &&
10531042
min_value>=0)
10541043
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)))
1044+
else if(max_value<(mp_integer(1)<<config.ansi_c.long_int_width) &&
1045+
min_value>=0)
1046+
return unsigned_long_int_type();
1047+
else if(max_value<(mp_integer(1)<<config.ansi_c.long_long_int_width) &&
1048+
min_value>=0)
1049+
return unsigned_long_long_int_type();
1050+
else if(max_value<(mp_integer(1)<<(config.ansi_c.long_int_width-1)) &&
1051+
min_value>=-(mp_integer(1)<<(config.ansi_c.long_int_width-1)))
1052+
return signed_long_int_type();
1053+
else
10571054
return signed_long_long_int_type();
1055+
}
1056+
1057+
/*******************************************************************\
1058+
1059+
Function: c_typecheck_baset::enum_underlying_type
1060+
1061+
Inputs:
1062+
1063+
Outputs:
1064+
1065+
Purpose:
1066+
1067+
\*******************************************************************/
1068+
1069+
typet c_typecheck_baset::enum_underlying_type(
1070+
const mp_integer &min_value,
1071+
const mp_integer &max_value,
1072+
bool is_packed) const
1073+
{
1074+
if(min_value<0)
1075+
{
1076+
// We'll want a signed type.
1077+
1078+
if(is_packed)
1079+
{
1080+
// If packed, there are smaller options.
1081+
if(max_value<(mp_integer(1)<<(config.ansi_c.char_width-1)) &&
1082+
min_value>=-(mp_integer(1)<<(config.ansi_c.char_width-1)))
1083+
return signed_char_type();
1084+
else if(max_value<(mp_integer(1)<<(config.ansi_c.short_int_width-1)) &&
1085+
min_value>=-(mp_integer(1)<<(config.ansi_c.short_int_width-1)))
1086+
return signed_short_int_type();
1087+
}
1088+
1089+
if(max_value<(mp_integer(1)<<(config.ansi_c.int_width-1)) &&
1090+
min_value>=-(mp_integer(1)<<(config.ansi_c.int_width-1)))
1091+
return signed_int_type();
1092+
else if(max_value<(mp_integer(1)<<(config.ansi_c.long_int_width-1)) &&
1093+
min_value>=-(mp_integer(1)<<(config.ansi_c.long_int_width-1)))
1094+
return signed_long_int_type();
1095+
else
1096+
return signed_long_long_int_type();
1097+
}
10581098
else
1059-
return unsigned_long_long_int_type();
1099+
{
1100+
// We'll want an unsigned type.
1101+
1102+
if(is_packed)
1103+
{
1104+
// If packed, there are smaller options.
1105+
if(max_value<(mp_integer(1)<<config.ansi_c.char_width))
1106+
return unsigned_char_type();
1107+
else if(max_value<(mp_integer(1)<<config.ansi_c.short_int_width))
1108+
return unsigned_short_int_type();
1109+
}
1110+
1111+
if(max_value<(mp_integer(1)<<config.ansi_c.int_width))
1112+
return unsigned_int_type();
1113+
else if(max_value<(mp_integer(1)<<config.ansi_c.long_int_width))
1114+
return unsigned_long_int_type();
1115+
else
1116+
return unsigned_long_long_int_type();
1117+
}
10601118
}
10611119

10621120
/*******************************************************************\
@@ -1129,13 +1187,12 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
11291187
if(value<min_value) min_value=value;
11301188
if(value>max_value) max_value=value;
11311189

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);
1190+
typet constant_type=
1191+
enum_constant_type(min_value, max_value);
11351192

1136-
v=from_integer(value, underlying_type);
1193+
v=from_integer(value, constant_type);
11371194

1138-
declaration.type()=underlying_type;
1195+
declaration.type()=constant_type;
11391196
typecheck_declaration(declaration);
11401197

11411198
irep_idt base_name=
@@ -1208,14 +1265,9 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
12081265
body.push_back(*it);
12091266

12101267
// 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.
12131268
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-
1269+
enum_underlying_type(min_value, max_value, is_packed);
1270+
12191271
enum_tag_symbol.type.subtype()=underlying_type;
12201272

12211273
// is it in the symbol table already?

0 commit comments

Comments
 (0)