Clang tells me there is no viable conversion from the return value of boost::beast::http::async_write
with completion token boost::asio::as_tuple(boost::asio::deferred)
to awaitable<tuple<boost::system::error_code, unsigned long>>
:
error: no viable conversion from returned value of type 'decltype(enable_if_t<enable_if_t<detail::are_completion_signatures<void (error_code, unsigned long)>::value, detail::async_result_has_initiate_memfn<as_tuple_t<deferred_t>, void (error_code, unsigned long)>>::value, async_result<decay_t<as_tuple_t<deferred_t>>, void (error_code, unsigned long)>>::initiate(static_cast<boost::beast::http::detail::run_write_msg_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp>> &&>(initiation), static_cast<boost::asio::as_tuple_t<boost::asio::deferred_t> &&>(token), static_cast<const boost::beast::http::message<false, boost::beast::http::basic_string_body<char>> *&&>(args), static_cast<std::integral_constant<bool, true> &&>(args)))' (aka 'deferred_async_operation<void (std::tuple<boost::system::error_code, unsigned long>), boost::asio::async_result<boost::asio::as_tuple_t<boost::asio::deferred_t>, void (boost::system::error_code, unsigned long)>::init_wrapper<boost::beast::http::detail::run_write_msg_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>>>, const boost::beast::http::message<false, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char>>, boost::beast::http::basic_fields<std::allocator<char>>> *, std::integral_constant<bool, true>>') to function return type 'boost::asio::awaitable<std::tuple<boost::system::error_code, std::size_t>>' (aka 'awaitable<tuple<boost::system::error_code, unsigned long>>')
179 |return boost::beast::http::async_write(stream, typed_message, boost::asio::as_tuple(boost::asio::deferred));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The function in question looks like this:
template<typename stream_t>
boost::asio::awaitable<void> response_worker(boost::asio::experimental::channel<void(boost::system::error_code, http_response_t)> &channel, stream_t &stream)
{
while (true) {
boost::system::error_code ec;
std::variant<
boost::beast::http::response<boost::beast::http::string_body>,
boost::beast::http::response<boost::beast::http::empty_body>,
boost::beast::http::response<boost::beast::http::dynamic_body>,
boost::beast::http::response<boost::beast::http::file_body>,
boost::beast::http::response<boost::beast::http::buffer_body>>
message = co_await channel.async_receive(boost::asio::redirect_error(boost::asio::deferred, ec));
if (ec == boost::asio::error::eof) {
channel.close();
co_return;
}
const auto [ec2, transferred] = co_await std::visit(
[&stream](auto &typed_message) -> boost::asio::awaitable<std::tuple<boost::system::error_code, std::size_t>> {
return boost::beast::http::async_write(stream, typed_message, boost::asio::as_tuple(boost::asio::deferred));
},
message);
//error handling
}
}
This used to compile and I'm incredibly confused by the error message, is there an error in my code or is my clang installation even more broken than I thought (libclang does not get the header search correct means I have to add -I/usr/lib/clang/19/include
as a compiler flag if I understand it right)?
Turns out this was a compiler bug in the version of Clang I was using.
You can see in this godbolt example how the minimally reproducible example compiles in Clang 20.1.0 but not Clang 19.1.10.
The issue was caused by having the code contained in a template inside a module.
File CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(
experiments
VERSION 0.0.0
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
add_executable(TEST
main.cpp)
target_sources(TEST PUBLIC FILE_SET CXX_MODULES FILES
test.cppm)
File test.cppm
//test.cppm
module;
#include <boost/beast.hpp>
export module test;
export namespace test {
template<typename arg_t>
void run(arg_t &&arg)
{
using http_response_t = std::variant<
boost::beast::http::response<boost::beast::http::empty_body>,
boost::beast::http::response<boost::beast::http::string_body>,
boost::beast::http::response<boost::beast::http::dynamic_body>,
boost::beast::http::response<boost::beast::http::file_body>,
boost::beast::http::response<boost::beast::http::buffer_body>>;
(void) arg;
http_response_t resp;
auto message = std::visit(
[]<typename body_t>(boost::beast::http::response<body_t> response) {
return boost::beast::http::message_generator{std::move(response)};
},
std::move(resp));
(void) message;
}
} // namespace test
File main.cpp
//main.cpp
import test;
int main()
{
test::run(5);
}