in checker/src/z3_solver.rs [1380:1487]
fn numeric_cast(
&self,
expression: &Expression,
target_type: ExpressionType,
) -> (bool, z3_sys::Z3_ast) {
unsafe {
let path_symbol = self.get_symbol_for(expression);
match target_type {
ExpressionType::F32 => (
true,
z3_sys::Z3_mk_const(self.z3_context, path_symbol, self.f32_sort),
),
ExpressionType::F64 => (
true,
z3_sys::Z3_mk_const(self.z3_context, path_symbol, self.f64_sort),
),
_ => {
if target_type.is_integer() || target_type == ExpressionType::Char {
let exp_type = expression.infer_type();
if exp_type == target_type {
self.get_as_numeric_z3_ast(expression)
} else if exp_type.is_signed_integer() {
// In order to (re-interpret) cast the expr value to unsigned, or
// just to safely truncate it, we need to compute the 2's complement.
let expr_ast = self.get_as_numeric_z3_ast(expression).1;
let modulo_constant = target_type.as_unsigned().modulo_constant();
let modulo_ast = if modulo_constant.is_bottom() {
let num_str = "340282366920938463463374607431768211456";
let c_string = CString::new(num_str).unwrap();
z3_sys::Z3_mk_numeral(
self.z3_context,
c_string.into_raw(),
self.int_sort,
)
} else {
self.get_constant_as_ast(&modulo_constant)
};
let args = vec![expr_ast, modulo_ast];
let complement = z3_sys::Z3_mk_add(self.z3_context, 2, args.as_ptr());
let is_negative =
z3_sys::Z3_mk_lt(self.z3_context, expr_ast, self.zero);
let mut unsigned_ast = z3_sys::Z3_mk_ite(
self.z3_context,
is_negative,
complement,
expr_ast,
);
// Truncate the complement by taking its unsigned remainder, if need be
if target_type.bit_length() < exp_type.bit_length() {
unsigned_ast =
z3_sys::Z3_mk_rem(self.z3_context, unsigned_ast, modulo_ast);
}
self.transmute_to_signed_if_necessary(
target_type,
modulo_ast,
unsigned_ast,
)
} else if exp_type.is_unsigned_integer() || exp_type == ExpressionType::Char
{
let mut unsigned_ast = self.get_as_numeric_z3_ast(expression).1;
let modulo_constant = target_type.as_unsigned().modulo_constant();
let modulo_ast = if modulo_constant.is_bottom() {
let num_str = "340282366920938463463374607431768211456";
let c_string = CString::new(num_str).unwrap();
z3_sys::Z3_mk_numeral(
self.z3_context,
c_string.into_raw(),
self.int_sort,
)
} else {
self.get_constant_as_ast(&modulo_constant)
};
// Truncate the expression value if need be
if target_type.bit_length() < exp_type.bit_length() {
unsigned_ast =
z3_sys::Z3_mk_rem(self.z3_context, unsigned_ast, modulo_ast);
}
self.transmute_to_signed_if_necessary(
target_type,
modulo_ast,
unsigned_ast,
)
} else {
// Could be a thin pointer or an enum
(
false,
z3_sys::Z3_mk_const(self.z3_context, path_symbol, self.int_sort),
)
}
} else {
if target_type != ExpressionType::ThinPointer {
// target type is not numeric and not a pointer, but the result of the
// cast is expected to be numeric. This probably a mistake.
info!(
"non numeric cast to {:?} found in numeric context {:?}",
target_type, expression
);
}
self.get_as_numeric_z3_ast(expression)
}
}
}
}
}