diff --git a/libcc1/connection.cc b/libcc1/connection.cc index 66d573911080cfdd25b844ce62d9caa876236f32..45560b9b790eea22e46d0e6d4272066c93d5bcd6 100644 --- a/libcc1/connection.cc +++ b/libcc1/connection.cc @@ -129,7 +129,7 @@ cc1_plugin::connection::do_wait (bool want_result) return FAIL; callback_ftype *callback - = m_callbacks.find_callback (method_name); + = m_callbacks.find_callback (method_name.get ()); // The call to CALLBACK is where we may end up in a // reentrant call. if (callback == NULL || !callback (this)) diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index cbc54ee0a0444950444aee3fbcadbdcf322c9918..febadc8420b0a420d5491f8b53c0655f6da7598a 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -143,15 +143,13 @@ void libcc1::add_callbacks () { cc1_plugin::callback_ftype *fun - = cc1_plugin::callback<int, - enum gcc_c_oracle_request, - const char *, - c_call_binding_oracle>; + = cc1_plugin::invoker<int, + enum gcc_c_oracle_request, + const char *>::invoke<c_call_binding_oracle>; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback<gcc_address, - const char *, - c_call_symbol_address>; + fun = cc1_plugin::invoker<gcc_address, + const char *>::invoke<c_call_symbol_address>; connection->add_callback ("address_oracle", fun); } diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc index d6951ab1a4d2047d5c71960c51568d66064437ae..4d6a3a11ee221268ea20c0fa26fe2f7fe96f9bbd 100644 --- a/libcc1/libcc1plugin.cc +++ b/libcc1/libcc1plugin.cc @@ -762,46 +762,46 @@ plugin_init (struct plugin_name_args *plugin_info, #define GCC_METHOD0(R, N) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, plugin_ ## N>; \ + = cc1_plugin::invoker<R>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, \ + D>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, E, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, D, \ + E>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, E, F, G, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, D, \ + E, F, G>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc index d22d9dc6af8c51c1825f91c3764e2148e06315e8..a93349833901a55d6322df77a58e03fb3f61d0d9 100644 --- a/libcc1/libcp1.cc +++ b/libcc1/libcp1.cc @@ -166,23 +166,18 @@ void libcp1::add_callbacks () { cc1_plugin::callback_ftype *fun - = cc1_plugin::callback<int, - enum gcc_cp_oracle_request, - const char *, - cp_call_binding_oracle>; + = cc1_plugin::invoker<int, enum gcc_cp_oracle_request, + const char *>::invoke<cp_call_binding_oracle>; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback<gcc_address, - const char *, - cp_call_symbol_address>; + fun = cc1_plugin::invoker<gcc_address, + const char *>::invoke<cp_call_symbol_address>; connection->add_callback ("address_oracle", fun); - fun = cc1_plugin::callback<int, - cp_call_enter_scope>; + fun = cc1_plugin::invoker<int>::invoke<cp_call_enter_scope>; connection->add_callback ("enter_scope", fun); - fun = cc1_plugin::callback<int, - cp_call_leave_scope>; + fun = cc1_plugin::invoker<int>::invoke<cp_call_leave_scope>; connection->add_callback ("leave_scope", fun); } diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index 64cde651139cac6b253e2b4df1d84cf99f77f5c1..79694b9196411ab71a8ad5934c12b2e6a1b7c4ac 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -3509,46 +3509,46 @@ plugin_init (struct plugin_name_args *plugin_info, #define GCC_METHOD0(R, N) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, plugin_ ## N>; \ + = cc1_plugin::invoker<R>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, \ + D>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, E, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, \ + D, E>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback<R, A, B, C, D, E, F, G, \ - plugin_ ## N>; \ + = cc1_plugin::invoker<R, A, B, C, \ + D, E, F, G>::invoke<plugin_ ## N>; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh index 09cd7bdda616013ea1cbc44560bb245c4ab68034..8e43fa146dcc8c7fff28db0804550f6182faf9aa 100644 --- a/libcc1/rpc.hh +++ b/libcc1/rpc.hh @@ -43,7 +43,7 @@ namespace cc1_plugin argument_wrapper (const argument_wrapper &) = delete; argument_wrapper &operator= (const argument_wrapper &) = delete; - operator T () const { return m_object; } + T get () const { return m_object; } status unmarshall (connection *conn) { @@ -68,7 +68,7 @@ namespace cc1_plugin typedef typename std::remove_const<T>::type type; - operator const type * () const + const type *get () const { return m_object.get (); } @@ -88,17 +88,14 @@ namespace cc1_plugin }; // There are two kinds of template functions here: "call" and - // "callback". "call" is implemented with variadic templates, but - // "callback" is repeated multiple times to handle different numbers - // of arguments. (This could be improved with C++17 and - // std::apply.) + // "invoker". // The "call" template is used for making a remote procedure call. // It starts a query ('Q') packet, marshalls its arguments, waits // for a result, and finally reads and returns the result via an // "out" parameter. - // The "callback" template is used when receiving a remote procedure + // The "invoker" template is used when receiving a remote procedure // call. This template function is suitable for use with the // "callbacks" and "connection" classes. It decodes incoming // arguments, passes them to the wrapped function, and finally @@ -123,175 +120,71 @@ namespace cc1_plugin return OK; } - template<typename R, R (*func) (connection *)> - status - callback (connection *conn) + // The base case -- just return OK. + template<int I, typename... T> + typename std::enable_if<I == sizeof... (T), status>::type + unmarshall (connection *, std::tuple<T...> &) { - R result; - - if (!unmarshall_check (conn, 0)) - return FAIL; - result = func (conn); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } - - template<typename R, typename A, R (*func) (connection *, A)> - status - callback (connection *conn) - { - argument_wrapper<A> arg; - R result; - - if (!unmarshall_check (conn, 1)) - return FAIL; - if (!arg.unmarshall (conn)) - return FAIL; - result = func (conn, arg); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return OK; } - template<typename R, typename A1, typename A2, R (*func) (connection *, - A1, A2)> - status - callback (connection *conn) + // Unmarshall this argument, then unmarshall all subsequent args. + template<int I, typename... T> + typename std::enable_if<I < sizeof... (T), status>::type + unmarshall (connection *conn, std::tuple<T...> &value) { - argument_wrapper<A1> arg1; - argument_wrapper<A2> arg2; - R result; - - if (!unmarshall_check (conn, 2)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) + if (!std::get<I> (value).unmarshall (conn)) return FAIL; - result = func (conn, arg1, arg2); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return unmarshall<I + 1, T...> (conn, value); } - template<typename R, typename A1, typename A2, typename A3, - R (*func) (connection *, A1, A2, A3)> - status - callback (connection *conn) + // Wrap a static function that is suitable for use as a callback. + // This is a template function inside a template class to work + // around limitations with multiple variadic packs. + template<typename R, typename... Arg> + class invoker { - argument_wrapper<A1> arg1; - argument_wrapper<A2> arg2; - argument_wrapper<A3> arg3; - R result; + // Base case -- we can call the function. + template<int I, R func (connection *, Arg...), typename... T> + static typename std::enable_if<I == sizeof... (Arg), R>::type + call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &, + T... args) + { + return func (conn, args...); + } - if (!unmarshall_check (conn, 3)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + // Unpack one argument and continue the recursion. + template<int I, R func (connection *, Arg...), typename... T> + static typename std::enable_if<I < sizeof... (Arg), R>::type + call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value, + T... args) + { + return call<I + 1, func> (conn, value, args..., + std::get<I> (value).get ()); + } - template<typename R, typename A1, typename A2, typename A3, typename A4, - R (*func) (connection *, A1, A2, A3, A4)> - status - callback (connection *conn) - { - argument_wrapper<A1> arg1; - argument_wrapper<A2> arg2; - argument_wrapper<A3> arg3; - argument_wrapper<A4> arg4; - R result; + public: - if (!unmarshall_check (conn, 4)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + // A callback function that reads arguments from the connection, + // calls the wrapped function, and then sends the result back on + // the connection. + template<R func (connection *, Arg...)> + static status + invoke (connection *conn) + { + if (!unmarshall_check (conn, sizeof... (Arg))) + return FAIL; + std::tuple<argument_wrapper<Arg>...> wrapped; + if (!unmarshall<0> (conn, wrapped)) + return FAIL; - template<typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)> - status - callback (connection *conn) - { - argument_wrapper<A1> arg1; - argument_wrapper<A2> arg2; - argument_wrapper<A3> arg3; - argument_wrapper<A4> arg4; - argument_wrapper<A5> arg5; - R result; - - if (!unmarshall_check (conn, 5)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - if (!arg5.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4, arg5); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + R result = call<0, func> (conn, wrapped); - template<typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6, typename A7, - R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)> - status - callback (connection *conn) - { - argument_wrapper<A1> arg1; - argument_wrapper<A2> arg2; - argument_wrapper<A3> arg3; - argument_wrapper<A4> arg4; - argument_wrapper<A5> arg5; - argument_wrapper<A6> arg6; - argument_wrapper<A7> arg7; - R result; - - if (!unmarshall_check (conn, 7)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - if (!arg5.unmarshall (conn)) - return FAIL; - if (!arg6.unmarshall (conn)) - return FAIL; - if (!arg7.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + if (!conn->send ('R')) + return FAIL; + return marshall (conn, result); + } + }; }; #endif // CC1_PLUGIN_RPC_HH