From 008ff1c0715470d657a2ef52d9c1d4b353035dcf Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 23 Jan 2026 19:34:36 -0800 Subject: [PATCH 1/2] add operator new overloads to test Callables When Callables are sufficiently small, they're emplaced into a small buffer directly by placement new. If one, however, uses an unqualified call to placement new, the class-based overloads are picked up and compilation fails. libs/compat/test/move_only_function_test.cpp:107:11: note: candidate function not viable: requires 1 argument, but 2 were provided 107 | void* operator new(std::size_t) { throw 1234; } --- test/move_only_function_test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/move_only_function_test.cpp b/test/move_only_function_test.cpp index ad9566b..6e3e60e 100644 --- a/test/move_only_function_test.cpp +++ b/test/move_only_function_test.cpp @@ -102,6 +102,9 @@ struct callable { return *p_ + x; } + + // Should never be called, as this should always fit into the small buffer. + void* operator new(std::size_t) { throw 1234; } }; struct noex_callable @@ -122,6 +125,9 @@ struct noex_callable { return *p_ + x; } + + // Should never be called, as this should always fit into the small buffer. + void* operator new(std::size_t) { throw 1234; } }; struct large_callable From d6fa246a9c761f4e92942db62e15b56a4eb52009 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 23 Jan 2026 19:38:19 -0800 Subject: [PATCH 2/2] properly qualify calls to placement new To avoid class-based overload sets for operator new, we qualify our calls to placement new with `::new` which forces us to pick up the correct overload when emplacing objects in the small buffer. --- include/boost/compat/move_only_function.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/compat/move_only_function.hpp b/include/boost/compat/move_only_function.hpp index d307a00..4a049f5 100644 --- a/include/boost/compat/move_only_function.hpp +++ b/include/boost/compat/move_only_function.hpp @@ -397,7 +397,7 @@ struct move_only_function_base case op_type::move: { VT* p = static_cast( src->addr() ); - new(s.addr()) VT( std::move( *p ) ); + ::new( s.addr() ) VT( std::move( *p ) ); // destruct the element here because move construction will leave the container empty // outside of this function p->~VT(); @@ -446,7 +446,7 @@ struct move_only_function_base template void init_object( std::true_type /* use_sbo */, CArgs&& ...args ) { - new( s_.addr() ) VT( std::forward( args )... ); + ::new( s_.addr() ) VT( std::forward( args )... ); invoke_ = &mo_invoke_local_holder::invoke_local; manager_ = &manage_local; }