Having "static inline" functions in liburing header file results in compilation errors when using the new C++20 module export feature: In file included from src/work.cpp:3: ./include/liburing.h:343:20: error: \ ‘void io_uring_cq_advance(io_uring*, unsigned int)’ \ exposes TU-local entity ‘void io_uring_smp_store_release(T*, T) [with T = unsigned int]’ 343 | IOURINGINLINE void io_uring_cq_advance(struct io_uring *ring, unsigned nr) | ^~~~~~~~~~~~~~~~~~~ In file included from ./include/liburing.h:20: ./include/liburing/barrier.h:42:20: note: \ ‘void io_uring_smp_store_release(T*, T) [with T = unsigned int]’ is a \ specialization of TU-local template \ ‘template void io_uring_smp_store_release(T*, T)’ 42 | static inline void io_uring_smp_store_release(T *p, T v) | ^~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/liburing/barrier.h:42:20: note: \ ‘template void io_uring_smp_store_release(T*, T)’ declared with internal linkage Introduce a new macro _LOCAL_INLINE, which will expand to "inline" instead of "static inline" if compiled using C++20 or later. Also, make IOURINGINLINE behave the same way in the same condition. No functional change is expected for C and older C++ versions. Closes: https://github.com/axboe/liburing/issues/1457 Reported-by: @xiaosa-zhz # A GitHub user Fixes: 3d74c677c45e ("Make the liburing header files again compatible with C++") Fixes: f2b6fb85b79b ("liburing: Don't use `IOURINGINLINE` on private helpers") Cc: dr.xiaosa@gmail.com Cc: Alviro Iskandar Setiawan Suggested-by: Bart Van Assche Link: https://lore.kernel.org/io-uring/e0559c10-104d-4da8-9f7f-d2ffd73d8df3@acm.org Signed-off-by: Ammar Faizi --- This patch is a follow up to: "[PATCH liburing v1] barrier: Convert C++ barrier functions into macros". Link: https://lore.kernel.org/io-uring/20250913131547.466233-1-ammarfaizi2@gnuweeb.org src/include/liburing.h | 56 ++++++++++++++++++++++++++-------- src/include/liburing/barrier.h | 10 +++--- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/include/liburing.h b/src/include/liburing.h index e3f394eab860..f9dcd52c1537 100644 --- a/src/include/liburing.h +++ b/src/include/liburing.h @@ -17,8 +17,6 @@ #include "liburing/compat.h" #include "liburing/io_uring.h" #include "liburing/io_uring_version.h" -#include "liburing/barrier.h" - #ifndef uring_unlikely #define uring_unlikely(cond) __builtin_expect(!!(cond), 0) @@ -29,15 +27,45 @@ #endif /* - * NOTE: Only use IOURINGINLINE macro for 'static inline' functions - * that are expected to be available in the FFI bindings. + * NOTE: Use IOURINGINLINE macro for "static inline" functions that are + * expected to be available in the FFI bindings. They must also + * be included in the liburing-ffi.map file. + * + * Use _LOCAL_INLINE macro for "static inline" functions that are + * not expected to be available in the FFI bindings. + * + * Don't use "static inline" directly when defining new functions + * in this header file. + * + * Reason: + * The C++20 module export feature fails to operate correctly + * with the "static inline" functions. Use "inline" instead of + * "static inline" when compiling with C++20 or later. * - * Functions that are marked as IOURINGINLINE should be - * included in the liburing-ffi.map file. + * See: + * https://github.com/axboe/liburing/issues/1457 + * https://lore.kernel.org/io-uring/e0559c10-104d-4da8-9f7f-d2ffd73d8df3@acm.org */ #ifndef IOURINGINLINE +#if defined(__cplusplus) && __cplusplus >= 202002L +#define IOURINGINLINE inline +#else #define IOURINGINLINE static inline #endif +#endif + +#ifndef _LOCAL_INLINE +#if defined(__cplusplus) && __cplusplus >= 202002L +#define _LOCAL_INLINE inline +#else +#define _LOCAL_INLINE static inline +#endif +#endif + +/* + * barrier.h needs _LOCAL_INLINE. + */ +#include "liburing/barrier.h" #ifdef __alpha__ /* @@ -159,7 +187,7 @@ struct io_uring_zcrx_rq { * Library interface */ -static inline __u64 uring_ptr_to_u64(const void *ptr) LIBURING_NOEXCEPT +_LOCAL_INLINE __u64 uring_ptr_to_u64(const void *ptr) LIBURING_NOEXCEPT { return (__u64) (unsigned long) ptr; } @@ -402,7 +430,7 @@ struct io_uring_cqe_iter { unsigned tail; }; -static inline struct io_uring_cqe_iter +_LOCAL_INLINE struct io_uring_cqe_iter io_uring_cqe_iter_init(const struct io_uring *ring) LIBURING_NOEXCEPT { @@ -416,7 +444,7 @@ io_uring_cqe_iter_init(const struct io_uring *ring) }; } -static inline bool io_uring_cqe_iter_next(struct io_uring_cqe_iter *iter, +_LOCAL_INLINE bool io_uring_cqe_iter_next(struct io_uring_cqe_iter *iter, struct io_uring_cqe **cqe) LIBURING_NOEXCEPT { @@ -522,7 +550,7 @@ IOURINGINLINE void io_uring_sqe_set_buf_group(struct io_uring_sqe *sqe, sqe->buf_group = (__u16) bgid; } -static inline void __io_uring_set_target_fixed_file(struct io_uring_sqe *sqe, +_LOCAL_INLINE void __io_uring_set_target_fixed_file(struct io_uring_sqe *sqe, unsigned int file_index) LIBURING_NOEXCEPT { @@ -704,7 +732,7 @@ IOURINGINLINE void io_uring_prep_sendmsg(struct io_uring_sqe *sqe, int fd, sqe->msg_flags = flags; } -static inline unsigned __io_uring_prep_poll_mask(unsigned poll_mask) +_LOCAL_INLINE unsigned __io_uring_prep_poll_mask(unsigned poll_mask) LIBURING_NOEXCEPT { #if __BYTE_ORDER == __BIG_ENDIAN @@ -1742,7 +1770,7 @@ IOURINGINLINE int io_uring_wait_cqe_nr(struct io_uring *ring, * "official" versions of this, io_uring_peek_cqe(), io_uring_wait_cqe(), * or io_uring_wait_cqes*(). */ -static inline int __io_uring_peek_cqe(struct io_uring *ring, +_LOCAL_INLINE int __io_uring_peek_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, unsigned *nr_available) LIBURING_NOEXCEPT @@ -1987,4 +2015,8 @@ bool io_uring_check_version(int major, int minor) LIBURING_NOEXCEPT; #undef IOURINGINLINE #endif +#ifdef _LOCAL_INLINE +#undef _LOCAL_INLINE +#endif + #endif diff --git a/src/include/liburing/barrier.h b/src/include/liburing/barrier.h index 985569f496a8..0ae77b16ecf3 100644 --- a/src/include/liburing/barrier.h +++ b/src/include/liburing/barrier.h @@ -26,14 +26,14 @@ after the acquire operation executes. This is implemented using #define LIBURING_NOEXCEPT noexcept template -static inline void IO_URING_WRITE_ONCE(T &var, T val) +_LOCAL_INLINE void IO_URING_WRITE_ONCE(T &var, T val) LIBURING_NOEXCEPT { std::atomic_store_explicit(reinterpret_cast *>(&var), val, std::memory_order_relaxed); } template -static inline T IO_URING_READ_ONCE(const T &var) +_LOCAL_INLINE T IO_URING_READ_ONCE(const T &var) LIBURING_NOEXCEPT { return std::atomic_load_explicit( @@ -42,7 +42,7 @@ static inline T IO_URING_READ_ONCE(const T &var) } template -static inline void io_uring_smp_store_release(T *p, T v) +_LOCAL_INLINE void io_uring_smp_store_release(T *p, T v) LIBURING_NOEXCEPT { std::atomic_store_explicit(reinterpret_cast *>(p), v, @@ -50,7 +50,7 @@ static inline void io_uring_smp_store_release(T *p, T v) } template -static inline T io_uring_smp_load_acquire(const T *p) +_LOCAL_INLINE T io_uring_smp_load_acquire(const T *p) LIBURING_NOEXCEPT { return std::atomic_load_explicit( @@ -58,7 +58,7 @@ static inline T io_uring_smp_load_acquire(const T *p) std::memory_order_acquire); } -static inline void io_uring_smp_mb() +_LOCAL_INLINE void io_uring_smp_mb() LIBURING_NOEXCEPT { std::atomic_thread_fence(std::memory_order_seq_cst); base-commit: 97c596056b81488b86ff300cdbaf06471af3cc6e -- Ammar Faizi