Skip to content

Commit cb892af

Browse files
committed
Move promotion rule application to C front-end
The front-ends handle type conversion when doing arithmetic over enum types. The case of an enum tag is not expected in goto-program conversion. That, however, was only the case for some operators. Made the C front-end properly handle all assignment operators. While at it, also support decrement operators over complex numbers. We already did so for increment, decrement just requires the same special case.
1 parent d285eb8 commit cb892af

File tree

5 files changed

+121
-121
lines changed

5 files changed

+121
-121
lines changed

regression/cbmc/complex1/main.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
int main()
44
{
5-
#ifdef __GNUC__
5+
#ifdef __GNUC__
66
_Complex c; // this is usually '_Complex double'
77
c=1.0i+2;
88

@@ -21,10 +21,10 @@ int main()
2121

2222
// The real part is stored first in memory on i386.
2323
// Need to find out about other architectures.
24-
#if defined(__i386__) || defined(__amd64__)
24+
#if defined(__i386__) || defined(__amd64__)
2525
assert(((signed char *)&char_complex)[0]==-2);
2626
assert(((signed char *)&char_complex)[1]==3);
27-
#endif
27+
#endif
2828

2929
assert(__real__ char_complex == -2);
3030
assert(__imag__ char_complex == 3);
@@ -44,18 +44,35 @@ int main()
4444
char_complex++;
4545
assert(__real__ char_complex == 101);
4646
assert(__imag__ char_complex == 3);
47+
++char_complex;
48+
assert(__real__ char_complex == 102);
49+
assert(__imag__ char_complex == 3);
50+
char_complex += 1;
51+
assert(__real__ char_complex == 103);
52+
assert(__imag__ char_complex == 3);
4753

4854
// also separately
4955
(__real__ char_complex)++;
50-
assert(__real__ char_complex == 102);
56+
assert(__real__ char_complex == 104);
5157
assert(__imag__ char_complex == 3);
5258

5359
// casts to reals produce the real part
54-
assert((int) char_complex == 102);
60+
assert((int)char_complex == 104);
61+
62+
// can be decremented
63+
char_complex--;
64+
assert(__real__ char_complex == 103);
65+
assert(__imag__ char_complex == 3);
66+
--char_complex;
67+
assert(__real__ char_complex == 102);
68+
assert(__imag__ char_complex == 3);
69+
char_complex -= 1;
70+
assert(__real__ char_complex == 101);
71+
assert(__imag__ char_complex == 3);
5572

56-
#else
73+
#else
5774

5875
// Visual studio doesn't have it
5976

60-
#endif
77+
#endif
6178
}

regression/cbmc/enum8/main.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <assert.h>
2+
3+
enum E
4+
{
5+
A = 1,
6+
B = 16
7+
};
8+
9+
int main()
10+
{
11+
enum E e = A;
12+
e <<= 4;
13+
assert(e == B);
14+
e >>= 4;
15+
assert(e == A);
16+
e |= B;
17+
e ^= A;
18+
assert(e == B);
19+
e -= 15;
20+
assert(e == A);
21+
return 0;
22+
}

regression/cbmc/enum8/test.desc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,16 +1855,20 @@ void c_typecheck_baset::typecheck_expr_side_effect(side_effect_exprt &expr)
18551855

18561856
if(type0.id() == ID_c_enum_tag)
18571857
{
1858-
if(follow_tag(to_c_enum_tag_type(type0)).is_incomplete())
1858+
const c_enum_typet &enum_type = follow_tag(to_c_enum_tag_type(type0));
1859+
if(enum_type.is_incomplete())
18591860
{
18601861
error().source_location = expr.source_location();
18611862
error() << "operator `" << statement
18621863
<< "' given incomplete type `"
18631864
<< to_string(type0) << "'" << eom;
18641865
throw 0;
18651866
}
1866-
else
1867-
expr.type()=type0;
1867+
1868+
// increment/decrement on underlying type
1869+
expr.op0() = typecast_exprt(expr.op0(), enum_type.subtype());
1870+
expr.type() = enum_type.subtype();
1871+
implicit_typecast_arithmetic(expr);
18681872
}
18691873
else if(type0.id() == ID_c_bit_field)
18701874
{
@@ -1873,6 +1877,11 @@ void c_typecheck_baset::typecheck_expr_side_effect(side_effect_exprt &expr)
18731877
expr.op0() = typecast_exprt(expr.op0(), underlying_type);
18741878
expr.type()=underlying_type;
18751879
}
1880+
else if(type0.id() == ID_bool || type0.id() == ID_c_bool)
1881+
{
1882+
implicit_typecast_arithmetic(expr.op0());
1883+
expr.type() = expr.op0().type();
1884+
}
18761885
else if(is_numeric_type(type0))
18771886
{
18781887
expr.type()=type0;
@@ -3321,6 +3330,7 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
33213330
else if(statement==ID_assign_shl ||
33223331
statement==ID_assign_shr)
33233332
{
3333+
implicit_typecast_arithmetic(op0);
33243334
implicit_typecast_arithmetic(op1);
33253335

33263336
if(is_number(op1.type()))
@@ -3335,12 +3345,6 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
33353345

33363346
typet underlying_type=op0.type();
33373347

3338-
if(underlying_type.id()==ID_c_enum_tag)
3339-
{
3340-
const auto &c_enum_type = to_c_enum_tag_type(underlying_type);
3341-
underlying_type=c_enum_type.subtype();
3342-
}
3343-
33443348
if(underlying_type.id()==ID_unsignedbv ||
33453349
underlying_type.id()==ID_c_bool)
33463350
{
@@ -3363,7 +3367,7 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
33633367
if(o_type0.id()==ID_bool ||
33643368
o_type0.id()==ID_c_bool)
33653369
{
3366-
implicit_typecast_arithmetic(op1);
3370+
implicit_typecast_arithmetic(op0, op1);
33673371
if(op1.type().id()==ID_bool ||
33683372
op1.type().id()==ID_c_bool ||
33693373
op1.type().id()==ID_c_enum_tag ||
@@ -3376,7 +3380,7 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
33763380
o_type0.id()==ID_signedbv ||
33773381
o_type0.id()==ID_c_bit_field)
33783382
{
3379-
implicit_typecast(op1, o_type0);
3383+
implicit_typecast_arithmetic(op0, op1);
33803384
return;
33813385
}
33823386
else if(o_type0.id()==ID_vector &&
@@ -3413,7 +3417,7 @@ void c_typecheck_baset::typecheck_side_effect_assignment(
34133417
else if(o_type0.id()==ID_bool ||
34143418
o_type0.id()==ID_c_bool)
34153419
{
3416-
implicit_typecast_arithmetic(op1);
3420+
implicit_typecast_arithmetic(op0, op1);
34173421
if(op1.type().id()==ID_bool ||
34183422
op1.type().id()==ID_c_bool ||
34193423
op1.type().id()==ID_c_enum_tag ||

src/goto-programs/goto_convert_side_effect.cpp

Lines changed: 51 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,13 @@ void goto_convertt::remove_assignment(
9999

100100
const typet &op0_type = expr.op0().type();
101101

102-
if(op0_type.id()==ID_c_bool)
103-
{
104-
// C/C++ Booleans get very special treatment.
105-
binary_exprt tmp(expr.op0(), new_id, expr.op1(), expr.op1().type());
106-
tmp.op0().make_typecast(expr.op1().type());
107-
rhs=typecast_exprt(is_not_zero(tmp, ns), expr.op0().type());
108-
}
109-
else if(op0_type.id() == ID_c_enum_tag)
110-
{
111-
// We convert c_enums to their underlying type, do the
112-
// operation, and then convert back
113-
const auto &enum_type = ns.follow_tag(to_c_enum_tag_type(op0_type));
114-
auto underlying_type = enum_type.subtype();
115-
auto op0 = typecast_exprt(expr.op0(), underlying_type);
116-
auto op1 = typecast_exprt(expr.op1(), underlying_type);
117-
binary_exprt tmp(op0, new_id, op1, underlying_type);
118-
rhs = typecast_exprt(tmp, expr.op0().type());
119-
}
120-
else
121-
{
122-
rhs.id(new_id);
123-
rhs.copy_to_operands(expr.op0(), expr.op1());
124-
rhs.type()=expr.op0().type();
125-
rhs.add_source_location()=expr.source_location();
126-
}
102+
PRECONDITION(
103+
op0_type.id() != ID_c_enum_tag && op0_type.id() != ID_c_enum &&
104+
op0_type.id() != ID_c_bool && op0_type.id() != ID_bool);
105+
rhs.id(new_id);
106+
rhs.copy_to_operands(expr.op0(), expr.op1());
107+
rhs.type() = expr.op0().type();
108+
rhs.add_source_location() = expr.source_location();
127109

128110
code_assignt assignment(expr.op0(), rhs);
129111
assignment.add_source_location()=expr.source_location();
@@ -171,45 +153,34 @@ void goto_convertt::remove_pre(
171153

172154
const typet &op_type = expr.op0().type();
173155

174-
if(op_type.id()==ID_bool)
175-
{
176-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
177-
rhs.op0().make_typecast(signed_int_type());
178-
rhs.type()=signed_int_type();
179-
rhs=is_not_zero(rhs, ns);
180-
}
181-
else if(op_type.id()==ID_c_bool)
156+
PRECONDITION(
157+
op_type.id() != ID_c_enum_tag && op_type.id() != ID_c_enum &&
158+
op_type.id() != ID_c_bool && op_type.id() != ID_bool);
159+
160+
typet constant_type;
161+
162+
if(op_type.id() == ID_pointer)
163+
constant_type = index_type();
164+
else if(is_number(op_type))
165+
constant_type = op_type;
166+
else
182167
{
183-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
184-
rhs.op0().make_typecast(signed_int_type());
185-
rhs.type()=signed_int_type();
186-
rhs=is_not_zero(rhs, ns);
187-
rhs.make_typecast(op_type);
168+
UNREACHABLE;
188169
}
189-
else if(op_type.id()==ID_c_enum ||
190-
op_type.id()==ID_c_enum_tag)
170+
171+
exprt constant;
172+
173+
if(constant_type.id() == ID_complex)
191174
{
192-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
193-
rhs.op0().make_typecast(signed_int_type());
194-
rhs.type()=signed_int_type();
195-
rhs.make_typecast(op_type);
175+
exprt real = from_integer(1, constant_type.subtype());
176+
exprt imag = from_integer(0, constant_type.subtype());
177+
constant = complex_exprt(real, imag, to_complex_type(constant_type));
196178
}
197179
else
198-
{
199-
typet constant_type;
200-
201-
if(op_type.id()==ID_pointer)
202-
constant_type=index_type();
203-
else if(is_number(op_type) || op_type.id()==ID_c_bool)
204-
constant_type=op_type;
205-
else
206-
{
207-
UNREACHABLE;
208-
}
180+
constant = from_integer(1, constant_type);
209181

210-
rhs.add_to_operands(expr.op0(), from_integer(1, constant_type));
211-
rhs.type()=expr.op0().type();
212-
}
182+
rhs.add_to_operands(expr.op0(), std::move(constant));
183+
rhs.type() = expr.op0().type();
213184

214185
code_assignt assignment(expr.op0(), rhs);
215186
assignment.add_source_location()=expr.find_source_location();
@@ -257,56 +228,34 @@ void goto_convertt::remove_post(
257228

258229
const typet &op_type = expr.op0().type();
259230

260-
if(op_type.id()==ID_bool)
261-
{
262-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
263-
rhs.op0().make_typecast(signed_int_type());
264-
rhs.type()=signed_int_type();
265-
rhs=is_not_zero(rhs, ns);
266-
}
267-
else if(op_type.id()==ID_c_bool)
231+
PRECONDITION(
232+
op_type.id() != ID_c_enum_tag && op_type.id() != ID_c_enum &&
233+
op_type.id() != ID_c_bool && op_type.id() != ID_bool);
234+
235+
typet constant_type;
236+
237+
if(op_type.id() == ID_pointer)
238+
constant_type = index_type();
239+
else if(is_number(op_type))
240+
constant_type = op_type;
241+
else
268242
{
269-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
270-
rhs.op0().make_typecast(signed_int_type());
271-
rhs.type()=signed_int_type();
272-
rhs=is_not_zero(rhs, ns);
273-
rhs.make_typecast(op_type);
243+
UNREACHABLE;
274244
}
275-
else if(op_type.id()==ID_c_enum ||
276-
op_type.id()==ID_c_enum_tag)
245+
246+
exprt constant;
247+
248+
if(constant_type.id() == ID_complex)
277249
{
278-
rhs.copy_to_operands(expr.op0(), from_integer(1, signed_int_type()));
279-
rhs.op0().make_typecast(signed_int_type());
280-
rhs.type()=signed_int_type();
281-
rhs.make_typecast(op_type);
250+
exprt real = from_integer(1, constant_type.subtype());
251+
exprt imag = from_integer(0, constant_type.subtype());
252+
constant = complex_exprt(real, imag, to_complex_type(constant_type));
282253
}
283254
else
284-
{
285-
typet constant_type;
255+
constant = from_integer(1, constant_type);
286256

287-
if(op_type.id()==ID_pointer)
288-
constant_type=index_type();
289-
else if(is_number(op_type) || op_type.id()==ID_c_bool)
290-
constant_type=op_type;
291-
else
292-
{
293-
UNREACHABLE;
294-
}
295-
296-
exprt constant;
297-
298-
if(constant_type.id()==ID_complex)
299-
{
300-
exprt real=from_integer(1, constant_type.subtype());
301-
exprt imag=from_integer(0, constant_type.subtype());
302-
constant=complex_exprt(real, imag, to_complex_type(constant_type));
303-
}
304-
else
305-
constant=from_integer(1, constant_type);
306-
307-
rhs.add_to_operands(expr.op0(), std::move(constant));
308-
rhs.type()=expr.op0().type();
309-
}
257+
rhs.add_to_operands(expr.op0(), std::move(constant));
258+
rhs.type() = expr.op0().type();
310259

311260
code_assignt assignment(expr.op0(), rhs);
312261
assignment.add_source_location()=expr.find_source_location();

0 commit comments

Comments
 (0)