Skip to content

Commit 0d5c737

Browse files
committed
C front-end: refactor type checking __builtin_*_overflow
Move the implementation to a method of its own. This avoids repeatedly testing the name to derive the underlying arithmetic operation. This change is to support upcoming extensions to handle further built-ins via this code path. No changes in behaviour intended with just this commit, and additional testing should ensure that this is also true for error handling. The function refactored from remains too large, and cpplint rightly complains about that, but this issue cannot be fixed in a single commit. Hence, adding an override.
1 parent 048b824 commit 0d5c737

File tree

5 files changed

+101
-59
lines changed

5 files changed

+101
-59
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
type-conflict.c
3+
4+
line 14 function main: __builtin_add_overflow takes exactly 3 arguments, but 2 were provided$
5+
^EXIT=6$
6+
^SIGNAL=0$
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
#ifndef __GNUC__
4+
_Bool __builtin_add_overflow();
5+
_Bool __builtin_add_overflow_p();
6+
#endif
7+
8+
int main(void)
9+
{
10+
int a, b, c, d, r;
11+
#ifdef CONFLICT1
12+
assert(!__builtin_add_overflow(a, b, r));
13+
#endif
14+
assert(__builtin_add_overflow(c, d));
15+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
type-conflict.c
3+
-DCONFLICT1
4+
line 12 function main: __builtin_add_overflow has signature __builtin_add_overflow\(integral, integral, integral\*\), but argument 3 \(r\) has type `signed int`$
5+
^EXIT=6$
6+
^SIGNAL=0$

src/ansi-c/c_typecheck_base.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ class c_typecheck_baset:
202202
virtual void typecheck_function_call_arguments(
203203
side_effect_expr_function_callt &expr);
204204
virtual exprt do_special_functions(side_effect_expr_function_callt &expr);
205+
exprt typecheck_builtin_overflow(
206+
side_effect_expr_function_callt &expr,
207+
const irep_idt &arith_op);
205208
virtual optionalt<symbol_exprt> typecheck_gcc_polymorphic_builtin(
206209
const irep_idt &identifier,
207210
const exprt::operandst &arguments,

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3170,76 +3170,88 @@ exprt c_typecheck_baset::do_special_functions(
31703170
}
31713171
else if(
31723172
identifier == "__builtin_add_overflow" ||
3173+
identifier == "__builtin_add_overflow_p")
3174+
{
3175+
return typecheck_builtin_overflow(expr, ID_plus);
3176+
}
3177+
else if(
31733178
identifier == "__builtin_sub_overflow" ||
3179+
identifier == "__builtin_sub_overflow_p")
3180+
{
3181+
return typecheck_builtin_overflow(expr, ID_minus);
3182+
}
3183+
else if(
31743184
identifier == "__builtin_mul_overflow" ||
3175-
identifier == "__builtin_add_overflow_p" ||
3176-
identifier == "__builtin_sub_overflow_p" ||
31773185
identifier == "__builtin_mul_overflow_p")
31783186
{
3179-
// check function signature
3180-
if(expr.arguments().size() != 3)
3181-
{
3182-
std::ostringstream error_message;
3183-
error_message << expr.source_location().as_string() << ": " << identifier
3184-
<< " takes exactly 3 arguments, but "
3185-
<< expr.arguments().size() << " were provided";
3186-
throw invalid_source_file_exceptiont{error_message.str()};
3187-
}
3187+
return typecheck_builtin_overflow(expr, ID_mult);
3188+
}
3189+
else
3190+
return nil_exprt();
3191+
// NOLINTNEXTLINE(readability/fn_size)
3192+
}
31883193

3189-
typecheck_function_call_arguments(expr);
3194+
exprt c_typecheck_baset::typecheck_builtin_overflow(
3195+
side_effect_expr_function_callt &expr,
3196+
const irep_idt &arith_op)
3197+
{
3198+
const irep_idt &identifier = to_symbol_expr(expr.function()).get_identifier();
31903199

3191-
auto lhs = expr.arguments()[0];
3192-
auto rhs = expr.arguments()[1];
3193-
auto result = expr.arguments()[2];
3194-
3195-
const bool is__p_variant = has_suffix(id2string(identifier), "_p");
3196-
3197-
{
3198-
auto const raise_wrong_argument_error =
3199-
[this, identifier](
3200-
const exprt &wrong_argument, std::size_t argument_number, bool _p) {
3201-
std::ostringstream error_message;
3202-
error_message << wrong_argument.source_location().as_string() << ": "
3203-
<< identifier << " has signature " << identifier
3204-
<< "(integral, integral, integral" << (_p ? "" : "*")
3205-
<< "), "
3206-
<< "but argument " << argument_number << " ("
3207-
<< expr2c(wrong_argument, *this) << ") has type `"
3208-
<< type2c(wrong_argument.type(), *this) << '`';
3209-
throw invalid_source_file_exceptiont{error_message.str()};
3210-
};
3211-
for(int arg_index = 0; arg_index <= (!is__p_variant ? 1 : 2); ++arg_index)
3212-
{
3213-
auto const &argument = expr.arguments()[arg_index];
3200+
// check function signature
3201+
if(expr.arguments().size() != 3)
3202+
{
3203+
std::ostringstream error_message;
3204+
error_message << expr.source_location().as_string() << ": " << identifier
3205+
<< " takes exactly 3 arguments, but "
3206+
<< expr.arguments().size() << " were provided";
3207+
throw invalid_source_file_exceptiont{error_message.str()};
3208+
}
32143209

3215-
if(!is_signed_or_unsigned_bitvector(argument.type()))
3216-
{
3217-
raise_wrong_argument_error(argument, arg_index + 1, is__p_variant);
3218-
}
3219-
}
3220-
if(
3221-
!is__p_variant &&
3222-
(result.type().id() != ID_pointer ||
3223-
!is_signed_or_unsigned_bitvector(result.type().subtype())))
3210+
typecheck_function_call_arguments(expr);
3211+
3212+
auto lhs = expr.arguments()[0];
3213+
auto rhs = expr.arguments()[1];
3214+
auto result = expr.arguments()[2];
3215+
3216+
const bool is__p_variant = has_suffix(id2string(identifier), "_p");
3217+
3218+
{
3219+
auto const raise_wrong_argument_error =
3220+
[this, identifier](
3221+
const exprt &wrong_argument, std::size_t argument_number, bool _p) {
3222+
std::ostringstream error_message;
3223+
error_message << wrong_argument.source_location().as_string() << ": "
3224+
<< identifier << " has signature " << identifier
3225+
<< "(integral, integral, integral" << (_p ? "" : "*")
3226+
<< "), "
3227+
<< "but argument " << argument_number << " ("
3228+
<< expr2c(wrong_argument, *this) << ") has type `"
3229+
<< type2c(wrong_argument.type(), *this) << '`';
3230+
throw invalid_source_file_exceptiont{error_message.str()};
3231+
};
3232+
for(int arg_index = 0; arg_index <= (!is__p_variant ? 1 : 2); ++arg_index)
3233+
{
3234+
auto const &argument = expr.arguments()[arg_index];
3235+
3236+
if(!is_signed_or_unsigned_bitvector(argument.type()))
32243237
{
3225-
raise_wrong_argument_error(result, 3, is__p_variant);
3238+
raise_wrong_argument_error(argument, arg_index + 1, is__p_variant);
32263239
}
32273240
}
3228-
3229-
irep_idt kind =
3230-
has_prefix(id2string(identifier), "__builtin_add_overflow")
3231-
? ID_plus
3232-
: has_prefix(id2string(identifier), "__builtin_sub_overflow") ? ID_minus
3233-
: ID_mult;
3234-
3235-
return side_effect_expr_overflowt{kind,
3236-
std::move(lhs),
3237-
std::move(rhs),
3238-
std::move(result),
3239-
expr.source_location()};
3241+
if(
3242+
!is__p_variant &&
3243+
(result.type().id() != ID_pointer ||
3244+
!is_signed_or_unsigned_bitvector(result.type().subtype())))
3245+
{
3246+
raise_wrong_argument_error(result, 3, is__p_variant);
3247+
}
32403248
}
3241-
else
3242-
return nil_exprt();
3249+
3250+
return side_effect_expr_overflowt{arith_op,
3251+
std::move(lhs),
3252+
std::move(rhs),
3253+
std::move(result),
3254+
expr.source_location()};
32433255
}
32443256

32453257
/// Typecheck the parameters in a function call expression, and where

0 commit comments

Comments
 (0)