[api] Use custom deleter to fix incomplete-type error on macOS libc++

libc++ eagerly instantiates the unique_ptr<APIConnection> destructor
when std::array<std::unique_ptr<APIConnection>, N> is parsed, requiring
sizeof(APIConnection). api_server.h only forward-declares APIConnection
(via list_entities.h), so the destructor instantiation fails for any
translation unit that includes api_server.h without also including
api_connection.h first.

Wrap the unique_ptr in a custom deleter (APIConnectionDeleter) whose
operator() is defined out-of-line in api_server.cpp where APIConnection
is complete. The default_delete<APIConnection> path is never
instantiated, so libc++'s incomplete-type assertion is avoided.

GCC/libstdc++ already deferred this instantiation, so this only affects
macOS host-platform builds (used by integration tests).
This commit is contained in:
J. Nick Koston
2026-04-27 05:59:21 -05:00
parent 79b741b8dc
commit acc15ff495
2 changed files with 13 additions and 2 deletions
+5
View File
@@ -30,6 +30,11 @@ APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-c
APIServer::APIServer() { global_api_server = this; }
// Custom deleter defined here so `delete` sees the complete APIConnection type.
// This prevents libc++ from emitting an "incomplete type" error when other
// translation units only have the forward declaration of APIConnection.
void APIServer::APIConnectionDeleter::operator()(APIConnection *p) const { delete p; }
void APIServer::socket_failed_(const LogString *msg) {
ESP_LOGW(TAG, "Socket %s: errno %d", LOG_STR_ARG(msg), errno);
this->destroy_socket_();
+8 -2
View File
@@ -193,7 +193,13 @@ class APIServer final : public Component,
// Range-for view over the populated slice [0, api_connection_count_). Read-only with respect
// to ownership — callers get `const unique_ptr&` so they can invoke non-const methods on the
// APIConnection but cannot reset/move the slot and break the count invariant.
using APIConnectionPtr = std::unique_ptr<APIConnection>;
// Custom deleter is defined out-of-line in api_server.cpp so libc++ does not
// eagerly instantiate `delete static_cast<APIConnection *>(p)` here, where
// only the forward declaration of APIConnection is visible (incomplete type).
struct APIConnectionDeleter {
void operator()(APIConnection *p) const;
};
using APIConnectionPtr = std::unique_ptr<APIConnection, APIConnectionDeleter>;
class ActiveClientsView {
const APIConnectionPtr *begin_;
const APIConnectionPtr *end_;
@@ -292,7 +298,7 @@ class APIServer final : public Component,
uint32_t last_connected_{0};
// Slots [0, api_connection_count_) are populated; trailing slots are always nullptr.
std::array<std::unique_ptr<APIConnection>, MAX_API_CONNECTIONS> clients_{};
std::array<APIConnectionPtr, MAX_API_CONNECTIONS> clients_{};
// Vectors and strings (12 bytes each on 32-bit)
// Shared proto write buffer for all connections.
// Not pre-allocated: all send paths call prepare_first_message_buffer() which