diff --git a/src/command_func.h b/src/command_func.h --- a/src/command_func.h +++ b/src/command_func.h @@ -78,6 +78,20 @@ private: static int _counter; }; +#if defined(__GNUC__) && !defined(__clang__) +/* + * We cast specialized function pointers to a generic one, but don't use the + * converted value to call the function, which is safe, except that GCC + * helpfully thinks it is not. + * + * "Any pointer to function can be converted to a pointer to a different function type. + * Calling the function through a pointer to a different function type is undefined, + * but converting such pointer back to pointer to the original function type yields + * the pointer to the original function." */ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-function-type" +# define SILENCE_GCC_FUNCTION_POINTER_CAST +#endif template struct CommandHelper; @@ -148,18 +162,19 @@ public: * @param err_message Message prefix to show on error * @param args Parameters for the command */ - static inline bool Post(StringID err_message, Targs... args) { return Post(err_message, nullptr, std::forward(args)...); } + static inline bool Post(StringID err_message, Targs... args) { return Post(err_message, nullptr, std::forward(args)...); } /** * Shortcut for the long Post when not using an error message. * @param callback A callback function to call after the command is finished * @param args Parameters for the command */ - static inline bool Post(CommandCallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward(args)...); } + template + static inline bool Post(Tcallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward(args)...); } /** * Shortcut for the long Post when not using a callback or an error message. * @param args Parameters for the command */ - static inline bool Post(Targs... args) { return Post((StringID)0, nullptr, std::forward(args)...); } + static inline bool Post(Targs... args) { return Post((StringID)0, nullptr, std::forward(args)...); } /** * Top-level network safe command execution for the current company. @@ -171,7 +186,8 @@ public: * @param args Parameters for the command * @return \c true if the command succeeded, else \c false. */ - static bool Post(StringID err_message, CommandCallback *callback, Targs... args) + template + static bool Post(StringID err_message, Tcallback *callback, Targs... args) { return InternalPost(err_message, callback, true, false, std::forward_as_tuple(args...)); } @@ -185,7 +201,8 @@ public: * @param args Parameters for the command * @return \c true if the command succeeded, else \c false. */ - static bool PostFromNet(StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex location, std::tuple args) + template + static bool PostFromNet(StringID err_message, Tcallback *callback, bool my_cmd, TileIndex location, std::tuple args) { return InternalPost(err_message, callback, my_cmd, true, location, std::move(args)); } @@ -194,11 +211,10 @@ public: * Prepare a command to be send over the network * @param cmd The command to execute (a CMD_* value) * @param err_message Message prefix to show on error - * @param callback A callback function to call after the command is finished * @param company The company that wants to send the command * @param args Parameters for the command */ - static void SendNet(StringID err_message, CommandCallback *callback, CompanyID company, Targs... args) + static void SendNet(StringID err_message, CompanyID company, Targs... args) { auto args_tuple = std::forward_as_tuple(args...); @@ -207,7 +223,7 @@ public: tile = std::get<0>(args_tuple); } - ::NetworkSendCommand(Tcmd, err_message, callback, _current_company, tile, EndianBufferWriter::FromValue(args_tuple)); + ::NetworkSendCommand(Tcmd, err_message, nullptr, _current_company, tile, EndianBufferWriter::FromValue(args_tuple)); } /** @@ -220,9 +236,10 @@ public: * @param args Parameters for the command * @return the command cost of this function. */ - static CommandCost Unsafe(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple args) + template + static CommandCost Unsafe(StringID err_message, Tcallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple args) { - return Execute(err_message, callback, my_cmd, estimate_only, false, location, std::move(args)); + return Execute(err_message, reinterpret_cast(callback), my_cmd, estimate_only, false, location, std::move(args)); } protected: @@ -242,7 +259,8 @@ protected: ((SetClientIdHelper(std::get(values))), ...); } - static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple args) + template + static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, std::tuple args) { /* Where to show the message? */ TileIndex tile{}; @@ -253,7 +271,8 @@ protected: return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args)); } - static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple args) + template + static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple args) { auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags(), tile, err_message, network_command); if (err) return false; @@ -261,7 +280,7 @@ protected: /* Only set client IDs when the command does not come from the network. */ if (!network_command && GetCommandFlags() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for{}); - CommandCost res = Execute(err_message, callback, my_cmd, estimate_only, network_command, tile, args); + CommandCost res = Execute(err_message, reinterpret_cast(callback), my_cmd, estimate_only, network_command, tile, args); InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd); if (!estimate_only && !only_sending && callback != nullptr) { @@ -360,20 +379,21 @@ struct CommandHelper(args)...); } + static inline bool Post(StringID err_message, TileIndex location, Targs... args) { return Post(err_message, nullptr, location, std::forward(args)...); } /** * Shortcut for Post when not using a callback. * @param callback A callback function to call after the command is finished * @param location Tile location for user feedback. * @param args Parameters for the command */ - static inline bool Post(CommandCallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward(args)...); } + template + static inline bool Post(Tcallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward(args)...); } /** * Shortcut for Post when not using a callback or an error message. * @param location Tile location for user feedback. * @param args Parameters for the command* */ - static inline bool Post(TileIndex location, Targs... args) { return Post((StringID)0, nullptr, location, std::forward(args)...); } + static inline bool Post(TileIndex location, Targs... args) { return Post((StringID)0, nullptr, location, std::forward(args)...); } /** * Post variant that takes a TileIndex (for error window location and text effects) for @@ -384,12 +404,16 @@ struct CommandHelper + static inline bool Post(StringID err_message, Tcallback *callback, TileIndex location, Targs... args) { return CommandHelper::InternalPost(err_message, callback, true, false, location, std::forward_as_tuple(args...)); } }; +#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST +# pragma GCC diagnostic pop +#endif template using Command = CommandHelper::ProcType, std::is_same_v::Args>>>;