Skip to content

Commit 727f7e6

Browse files
authored
Merge pull request diffblue#4148 from diffblue/gcc_switch_case_range
introduce code_gcc_switch_case_ranget
2 parents 126aaaa + a214fe7 commit 727f7e6

File tree

6 files changed

+110
-38
lines changed

6 files changed

+110
-38
lines changed

src/ansi-c/c_typecheck_base.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class c_typecheck_baset:
136136
virtual void typecheck_label(code_labelt &code);
137137
virtual void typecheck_switch_case(code_switch_caset &code);
138138
virtual void typecheck_gcc_computed_goto(codet &code);
139-
virtual void typecheck_gcc_switch_case_range(codet &code);
139+
virtual void typecheck_gcc_switch_case_range(code_gcc_switch_case_ranget &);
140140
virtual void typecheck_gcc_local_label(codet &code);
141141
virtual void typecheck_return(codet &code);
142142
virtual void typecheck_switch(code_switcht &code);

src/ansi-c/c_typecheck_code.cpp

+10-18
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void c_typecheck_baset::typecheck_code(codet &code)
4242
else if(statement==ID_switch_case)
4343
typecheck_switch_case(to_code_switch_case(code));
4444
else if(statement==ID_gcc_switch_case_range)
45-
typecheck_gcc_switch_case_range(code);
45+
typecheck_gcc_switch_case_range(to_code_gcc_switch_case_range(code));
4646
else if(statement==ID_block)
4747
typecheck_block(to_code_block(code));
4848
else if(statement==ID_decl_block)
@@ -515,31 +515,23 @@ void c_typecheck_baset::typecheck_switch_case(code_switch_caset &code)
515515
}
516516
}
517517

518-
void c_typecheck_baset::typecheck_gcc_switch_case_range(codet &code)
518+
void c_typecheck_baset::typecheck_gcc_switch_case_range(
519+
code_gcc_switch_case_ranget &code)
519520
{
520-
if(code.operands().size()!=3)
521-
{
522-
error().source_location = code.source_location();
523-
error() << "gcc_switch_case_range expected to have three operands"
524-
<< eom;
525-
throw 0;
526-
}
527-
528-
typecheck_code(to_code(code.op2()));
529-
530521
if(!case_is_allowed)
531522
{
532523
error().source_location = code.source_location();
533524
error() << "did not expect `case' here" << eom;
534525
throw 0;
535526
}
536527

537-
typecheck_expr(code.op0());
538-
typecheck_expr(code.op1());
539-
implicit_typecast(code.op0(), switch_op_type);
540-
implicit_typecast(code.op1(), switch_op_type);
541-
make_constant(code.op0());
542-
make_constant(code.op1());
528+
typecheck_expr(code.lower());
529+
typecheck_expr(code.upper());
530+
implicit_typecast(code.lower(), switch_op_type);
531+
implicit_typecast(code.upper(), switch_op_type);
532+
make_constant(code.lower());
533+
make_constant(code.upper());
534+
typecheck_code(code.code());
543535
}
544536

545537
void c_typecheck_baset::typecheck_gcc_local_label(codet &)

src/cpp/parse.cpp

+5-7
Original file line numberDiff line numberDiff line change
@@ -7414,20 +7414,18 @@ bool Parser::rStatement(codet &statement)
74147414
if(!rExpression(range_end, false))
74157415
return false;
74167416

7417-
statement=codet(ID_gcc_switch_case_range);
7418-
statement.operands().resize(3);
7419-
statement.op0()=case_expr;
7420-
statement.op1()=range_end;
7421-
set_location(statement, tk1);
7422-
74237417
if(lex.get_token(tk2)!=':')
74247418
return false;
74257419

74267420
codet statement2;
74277421
if(!rStatement(statement2))
74287422
return false;
74297423

7430-
statement.op2().swap(statement2);
7424+
code_gcc_switch_case_ranget code(
7425+
std::move(case_expr), std::move(range_end), std::move(statement2));
7426+
set_location(code, tk1);
7427+
7428+
statement = std::move(code);
74317429
}
74327430
else
74337431
{

src/goto-programs/goto_convert.cpp

+7-11
Original file line numberDiff line numberDiff line change
@@ -384,17 +384,12 @@ void goto_convertt::convert_switch_case(
384384
}
385385

386386
void goto_convertt::convert_gcc_switch_case_range(
387-
const codet &code,
387+
const code_gcc_switch_case_ranget &code,
388388
goto_programt &dest,
389389
const irep_idt &mode)
390390
{
391-
INVARIANT_WITH_DIAGNOSTICS(
392-
code.operands().size() == 3,
393-
"GCC's switch-case-range statement expected to have three operands",
394-
code.find_source_location());
395-
396-
const auto lb = numeric_cast<mp_integer>(code.op0());
397-
const auto ub = numeric_cast<mp_integer>(code.op1());
391+
const auto lb = numeric_cast<mp_integer>(code.lower());
392+
const auto ub = numeric_cast<mp_integer>(code.upper());
398393

399394
INVARIANT_WITH_DIAGNOSTICS(
400395
lb.has_value() && ub.has_value(),
@@ -409,7 +404,7 @@ void goto_convertt::convert_gcc_switch_case_range(
409404
}
410405

411406
goto_programt tmp;
412-
convert(to_code(code.op2()), tmp, mode);
407+
convert(code.code(), tmp, mode);
413408

414409
goto_programt::targett target = tmp.instructions.begin();
415410
dest.destructive_append(tmp);
@@ -425,7 +420,7 @@ void goto_convertt::convert_gcc_switch_case_range(
425420
exprt::operandst &case_op_dest = cases_entry->second->second;
426421

427422
for(mp_integer i = *lb; i <= *ub; ++i)
428-
case_op_dest.push_back(from_integer(i, code.op0().type()));
423+
case_op_dest.push_back(from_integer(i, code.lower().type()));
429424
}
430425

431426
/// converts 'code' and appends the result to 'dest'
@@ -459,7 +454,8 @@ void goto_convertt::convert(
459454
else if(statement==ID_switch_case)
460455
convert_switch_case(to_code_switch_case(code), dest, mode);
461456
else if(statement==ID_gcc_switch_case_range)
462-
convert_gcc_switch_case_range(code, dest, mode);
457+
convert_gcc_switch_case_range(
458+
to_code_gcc_switch_case_range(code), dest, mode);
463459
else if(statement==ID_for)
464460
convert_for(to_code_for(code), dest, mode);
465461
else if(statement==ID_while)

src/goto-programs/goto_convert_class.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ class goto_convertt:public messaget
283283
goto_programt &dest,
284284
const irep_idt &mode);
285285
void convert_gcc_switch_case_range(
286-
const codet &code,
286+
const code_gcc_switch_case_ranget &,
287287
goto_programt &dest,
288288
const irep_idt &mode);
289289
void convert_function_call(

src/util/std_code.h

+86
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,92 @@ inline code_switch_caset &to_code_switch_case(codet &code)
14741474
return static_cast<code_switch_caset &>(code);
14751475
}
14761476

1477+
/// \ref codet representation of a switch-case, i.e.\ a `case` statement
1478+
/// within a `switch`. This is the variant that takes a range,
1479+
/// which is a gcc extension.
1480+
class code_gcc_switch_case_ranget : public codet
1481+
{
1482+
public:
1483+
code_gcc_switch_case_ranget(exprt _lower, exprt _upper, codet _code)
1484+
: codet(
1485+
ID_gcc_switch_case_range,
1486+
{std::move(_lower), std::move(_upper), std::move(_code)})
1487+
{
1488+
}
1489+
1490+
/// lower bound of range
1491+
const exprt &lower() const
1492+
{
1493+
return op0();
1494+
}
1495+
1496+
/// lower bound of range
1497+
exprt &lower()
1498+
{
1499+
return op0();
1500+
}
1501+
1502+
/// upper bound of range
1503+
const exprt &upper() const
1504+
{
1505+
return op1();
1506+
}
1507+
1508+
/// upper bound of range
1509+
exprt &upper()
1510+
{
1511+
return op1();
1512+
}
1513+
1514+
/// the statement to be executed when the case applies
1515+
codet &code()
1516+
{
1517+
return static_cast<codet &>(op2());
1518+
}
1519+
1520+
/// the statement to be executed when the case applies
1521+
const codet &code() const
1522+
{
1523+
return static_cast<const codet &>(op2());
1524+
}
1525+
1526+
protected:
1527+
using codet::op0;
1528+
using codet::op1;
1529+
using codet::op2;
1530+
using codet::op3;
1531+
};
1532+
1533+
template <>
1534+
inline bool can_cast_expr<code_gcc_switch_case_ranget>(const exprt &base)
1535+
{
1536+
return detail::can_cast_code_impl(base, ID_gcc_switch_case_range);
1537+
}
1538+
1539+
inline void validate_expr(const code_gcc_switch_case_ranget &x)
1540+
{
1541+
validate_operands(x, 3, "gcc-switch-case-range must have three operands");
1542+
}
1543+
1544+
inline const code_gcc_switch_case_ranget &
1545+
to_code_gcc_switch_case_range(const codet &code)
1546+
{
1547+
PRECONDITION(code.get_statement() == ID_gcc_switch_case_range);
1548+
DATA_INVARIANT(
1549+
code.operands().size() == 3,
1550+
"gcc-switch-case-range must have three operands");
1551+
return static_cast<const code_gcc_switch_case_ranget &>(code);
1552+
}
1553+
1554+
inline code_gcc_switch_case_ranget &to_code_gcc_switch_case_range(codet &code)
1555+
{
1556+
PRECONDITION(code.get_statement() == ID_gcc_switch_case_range);
1557+
DATA_INVARIANT(
1558+
code.operands().size() == 3,
1559+
"gcc-switch-case-range must have three operands");
1560+
return static_cast<code_gcc_switch_case_ranget &>(code);
1561+
}
1562+
14771563
/// \ref codet representation of a `break` statement (within a `for` or `while`
14781564
/// loop).
14791565
class code_breakt:public codet

0 commit comments

Comments
 (0)