From 42d3d07427a94bb6322a7a6f7b601e15267623a1 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Tue, 10 Mar 2026 10:30:24 +0200 Subject: [PATCH 1/2] Replace C-style casts with static_cast/reinterpret_cast for -Wold-style-cast compliance Projects using -Wold-style-cast and -Wuseless-cast (common in modern C++ codebases with strict warning policies) cannot compile concurrentqueue without warnings. Changes: - lightweightsemaphore.h: Replace C-style casts with static_cast in timed_wait, waitWithPartialSpinning, waitManyWithPartialSpinning, and signal methods - blockingconcurrentqueue.h: Replace C-style casts with static_cast for sema->signal, sema->waitMany, sema->tryWaitMany, sema->availableApprox calls and constructor MAX_SEMA_SPINS; replace C-style pointer casts in assert with reinterpret_cast - concurrentqueue.h: Suppress -Wuseless-cast around hash_thread_id static_cast that is needed for cross-platform correctness but redundant on 64-bit Tested clean with GCC 14/15, C++17/20/23, using -Wall -Wextra -Wpedantic -Werror -Wold-style-cast -Wuseless-cast -Wconversion -Wsign-conversion and other strict flags. --- blockingconcurrentqueue.h | 30 +++++++++++++++--------------- concurrentqueue.h | 7 +++++++ lightweightsemaphore.h | 10 +++++----- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/blockingconcurrentqueue.h b/blockingconcurrentqueue.h index 205a4db7..c68b0fd8 100644 --- a/blockingconcurrentqueue.h +++ b/blockingconcurrentqueue.h @@ -56,18 +56,18 @@ class BlockingConcurrentQueue // includes making the memory effects of construction visible, possibly with a // memory barrier). explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) - : inner(capacity), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + : inner(capacity), sema(create(0, static_cast(Traits::MAX_SEMA_SPINS)), &BlockingConcurrentQueue::template destroy) { - assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + assert(reinterpret_cast(reinterpret_cast(1)) == &(reinterpret_cast(1))->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); if (!sema) { MOODYCAMEL_THROW(std::bad_alloc()); } } BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) - : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create(0, static_cast(Traits::MAX_SEMA_SPINS)), &BlockingConcurrentQueue::template destroy) { - assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + assert(reinterpret_cast(reinterpret_cast(1)) == &(reinterpret_cast(1))->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); if (!sema) { MOODYCAMEL_THROW(std::bad_alloc()); } @@ -179,7 +179,7 @@ class BlockingConcurrentQueue inline bool enqueue_bulk(It itemFirst, size_t count) { if ((details::likely)(inner.enqueue_bulk(std::forward(itemFirst), count))) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + sema->signal(static_cast(count)); return true; } return false; @@ -195,7 +195,7 @@ class BlockingConcurrentQueue inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { if ((details::likely)(inner.enqueue_bulk(token, std::forward(itemFirst), count))) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + sema->signal(static_cast(count)); return true; } return false; @@ -264,7 +264,7 @@ class BlockingConcurrentQueue inline bool try_enqueue_bulk(It itemFirst, size_t count) { if (inner.try_enqueue_bulk(std::forward(itemFirst), count)) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + sema->signal(static_cast(count)); return true; } return false; @@ -279,7 +279,7 @@ class BlockingConcurrentQueue inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { if (inner.try_enqueue_bulk(token, std::forward(itemFirst), count)) { - sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + sema->signal(static_cast(count)); return true; } return false; @@ -327,7 +327,7 @@ class BlockingConcurrentQueue inline size_t try_dequeue_bulk(It itemFirst, size_t max) { size_t count = 0; - max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + max = static_cast(sema->tryWaitMany(static_cast(max))); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } @@ -343,7 +343,7 @@ class BlockingConcurrentQueue inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) { size_t count = 0; - max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + max = static_cast(sema->tryWaitMany(static_cast(max))); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); } @@ -447,7 +447,7 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk(It itemFirst, size_t max) { size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + max = static_cast(sema->waitMany(static_cast(max))); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } @@ -465,7 +465,7 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) { size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + max = static_cast(sema->waitMany(static_cast(max), timeout_usecs)); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } @@ -492,7 +492,7 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) { size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + max = static_cast(sema->waitMany(static_cast(max))); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); } @@ -510,7 +510,7 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) { size_t count = 0; - max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + max = static_cast(sema->waitMany(static_cast(max), timeout_usecs)); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); } @@ -537,7 +537,7 @@ class BlockingConcurrentQueue // Thread-safe. inline size_t size_approx() const { - return (size_t)sema->availableApprox(); + return static_cast(sema->availableApprox()); } diff --git a/concurrentqueue.h b/concurrentqueue.h index 9d00070f..d65f73c4 100644 --- a/concurrentqueue.h +++ b/concurrentqueue.h @@ -469,8 +469,15 @@ namespace details static inline size_t hash_thread_id(thread_id_t id) { static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuseless-cast" +#endif return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( thread_id_converter::prehash(id))); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif } template diff --git a/lightweightsemaphore.h b/lightweightsemaphore.h index 3ae8100d..c103068f 100644 --- a/lightweightsemaphore.h +++ b/lightweightsemaphore.h @@ -234,8 +234,8 @@ class Semaphore #else clock_gettime(CLOCK_REALTIME, &ts); #endif - ts.tv_sec += (time_t)(usecs / usecs_in_1_sec); - ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000; + ts.tv_sec += static_cast(usecs / usecs_in_1_sec); + ts.tv_nsec += static_cast(usecs % usecs_in_1_sec) * 1000; // sem_timedwait bombs if you have more than 1e9 in tv_nsec // so we have to clean things up before passing it in if (ts.tv_nsec >= nsecs_in_1_sec) { @@ -306,7 +306,7 @@ class LightweightSemaphore if (m_sema.wait()) return true; } - if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs)) + if (timeout_usecs > 0 && m_sema.timed_wait(static_cast(timeout_usecs))) return true; // At this point, we've timed out waiting for the semaphore, but the // count is still decremented indicating we may still be waiting on @@ -342,7 +342,7 @@ class LightweightSemaphore oldCount = m_count.fetch_sub(1, std::memory_order_acquire); if (oldCount <= 0) { - if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs))) + if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait(static_cast(timeout_usecs)))) { while (true) { @@ -425,7 +425,7 @@ class LightweightSemaphore ssize_t toRelease = -oldCount < count ? -oldCount : count; if (toRelease > 0) { - m_sema.signal((int)toRelease); + m_sema.signal(static_cast(toRelease)); } } From 21af27350d82267ea0d49b9e90164e3850213b76 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Sun, 15 Mar 2026 03:20:12 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Preserve=20two-step=20size=5Ft=E2=86=92ssiz?= =?UTF-8?q?e=5Ft=E2=86=92LightweightSemaphore::ssize=5Ft=20cast=20with=20a?= =?UTF-8?q?ssert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address maintainer review: restore the intermediate ssize_t cast that was dropped when converting from C-style casts, and add an explicit assert that the value is non-negative to guard against size differences between BlockingConcurrentQueue::ssize_t and LightweightSemaphore::ssize_t. --- blockingconcurrentqueue.h | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/blockingconcurrentqueue.h b/blockingconcurrentqueue.h index c68b0fd8..d3f09f68 100644 --- a/blockingconcurrentqueue.h +++ b/blockingconcurrentqueue.h @@ -179,12 +179,13 @@ class BlockingConcurrentQueue inline bool enqueue_bulk(It itemFirst, size_t count) { if ((details::likely)(inner.enqueue_bulk(std::forward(itemFirst), count))) { - sema->signal(static_cast(count)); + assert(static_cast(count) >= 0); + sema->signal(static_cast(static_cast(count))); return true; } return false; } - + // Enqueues several items using an explicit producer token. // Allocates memory if required. Only fails if memory allocation fails // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). @@ -195,7 +196,8 @@ class BlockingConcurrentQueue inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { if ((details::likely)(inner.enqueue_bulk(token, std::forward(itemFirst), count))) { - sema->signal(static_cast(count)); + assert(static_cast(count) >= 0); + sema->signal(static_cast(static_cast(count))); return true; } return false; @@ -264,12 +266,13 @@ class BlockingConcurrentQueue inline bool try_enqueue_bulk(It itemFirst, size_t count) { if (inner.try_enqueue_bulk(std::forward(itemFirst), count)) { - sema->signal(static_cast(count)); + assert(static_cast(count) >= 0); + sema->signal(static_cast(static_cast(count))); return true; } return false; } - + // Enqueues several items using an explicit producer token. // Does not allocate memory. Fails if not enough room to enqueue. // Note: Use std::make_move_iterator if the elements should be moved @@ -279,7 +282,8 @@ class BlockingConcurrentQueue inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { if (inner.try_enqueue_bulk(token, std::forward(itemFirst), count)) { - sema->signal(static_cast(count)); + assert(static_cast(count) >= 0); + sema->signal(static_cast(static_cast(count))); return true; } return false; @@ -327,13 +331,14 @@ class BlockingConcurrentQueue inline size_t try_dequeue_bulk(It itemFirst, size_t max) { size_t count = 0; - max = static_cast(sema->tryWaitMany(static_cast(max))); + assert(static_cast(max) >= 0); + max = static_cast(sema->tryWaitMany(static_cast(static_cast(max)))); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } return count; } - + // Attempts to dequeue several elements from the queue using an explicit consumer token. // Returns the number of items actually dequeued. // Returns 0 if all producer streams appeared empty at the time they @@ -343,7 +348,8 @@ class BlockingConcurrentQueue inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) { size_t count = 0; - max = static_cast(sema->tryWaitMany(static_cast(max))); + assert(static_cast(max) >= 0); + max = static_cast(sema->tryWaitMany(static_cast(static_cast(max)))); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); } @@ -447,13 +453,14 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk(It itemFirst, size_t max) { size_t count = 0; - max = static_cast(sema->waitMany(static_cast(max))); + assert(static_cast(max) >= 0); + max = static_cast(sema->waitMany(static_cast(static_cast(max)))); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } return count; } - + // Attempts to dequeue several elements from the queue. // Returns the number of items actually dequeued, which can // be 0 if the timeout expires while waiting for elements, @@ -465,7 +472,8 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) { size_t count = 0; - max = static_cast(sema->waitMany(static_cast(max), timeout_usecs)); + assert(static_cast(max) >= 0); + max = static_cast(sema->waitMany(static_cast(static_cast(max)), timeout_usecs)); while (count != max) { count += inner.template try_dequeue_bulk(itemFirst, max - count); } @@ -492,7 +500,8 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) { size_t count = 0; - max = static_cast(sema->waitMany(static_cast(max))); + assert(static_cast(max) >= 0); + max = static_cast(sema->waitMany(static_cast(static_cast(max)))); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); } @@ -510,7 +519,8 @@ class BlockingConcurrentQueue inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) { size_t count = 0; - max = static_cast(sema->waitMany(static_cast(max), timeout_usecs)); + assert(static_cast(max) >= 0); + max = static_cast(sema->waitMany(static_cast(static_cast(max)), timeout_usecs)); while (count != max) { count += inner.template try_dequeue_bulk(token, itemFirst, max - count); }