@@ -18,9 +18,11 @@ Author: Daniel Kroening, kroening@kroening.com
1818#include < util/c_types.h>
1919#include < util/config.h>
2020#include < util/cprover_prefix.h>
21+ #include < util/expr_util.h>
2122#include < util/ieee_float.h>
2223#include < util/pointer_offset_size.h>
2324#include < util/pointer_predicates.h>
25+ #include < util/replace_symbol.h>
2426#include < util/simplify_expr.h>
2527#include < util/string_constant.h>
2628
@@ -1918,7 +1920,10 @@ void c_typecheck_baset::typecheck_side_effect_function_call(
19181920 if (entry!=asm_label_map.end ())
19191921 identifier=entry->second ;
19201922
1921- if (symbol_table.symbols .find (identifier)==symbol_table.symbols .end ())
1923+ symbol_tablet::symbolst::const_iterator sym_entry =
1924+ symbol_table.symbols .find (identifier);
1925+
1926+ if (sym_entry == symbol_table.symbols .end ())
19221927 {
19231928 // This is an undeclared function.
19241929 // Is this a builtin?
@@ -1960,6 +1965,87 @@ void c_typecheck_baset::typecheck_side_effect_function_call(
19601965 warning () << " function `" << identifier << " ' is not declared" << eom;
19611966 }
19621967 }
1968+ else if (
1969+ sym_entry->second .type .get_bool (ID_C_inlined) &&
1970+ sym_entry->second .is_macro && sym_entry->second .value .is_not_nil ())
1971+ {
1972+ // calling a function marked as always_inline
1973+ const symbolt &func_sym = sym_entry->second ;
1974+ const code_typet &func_type = to_code_type (func_sym.type );
1975+
1976+ replace_symbolt replace;
1977+
1978+ const code_typet::parameterst ¶meters = func_type.parameters ();
1979+ auto p_it = parameters.begin ();
1980+ for (const auto &arg : expr.arguments ())
1981+ {
1982+ if (p_it == parameters.end ())
1983+ {
1984+ // we don't support varargs with always_inline
1985+ err_location (f_op);
1986+ error () << " function call has additional arguments, "
1987+ << " cannot apply always_inline" << eom;
1988+ throw 0 ;
1989+ }
1990+
1991+ irep_idt p_id = p_it->get_identifier ();
1992+ if (p_id.empty ())
1993+ {
1994+ p_id = id2string (func_sym.base_name ) + " ::" +
1995+ id2string (p_it->get_base_name ());
1996+ }
1997+ replace.insert (p_id, arg);
1998+
1999+ ++p_it;
2000+ }
2001+
2002+ if (p_it != parameters.end ())
2003+ {
2004+ err_location (f_op);
2005+ error () << " function call has missing arguments, "
2006+ << " cannot apply always_inline" << eom;
2007+ throw 0 ;
2008+ }
2009+
2010+ codet body = to_code (func_sym.value );
2011+ replace (body);
2012+
2013+ side_effect_exprt side_effect_expr (
2014+ ID_statement_expression, func_type.return_type ());
2015+ body.make_block ();
2016+
2017+ // simulates parts of typecheck_function_body
2018+ typet cur_return_type = return_type;
2019+ return_type = func_type.return_type ();
2020+ typecheck_code (body);
2021+ return_type.swap (cur_return_type);
2022+
2023+ // replace final return by an ID_expression
2024+ codet &last = to_code_block (body).find_last_statement ();
2025+
2026+ if (last.get_statement () == ID_return)
2027+ last.set_statement (ID_expression);
2028+
2029+ // NOLINTNEXTLINE(whitespace/braces)
2030+ const bool has_returns = has_subexpr (body, [&](const exprt &e) {
2031+ return e.id () == ID_code && to_code (e).get_statement () == ID_return;
2032+ });
2033+ if (has_returns)
2034+ {
2035+ // we don't support multiple return statements with always_inline
2036+ err_location (last);
2037+ error () << " function has multiple return statements, "
2038+ << " cannot apply always_inline" << eom;
2039+ throw 0 ;
2040+ }
2041+
2042+ side_effect_expr.copy_to_operands (body);
2043+ typecheck_side_effect_statement_expression (side_effect_expr);
2044+
2045+ expr.swap (side_effect_expr);
2046+
2047+ return ;
2048+ }
19632049 }
19642050
19652051 // typecheck it now
0 commit comments