|
25 | 25 | #include <util/string_constant.h> |
26 | 26 | #include <util/pointer_offset_size.h> |
27 | 27 | #include <util/pointer_predicates.h> |
| 28 | +#include <util/replace_symbol.h> |
28 | 29 |
|
29 | 30 | #include "builtin_factory.h" |
30 | 31 | #include "c_typecast.h" |
@@ -1912,7 +1913,10 @@ void c_typecheck_baset::typecheck_side_effect_function_call( |
1912 | 1913 | if(entry!=asm_label_map.end()) |
1913 | 1914 | identifier=entry->second; |
1914 | 1915 |
|
1915 | | - if(symbol_table.symbols.find(identifier)==symbol_table.symbols.end()) |
| 1916 | + symbol_tablet::symbolst::const_iterator sym_entry = |
| 1917 | + symbol_table.symbols.find(identifier); |
| 1918 | + |
| 1919 | + if(sym_entry == symbol_table.symbols.end()) |
1916 | 1920 | { |
1917 | 1921 | // This is an undeclared function. |
1918 | 1922 | // Is this a builtin? |
@@ -1954,6 +1958,87 @@ void c_typecheck_baset::typecheck_side_effect_function_call( |
1954 | 1958 | warning() << "function `" << identifier << "' is not declared" << eom; |
1955 | 1959 | } |
1956 | 1960 | } |
| 1961 | + else if( |
| 1962 | + sym_entry->second.type.get_bool(ID_C_inlined) && |
| 1963 | + sym_entry->second.is_macro && sym_entry->second.value.is_not_nil()) |
| 1964 | + { |
| 1965 | + // calling a function marked as always_inline |
| 1966 | + const symbolt &func_sym = sym_entry->second; |
| 1967 | + const code_typet &func_type = to_code_type(func_sym.type); |
| 1968 | + |
| 1969 | + replace_symbolt replace; |
| 1970 | + |
| 1971 | + const code_typet::parameterst ¶meters = func_type.parameters(); |
| 1972 | + auto p_it = parameters.begin(); |
| 1973 | + for(const auto &arg : expr.arguments()) |
| 1974 | + { |
| 1975 | + if(p_it == parameters.end()) |
| 1976 | + { |
| 1977 | + // we don't support varargs with always_inline |
| 1978 | + err_location(f_op); |
| 1979 | + error() << "function call has additional arguments, " |
| 1980 | + << "cannot apply always_inline" << eom; |
| 1981 | + throw 0; |
| 1982 | + } |
| 1983 | + |
| 1984 | + irep_idt p_id = p_it->get_identifier(); |
| 1985 | + if(p_id.empty()) |
| 1986 | + { |
| 1987 | + p_id = id2string(func_sym.base_name) + "::" + |
| 1988 | + id2string(p_it->get_base_name()); |
| 1989 | + } |
| 1990 | + replace.insert(p_id, arg); |
| 1991 | + |
| 1992 | + ++p_it; |
| 1993 | + } |
| 1994 | + |
| 1995 | + if(p_it != parameters.end()) |
| 1996 | + { |
| 1997 | + err_location(f_op); |
| 1998 | + error() << "function call has missing arguments, " |
| 1999 | + << "cannot apply always_inline" << eom; |
| 2000 | + throw 0; |
| 2001 | + } |
| 2002 | + |
| 2003 | + codet body = to_code(func_sym.value); |
| 2004 | + replace(body); |
| 2005 | + |
| 2006 | + side_effect_exprt side_effect_expr( |
| 2007 | + ID_statement_expression, func_type.return_type()); |
| 2008 | + body.make_block(); |
| 2009 | + |
| 2010 | + // simulates parts of typecheck_function_body |
| 2011 | + typet cur_return_type = return_type; |
| 2012 | + return_type = func_type.return_type(); |
| 2013 | + typecheck_code(body); |
| 2014 | + return_type.swap(cur_return_type); |
| 2015 | + |
| 2016 | + // replace final return by an ID_expression |
| 2017 | + codet &last = to_code_block(body).find_last_statement(); |
| 2018 | + |
| 2019 | + if(last.get_statement() == ID_return) |
| 2020 | + last.set_statement(ID_expression); |
| 2021 | + |
| 2022 | + // NOLINTNEXTLINE(whitespace/braces) |
| 2023 | + const bool has_returns = has_subexpr(body, [&](const exprt &e) { |
| 2024 | + return e.id() == ID_code && to_code(e).get_statement() == ID_return; |
| 2025 | + }); |
| 2026 | + if(has_returns) |
| 2027 | + { |
| 2028 | + // we don't support multiple return statements with always_inline |
| 2029 | + err_location(last); |
| 2030 | + error() << "function has multiple return statements, " |
| 2031 | + << "cannot apply always_inline" << eom; |
| 2032 | + throw 0; |
| 2033 | + } |
| 2034 | + |
| 2035 | + side_effect_expr.copy_to_operands(body); |
| 2036 | + typecheck_side_effect_statement_expression(side_effect_expr); |
| 2037 | + |
| 2038 | + expr.swap(side_effect_expr); |
| 2039 | + |
| 2040 | + return; |
| 2041 | + } |
1957 | 2042 | } |
1958 | 2043 |
|
1959 | 2044 | // typecheck it now |
|
0 commit comments