summaryrefslogtreecommitdiff
path: root/libcc1
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2021-05-04 15:26:58 -0600
committerTom Tromey <tom@tromey.com>2021-05-05 00:06:18 -0600
commit8fdffa48c57f13b90556bc179150d24efdeeeef5 (patch)
tree6b946a1fe949ce299c120d384e8d844eeab0ad87 /libcc1
parentee75ca6b72e4235aa48d6fb30c5cd274f2ff6b67 (diff)
libcc1: use variadic templates for callbacks
This patch completes the transition of libcc1 from the use of separate template functions for different arities to the use of variadic functions. This is how I had wanted it to work from the very beginning, and is possible now with C++11. I had thought that variadic callbacks required C++17, but it turns out that the approach taken here is basically equivalent to std::apply -- just a bit wordier. libcc1 * rpc.hh (argument_wrapper) <get>: Replace cast operator. (argument_wrapper<T *>) <get>: Likewise. (unmarshall): Add std::tuple overloads. (callback): Remove. (class invoker): New. * libcp1plugin.cc (plugin_init): Update. * libcp1.cc (libcp1::add_callbacks): Update. * libcc1plugin.cc (plugin_init): Update. * libcc1.cc (libcc1::add_callbacks): Update. * connection.cc (cc1_plugin::connection::do_wait): Update.
Diffstat (limited to 'libcc1')
-rw-r--r--libcc1/connection.cc2
-rw-r--r--libcc1/libcc1.cc12
-rw-r--r--libcc1/libcc1plugin.cc20
-rw-r--r--libcc1/libcp1.cc17
-rw-r--r--libcc1/libcp1plugin.cc20
-rw-r--r--libcc1/rpc.hh219
6 files changed, 88 insertions, 202 deletions
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<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 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<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 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<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 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<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 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<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