diff --git a/libcc1/connection.cc b/libcc1/connection.cc index 66d57391108..45560b9b790 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 cbc54ee0a04..febadc8420b 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; + = cc1_plugin::invoker::invoke; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("address_oracle", fun); } diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc index d6951ab1a4d..4d6a3a11ee2 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; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ 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; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc index d22d9dc6af8..a9334983390 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; + = cc1_plugin::invoker::invoke; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("address_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("enter_scope", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("leave_scope", fun); } diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index 64cde651139..79694b91964 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; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ 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; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh index 09cd7bdda61..8e43fa146dc 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::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 - status - callback (connection *conn) + // The base case -- just return OK. + template + typename std::enable_if::type + unmarshall (connection *, std::tuple &) { - R result; - - if (!unmarshall_check (conn, 0)) - return FAIL; - result = func (conn); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return OK; } - template - status - callback (connection *conn) + // Unmarshall this argument, then unmarshall all subsequent args. + template + typename std::enable_if::type + unmarshall (connection *conn, std::tuple &value) { - argument_wrapper arg; - R result; - - if (!unmarshall_check (conn, 1)) + if (!std::get (value).unmarshall (conn)) return FAIL; - if (!arg.unmarshall (conn)) - return FAIL; - result = func (conn, arg); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return unmarshall (conn, value); } - template - 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 + class invoker { - argument_wrapper arg1; - argument_wrapper arg2; - R result; + // Base case -- we can call the function. + template + static typename std::enable_if::type + call (connection *conn, const std::tuple...> &, + T... args) + { + return func (conn, args...); + } - if (!unmarshall_check (conn, 2)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + // Unpack one argument and continue the recursion. + template + static typename std::enable_if::type + call (connection *conn, const std::tuple...> &value, + T... args) + { + return call (conn, value, args..., + std::get (value).get ()); + } - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - R result; + public: - 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); - } + // A callback function that reads arguments from the connection, + // calls the wrapped function, and then sends the result back on + // the connection. + template + static status + invoke (connection *conn) + { + if (!unmarshall_check (conn, sizeof... (Arg))) + return FAIL; + std::tuple...> wrapped; + if (!unmarshall<0> (conn, wrapped)) + return FAIL; - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - R result; + R result = call<0, func> (conn, wrapped); - 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); - } - - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - argument_wrapper 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); - } - - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - argument_wrapper arg5; - argument_wrapper arg6; - argument_wrapper 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